diff --git a/src/arg_parser.hpp b/src/arg_parser.hpp
index b96c06b..0e4fbd4 100644
--- a/src/arg_parser.hpp
+++ b/src/arg_parser.hpp
@@ -20,6 +20,7 @@
 #define HEADER_ARG_PARSER_HPP
 
 #include <string>
+#include <iostream>
 #include <vector>
 
 class ArgParser
diff --git a/src/command_line_options.cpp b/src/command_line_options.cpp
index 2b83047..05fc9c4 100644
--- a/src/command_line_options.cpp
+++ b/src/command_line_options.cpp
@@ -16,6 +16,8 @@
 **  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+#include "command_line_options.hpp"
+
 #include <stdio.h>
 #include <iostream>
 #include <stdexcept>
@@ -26,7 +28,8 @@
 #include "arg_parser.hpp"
 #include "helper.hpp"
 #include "uinput_deviceid.hpp"
-#include "command_line_options.hpp"
+#include "options.hpp"
+#include "ini_schema.hpp"
 
 #define RAISE_EXCEPTION(x) do { \
   std::ostringstream kiJk8f08d4oMX; \
@@ -34,7 +37,7 @@
   throw std::runtime_error(kiJk8f08d4oMX.str()); \
 } while(0)
 
-CommandLineOptions* command_line_options = 0;
+Options* g__options = 0;
 
 enum {
   OPTION_HELP,
@@ -88,42 +91,9 @@ enum {
   OPTION_HELP_DEVICES
 };
 
-CommandLineOptions::CommandLineOptions() :
-  mode(RUN_DEFAULT),
-  verbose(false),
-  silent (false),
-  quiet  (false),
-  rumble (false),
-  led    (-1),
-  rumble_l(-1),
-  rumble_r(-1),
-  rumble_gain(255),
-  controller_id(0),
-  wireless_id(0),
-  instant_exit(false),
-  no_uinput(false),
-  detach_kernel_driver(),
-  gamepad_type(GAMEPAD_UNKNOWN),
-  vendor_id(-1),
-  product_id(-1),
-  uinput_config(),
-  deadzone(0),
-  deadzone_trigger(0),
-  button_map(),
-  axis_map(),
-  autofire_map(),
-  relative_axis_map(),
-  calibration_map(),
-  axis_sensitivity_map(),
-  square_axis(false),
-  four_way_restrictor(false),
-  dpad_rotation(0),
-  evdev_device(),
+CommandLineParser::CommandLineParser() :
   argp()
 {
-  busid[0] = '\0';
-  devid[0] = '\0';
-
   argp
     .add_usage("[OPTION]...")
     .add_text("Xbox360 USB Gamepad Userspace Driver")
@@ -264,23 +234,23 @@ void set_evdev_keymap(std::map<int, XboxButton>& keymap, const std::string& str)
 }
 
 void
-CommandLineOptions::parse_args(int argc, char** argv)
+CommandLineParser::parse_args(int argc, char** argv, Options* options)
 {  
   ArgParser::ParsedOptions parsed = argp.parse_args(argc, argv);
 
   for(ArgParser::ParsedOptions::const_iterator i = parsed.begin(); i != parsed.end(); ++i)
   {
-    CommandLineOptions& opts = *this;
+    Options& opts = *options;
     const ArgParser::ParsedOption& opt = *i;
 
     switch (i->key)
     {
       case OPTION_HELP:
-        opts.mode = PRINT_HELP;
+        opts.mode = Options::PRINT_HELP;
         break;
 
       case OPTION_VERSION:
-        opts.mode = PRINT_VERSION;
+        opts.mode = Options::PRINT_VERSION;
         break;
           
       case OPTION_VERBOSE:
@@ -297,7 +267,7 @@ CommandLineOptions::parse_args(int argc, char** argv)
 
       case OPTION_DAEMON:
         opts.silent = true;
-        opts.mode = RUN_DAEMON;
+        opts.mode = Options::RUN_DAEMON;
         break;
 
       case OPTION_TEST_RUMBLE:
@@ -457,7 +427,7 @@ CommandLineOptions::parse_args(int argc, char** argv)
       case OPTION_LED:
         if (opt.argument == "help")
         {
-          opts.mode = PRINT_LED_HELP;
+          opts.mode = Options::PRINT_LED_HELP;
         }
         else
         {
@@ -519,14 +489,14 @@ CommandLineOptions::parse_args(int argc, char** argv)
         break;
 
       case OPTION_DPAD_ROTATION:
-      {
-        int degree = boost::lexical_cast<int>(opt.argument);
-        degree /= 45;
-        degree %= 8;
-        if (degree < 0) degree += 8;
-        opts.dpad_rotation = degree;
-      }
-      break;
+        {
+          int degree = boost::lexical_cast<int>(opt.argument);
+          degree /= 45;
+          degree %= 8;
+          if (degree < 0) degree += 8;
+          opts.dpad_rotation = degree;
+        }
+        break;
 
       case OPTION_SQUARE_AXIS:
         opts.square_axis = true;
@@ -544,46 +514,56 @@ CommandLineOptions::parse_args(int argc, char** argv)
         break;
 
       case OPTION_HELP_LED:
-        opts.mode = PRINT_LED_HELP;
+        opts.mode = Options::PRINT_LED_HELP;
         break;
 
       case OPTION_DEVICE_BY_ID:
-      {
-        unsigned int tmp_product_id;
-        unsigned int tmp_vendor_id;
-        if (sscanf(opt.argument.c_str(), "%x:%x", &tmp_vendor_id, &tmp_product_id) == 2)
         {
-          opts.vendor_id  = tmp_vendor_id;
-          opts.product_id = tmp_product_id;
+          unsigned int tmp_product_id;
+          unsigned int tmp_vendor_id;
+          if (sscanf(opt.argument.c_str(), "%x:%x", &tmp_vendor_id, &tmp_product_id) == 2)
+          {
+            opts.vendor_id  = tmp_vendor_id;
+            opts.product_id = tmp_product_id;
+          }
+          else
+          {
+            RAISE_EXCEPTION(opt.option << " expected an argument in form PRODUCT:VENDOR (i.e. 046d:c626)");
+          }
+          break;
         }
-        else
-        {
-          RAISE_EXCEPTION(opt.option << " expected an argument in form PRODUCT:VENDOR (i.e. 046d:c626)");
-        }
-        break;
-      }
 
       case OPTION_DEVICE_BY_PATH:
-        if (sscanf(opt.argument.c_str(), "%3s:%3s", opts.busid, opts.devid) != 2)
-        {  
-          RAISE_EXCEPTION(opt.option << " expected an argument in form BUS:DEV (i.e. 006:003)");
+        {
+          char busid[4] = { '\0' };
+          char devid[4] = { '\0' };
+
+          if (sscanf(opt.argument.c_str(), "%3s:%3s", busid, devid) != 2)
+          {  
+            RAISE_EXCEPTION(opt.option << " expected an argument in form BUS:DEV (i.e. 006:003)");
+          }
+          else
+          {
+            opts.busid = busid;
+            opts.devid = devid;
+          }
         }
         break;
 
       case OPTION_LIST_SUPPORTED_DEVICES:
-        opts.mode = RUN_LIST_SUPPORTED_DEVICES;
+        opts.mode = Options::RUN_LIST_SUPPORTED_DEVICES;
         break;
 
       case OPTION_LIST_SUPPORTED_DEVICES_XPAD:
-        opts.mode = RUN_LIST_SUPPORTED_DEVICES_XPAD;
+        opts.mode = Options::RUN_LIST_SUPPORTED_DEVICES_XPAD;
         break;
 
       case OPTION_LIST_CONTROLLER:
-        opts.mode = RUN_LIST_CONTROLLER;
+        opts.mode = Options::RUN_LIST_CONTROLLER;
         break;
 
       case OPTION_HELP_DEVICES:
-        opts.mode = PRINT_HELP_DEVICES;
+        opts.mode = Options::PRINT_HELP_DEVICES;
         break;
 
       case ArgParser::REST_ARG:
@@ -598,13 +578,13 @@ CommandLineOptions::parse_args(int argc, char** argv)
 }
 
 void
-CommandLineOptions::print_help() const
+CommandLineParser::print_help() const
 {
   argp.print_help(std::cout);
 }
 
 void
-CommandLineOptions::print_led_help() const
+CommandLineParser::print_led_help() const
 {
   std::cout << 
     "Possible values for '--led VALUE' are:\n\n"
@@ -628,7 +608,7 @@ CommandLineOptions::print_led_help() const
 }
   
 void
-CommandLineOptions::print_version() const
+CommandLineParser::print_version() const
 {
   std::cout
     << "xboxdrv " PACKAGE_VERSION " - http://pingus.seul.org/~grumbel/xboxdrv/\n"
@@ -638,4 +618,55 @@ CommandLineOptions::print_version() const
     << "This is free software, and you are welcome to redistribute it under certain conditions; see the file COPYING for details.\n";
 }
 
+void
+CommandLineParser::create_ini_schema()
+{
+  // INISchema ini;
+
+  // ini.section("general")
+  //   ("verbose", &verbose)
+  //   ("silent",  &silent)
+  //   ("quiet",   &quiet)
+  //   ("rumble",  &rumble)
+  //   ("led",  &led)
+  //   ("rumble_l",  &rumble_l)
+  //   ("rumble_r",  &rumble_r)
+  //   ("rumble_gain",  &rumble_gain)
+  //   ("controller-id",  &controller_id)
+  //   ("wireless-id",  &wireless_id)
+  //   ("instant-exit",  &instant_exit)
+  //   ("no-uinput",  &no_uinput)
+  //   ("detach-kernel-driver",  &detach_kernel_driver);
+
+  // char busid[4];
+  // char devid[4];
+  // int deadzone;
+  // int deadzone_trigger;
+
+  // int vendor_id;
+  // int product_id;
+
+  // bool square_axis;
+  // bool four_way_restrictor;
+  // int  dpad_rotation;
+  // std::string evdev_device;
+
+  // uInputCfg uinput_config;
+  //ini.section("ui-buttonmap",  ui_buttonmap_cb);
+  //ini.section("ui-axismap", ui_buttonmap_cb);
+
+  // std::vector<ButtonMapping> button_map;
+  //ini.section("buttonmap", buttonmap_cb);
+
+  // std::vector<AxisMapping>   axis_map;
+  //ini.section("axismap", axismap_cb);
+
+  // std::vector<AutoFireMapping> autofire_map;
+  // std::vector<RelativeAxisMapping> relative_axis_map;
+  // std::vector<CalibrationMapping> calibration_map;
+  // std::vector<AxisSensitivityMapping> axis_sensitivity_map;
+  // std::map<int, XboxAxis>   evdev_absmap;
+  // std::map<int, XboxButton> evdev_keymap;
+}
+
 /* EOF */
diff --git a/src/command_line_options.hpp b/src/command_line_options.hpp
index b64a81a..945ab32 100644
--- a/src/command_line_options.hpp
+++ b/src/command_line_options.hpp
@@ -29,70 +29,23 @@
 
 class Xboxdrv;
 
-class CommandLineOptions 
+class CommandLineParser 
 {
 public:
-  enum { RUN_DEFAULT,
-         RUN_DAEMON, 
-         RUN_LIST_CONTROLLER,
-         RUN_LIST_SUPPORTED_DEVICES,
-         RUN_LIST_SUPPORTED_DEVICES_XPAD,
-         PRINT_VERSION,
-         PRINT_HELP,
-         PRINT_HELP_DEVICES,
-         PRINT_LED_HELP
-  } mode;
-
-  bool verbose;
-  bool silent;
-  bool quiet;
-  bool rumble;
-  int  led;
-  int  rumble_l;
-  int  rumble_r;
-  int  rumble_gain;
-  int  controller_id;
-  int  wireless_id;
-  bool instant_exit;
-  bool no_uinput;
-  bool detach_kernel_driver;
-
-  GamepadType gamepad_type;
-  
-  char busid[4];
-  char devid[4];
-
-  int vendor_id;
-  int product_id;
-
-  uInputCfg uinput_config;
-  int deadzone;
-  int deadzone_trigger;
-  std::vector<ButtonMapping> button_map;
-  std::vector<AxisMapping>   axis_map;
-  std::vector<AutoFireMapping> autofire_map;
-  std::vector<RelativeAxisMapping> relative_axis_map;
-  std::vector<CalibrationMapping> calibration_map;
-  std::vector<AxisSensitivityMapping> axis_sensitivity_map;
-  bool square_axis;
-  bool four_way_restrictor;
-  int  dpad_rotation;
-  std::string evdev_device;
-  std::map<int, XboxAxis>   evdev_absmap;
-  std::map<int, XboxButton> evdev_keymap;
-
   ArgParser argp;
 
 public:
-  CommandLineOptions();
-  void parse_args(int argc, char** argv);
+  CommandLineParser();
+
+  void parse_args(int argc, char** argv, Options* options);
 
   void print_help() const;
   void print_led_help() const;
   void print_version() const;
+  void create_ini_schema();
 };
 
-extern CommandLineOptions* command_line_options;
+extern Options* g_options;
 
 #endif
 
diff --git a/src/force_feedback_handler.cpp b/src/force_feedback_handler.cpp
index 4024654..78b651f 100644
--- a/src/force_feedback_handler.cpp
+++ b/src/force_feedback_handler.cpp
@@ -19,7 +19,7 @@
 #include <stdlib.h>
 #include <iostream>
 #include <assert.h>
-#include "command_line_options.hpp"
+#include "options.hpp"
 #include "force_feedback_handler.hpp"
 
 std::ostream& operator<<(std::ostream& out, const struct ff_envelope& envelope)
@@ -294,7 +294,7 @@ ForceFeedbackHandler::get_max_effects()
 void
 ForceFeedbackHandler::upload(const struct ff_effect& effect)
 {
-  if (command_line_options->verbose)
+  if (g_options->verbose)
     std::cout << "FF_UPLOAD("
               << "effect_id:" << effect.id
               << ", effect_type:" << effect.type
@@ -325,7 +325,7 @@ ForceFeedbackHandler::upload(const struct ff_effect& effect)
 void
 ForceFeedbackHandler::erase(int id)
 {
-  if (command_line_options->verbose)
+  if (g_options->verbose)
     std::cout << "FF_ERASE(effect_id:" << id << ")" << std::endl;
 
   std::map<int, ForceFeedbackEffect>::iterator i = effects.find(id);
@@ -338,7 +338,7 @@ ForceFeedbackHandler::erase(int id)
 void
 ForceFeedbackHandler::play(int id)
 {
-  if (command_line_options->verbose)
+  if (g_options->verbose)
     std::cout << "FFPlay(effect_id:" << id << ")" << std::endl;
 
   std::map<int, ForceFeedbackEffect>::iterator i = effects.find(id);
@@ -351,7 +351,7 @@ ForceFeedbackHandler::play(int id)
 void
 ForceFeedbackHandler::stop(int id)
 {
-  if (command_line_options->verbose)
+  if (g_options->verbose)
     std::cout << "FFStop(effect_id:" << id << ")" << std::endl;
 
   std::map<int, ForceFeedbackEffect>::iterator i = effects.find(id);
diff --git a/src/ini_builder.hpp b/src/ini_builder.hpp
new file mode 100644
index 0000000..48e8407
--- /dev/null
+++ b/src/ini_builder.hpp
@@ -0,0 +1,32 @@
+/*
+**  Xbox360 USB Gamepad Userspace Driver
+**  Copyright (C) 2010 Ingo Ruhnke <grumbel@gmx.de>
+**
+**  This program is free software: you can redistribute it and/or modify
+**  it under the terms of the GNU General Public License as published by
+**  the Free Software Foundation, either version 3 of the License, or
+**  (at your option) any later version.
+**
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+**
+**  You should have received a copy of the GNU General Public License
+**  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef HEADER_XBOXDRV_INI_BUILDER_HPP
+#define HEADER_XBOXDRV_INI_BUILDER_HPP
+
+class INIBuilder
+{
+public:
+  virtual ~INIBuilder() {}
+  virtual void send_section(const std::string& section) =0;
+  virtual void send_pair(const std::string& name, const std::string& value) =0;
+};
+
+#endif
+
+/* EOF */
diff --git a/src/ini_parser.cpp b/src/ini_parser.cpp
new file mode 100644
index 0000000..bcf0a2e
--- /dev/null
+++ b/src/ini_parser.cpp
@@ -0,0 +1,268 @@
+/*
+**  Xbox360 USB Gamepad Userspace Driver
+**  Copyright (C) 2010 Ingo Ruhnke <grumbel@gmx.de>
+**
+**  This program is free software: you can redistribute it and/or modify
+**  it under the terms of the GNU General Public License as published by
+**  the Free Software Foundation, either version 3 of the License, or
+**  (at your option) any later version.
+**
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+**
+**  You should have received a copy of the GNU General Public License
+**  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "ini_parser.hpp"
+
+#include <stdlib.h>
+#include <iostream>
+#include <ctype.h>
+#include <stdexcept>
+
+#include "ini_builder.hpp"
+
+INIParser::INIParser(std::istream& in, INIBuilder& builder, const std::string& context) :
+  m_in(in),
+  m_builder(builder),
+  m_context(context),
+  m_line(1),
+  m_column(0),
+  m_current_char(-1)  
+{}
+
+void
+INIParser::run()
+{
+  // read the first char
+  next();
+
+  while(peek() != -1) 
+  {
+    if (accept('['))
+    {
+      m_builder.send_section(get_section());
+      expect(']');
+      whitespace();
+      if (accept('#'))
+        eat_rest_of_line();
+      newline();
+    }
+    else if (accept(' ') || accept('\t') || accept('\n'))
+    {
+      // eat whitespace
+    }
+    else if (accept('#'))
+    {
+      eat_rest_of_line();
+      newline();
+    }
+    else // assume name=value pair
+    {
+      std::string n;
+      std::string v;
+
+      n = get_ident();
+      whitespace();
+      expect('=');
+      whitespace();
+      if (accept('#'))
+      { // "foobar = # comment here, value empty"
+        eat_rest_of_line();
+        newline();
+      }
+      else
+      {
+        if (accept('"'))
+        {
+          v = get_string();
+          expect('"');
+        }
+        else
+        {
+          v = get_value();
+        }
+
+        whitespace();
+        if (accept('#'))
+          eat_rest_of_line();
+        newline();
+      }
+      m_builder.send_pair(n, v);
+    }
+  }
+}
+
+void
+INIParser::error(const std::string& message)
+{
+  std::ostringstream str;
+  str << m_context << ":" << m_line << ":" << m_column << ": error: " << message;
+  throw std::runtime_error(str.str());
+}
+
+int
+INIParser::peek()
+{
+  return m_current_char;
+}
+
+void
+INIParser::next()
+{
+  if (m_in.eof())
+  {
+    error("unexpected end of file");
+  }
+  else
+  {
+    m_current_char = m_in.get();
+    if (m_current_char == '\n')
+    {
+      m_line  += 1;
+      m_column = 0;
+    }
+  }
+}
+
+bool
+INIParser::accept(char c)
+{
+  if (peek() != c)
+  {
+    return false;
+  }
+  else
+  {
+    next();
+    return true;
+  }
+}
+
+void
+INIParser::expect(char c)
+{
+  if (peek() != c)
+  {
+    std::ostringstream str;
+    str << "expected '" << c << "', got ";
+    if (peek() == -1)
+      str << "EOF";
+    else
+      str << "'" << static_cast<char>(peek()) << "'";
+    error(str.str());
+  }
+  else
+  {
+    next();
+  }
+}
+
+std::string
+INIParser::get_value()
+{
+  std::ostringstream str;
+  while(peek() != ' ' && peek() != '\t' && peek() != '\n')
+  {
+    str << (char)peek();
+    next();
+  }
+  return str.str();
+}
+
+std::string
+INIParser::get_ident()
+{
+  std::ostringstream str;
+  while(peek() != '=' && peek() != ' ' && peek() != '\t')
+  {
+    str << (char)peek();
+    next();
+  }
+  return str.str();
+}
+
+std::string
+INIParser::get_string()
+{
+  std::ostringstream str;
+  while(peek() != '"')
+  {
+    if (peek() == '\\')
+    {
+      next();
+      switch(peek())
+      {
+        case '\\': str << '\\'; break;
+        case '0': str << '\0'; break;
+        case 'a': str << '\a'; break;
+        case 'b': str << '\b'; break;
+        case 't': str << '\t'; break;
+        case 'r': str << '\r'; break;
+        case 'n': str << '\n'; break;
+        default: str << '\\' << (char)peek(); break;
+      }
+    }
+    else
+    {
+      str << (char)peek();
+    }
+    next();
+  }
+  return str.str();
+}
+
+void
+INIParser::newline()
+{
+  if (peek() != '\n')
+  {
+    error("expected newline");
+  }
+  else
+  {
+    next();
+  }
+}
+
+void
+INIParser::eat_rest_of_line()
+{
+  while(peek() != '\n')
+  {
+    next();
+  }
+}
+
+std::string
+INIParser::get_section()
+{
+  std::ostringstream str;
+  while(peek() != ']')
+  {
+    str << (char)peek(); 
+    next();
+  }
+  return str.str();
+}
+
+
+void
+INIParser::whitespace()
+{
+  while(peek() == ' ' || peek() == '\t')
+  {
+    next();
+  }
+}
+
+int
+INIParser::getchar()
+{
+  return m_in.get();
+}
+
+/* EOF */
diff --git a/src/ini_parser.hpp b/src/ini_parser.hpp
new file mode 100644
index 0000000..d58b7c5
--- /dev/null
+++ b/src/ini_parser.hpp
@@ -0,0 +1,65 @@
+/*
+**  Xbox360 USB Gamepad Userspace Driver
+**  Copyright (C) 2010 Ingo Ruhnke <grumbel@gmx.de>
+**
+**  This program is free software: you can redistribute it and/or modify
+**  it under the terms of the GNU General Public License as published by
+**  the Free Software Foundation, either version 3 of the License, or
+**  (at your option) any later version.
+**
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+**
+**  You should have received a copy of the GNU General Public License
+**  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef HEADER_XBOXDRV_INI_PARSER_HPP
+#define HEADER_XBOXDRV_INI_PARSER_HPP
+
+#include <map>
+#include <string>
+#include <sstream>
+
+class INIBuilder;
+
+class INIParser
+{
+private:
+  std::istream& m_in;
+  INIBuilder& m_builder;
+  std::string m_context;
+  int m_line;
+  int m_column;
+  int m_current_char;
+
+public:
+  INIParser(std::istream& in, INIBuilder& builder, const std::string& context);
+  
+  void run();
+
+private:
+  void error(const std::string& message);
+  int  peek();
+  void next();
+  bool accept(char c);
+  void expect(char c);
+  std::string get_string();
+  std::string get_value();
+  std::string get_ident(); 
+  void newline();
+  void eat_rest_of_line();
+  std::string get_section();
+  void whitespace();
+  int  getchar();  
+
+private:
+  INIParser(const INIParser&);
+  INIParser& operator=(const INIParser&);
+};
+
+#endif
+
+/* EOF */
diff --git a/src/ini_schema.cpp b/src/ini_schema.cpp
new file mode 100644
index 0000000..95325fe
--- /dev/null
+++ b/src/ini_schema.cpp
@@ -0,0 +1,208 @@
+/*
+**  Xbox360 USB Gamepad Userspace Driver
+**  Copyright (C) 2010 Ingo Ruhnke <grumbel@gmx.de>
+**
+**  This program is free software: you can redistribute it and/or modify
+**  it under the terms of the GNU General Public License as published by
+**  the Free Software Foundation, either version 3 of the License, or
+**  (at your option) any later version.
+**
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+**
+**  You should have received a copy of the GNU General Public License
+**  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "ini_schema.hpp"
+
+class INIPairSchema
+{
+public:
+  virtual ~INIPairSchema() {}
+};
+
+class INIPairSchemaBool : public INIPairSchema
+{
+private:
+  bool* m_data;
+  
+public:
+  INIPairSchemaBool(bool* data) : m_data(data) {}
+  void call(const std::string& value)
+  {
+    if (value == "yes" || value == "true" || value == "1")
+    {
+      *m_data = true;
+    }
+    else if (value == "no" || value == "false" || value == "0")
+    {
+      *m_data = false;
+    }
+    else
+    {
+      throw std::runtime_error("unable to convert '" + value + "' to bool");
+    }
+  }
+};
+
+class INIPairSchemaInt : public INIPairSchema
+{
+private:
+  int* m_data;
+  
+public:
+  INIPairSchemaInt(int* data) : m_data(data) {}
+  void call(const std::string& value)
+  {
+    *m_data = atoi(value.c_str());
+  }
+};
+
+class INIPairSchemaFloat : public INIPairSchema
+{
+private:
+  float* m_data;
+  
+public:
+  INIPairSchemaFloat(float* data) : m_data(data) {}
+  void call(const std::string& value)
+  {
+    *m_data = atoi(value.c_str());
+  }
+};
+
+class INIPairSchemaString : public INIPairSchema
+{
+private:
+  std::string* m_data;
+  
+public:
+  INIPairSchemaString(std::string* data) : m_data(data) {}
+  void call(const std::string& value)
+  {
+    *m_data = value;
+  }
+};
+
+class INIPairSchemaCallback : public INIPairSchema
+{
+private:
+  boost::function<void (const std::string&)> m_callback;
+  
+public:
+  INIPairSchemaCallback(boost::function<void (const std::string&)> callback) : m_callback(callback) {}
+  void call(const std::string& value)
+  {
+    if (m_callback)
+      m_callback(value);
+  }
+};
+
+INISchemaSection::INISchemaSection()
+{
+}
+
+INISchemaSection::~INISchemaSection()
+{
+  for(Schema::iterator i = m_schema.begin(); i != m_schema.end(); ++i)
+  {
+    delete i->second;
+  }
+}
+
+INISchemaSection& 
+INISchemaSection::add(const std::string& name, INIPairSchema* schema)
+{
+  Schema::iterator i = m_schema.find(name);
+
+  if (i != m_schema.end())
+  {
+    delete i->second;
+  }
+  
+  m_schema.insert(std::pair<std::string, INIPairSchema*>(name, schema));
+    
+  return *this;
+}
+
+INISchemaSection&
+INISchemaSection::operator()(const std::string& name, bool*  value)
+{
+  add(name, new INIPairSchemaBool(value));
+  return *this;
+}
+
+INISchemaSection& 
+INISchemaSection::operator()(const std::string& name, int*   value)
+{
+  add(name, new INIPairSchemaInt(value));
+  return *this;
+}
+
+INISchemaSection& 
+INISchemaSection::operator()(const std::string& name, float* value)
+{
+  add(name, new INIPairSchemaFloat(value));
+  return *this;
+}
+
+INISchemaSection& 
+INISchemaSection::operator()(const std::string& name, std::string* value)
+{
+  add(name, new INIPairSchemaString(value));
+  return *this;
+}
+
+INISchemaSection& 
+INISchemaSection::operator()(const std::string& name, boost::function<void (const std::string&)> callback)
+{
+  add(name, new INIPairSchemaCallback(callback));
+  return *this;
+}
+
+INISchema::INISchema() :
+  m_sections()
+{
+}
+
+INISchema::~INISchema()
+{
+  for(Sections::iterator i = m_sections.begin(); i != m_sections.end(); ++i)
+  {
+    delete i->second;
+  }
+}
+
+INISchemaSection&
+INISchema::section(const std::string& name, 
+                   boost::function<void (const std::string&, const std::string&)> callback)
+{
+  Sections::iterator i = m_sections.find(name);
+  if (i != m_sections.end())
+  {
+    delete i->second;
+  }
+
+  INISchemaSection* section = new INISchemaSection();
+  m_sections.insert(std::pair<std::string, INISchemaSection*>(name, section));
+  return *section;
+}
+
+INISchemaSection*
+INISchema::get_section(const std::string& name)
+{
+  Sections::iterator i = m_sections.find(name);
+  if (i != m_sections.end())
+  {
+    return i->second;
+  }
+  else
+  {
+    return 0;
+  }
+}
+
+/* EOF */
diff --git a/src/ini_schema.hpp b/src/ini_schema.hpp
new file mode 100644
index 0000000..3ebe8e9
--- /dev/null
+++ b/src/ini_schema.hpp
@@ -0,0 +1,75 @@
+/*
+**  Xbox360 USB Gamepad Userspace Driver
+**  Copyright (C) 2010 Ingo Ruhnke <grumbel@gmx.de>
+**
+**  This program is free software: you can redistribute it and/or modify
+**  it under the terms of the GNU General Public License as published by
+**  the Free Software Foundation, either version 3 of the License, or
+**  (at your option) any later version.
+**
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+**
+**  You should have received a copy of the GNU General Public License
+**  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef HEADER_XBOXDRV_INI_SCHEMA_HPP
+#define HEADER_XBOXDRV_INI_SCHEMA_HPP
+
+#include <map>
+#include <string>
+#include <boost/function.hpp>
+
+class INIPairSchema;
+
+class INISchemaSection
+{
+private:
+  typedef std::map<std::string, INIPairSchema*> Schema; 
+  Schema m_schema;
+
+public:
+  INISchemaSection();
+  ~INISchemaSection();
+
+  INISchemaSection& operator()(const std::string& name, bool*  value);
+  INISchemaSection& operator()(const std::string& name, int*   value);
+  INISchemaSection& operator()(const std::string& name, float* value);
+  INISchemaSection& operator()(const std::string& name, std::string* value);
+  INISchemaSection& operator()(const std::string& name, boost::function<void (const std::string&)> callback);
+
+private:
+  INISchemaSection& add(const std::string& name, INIPairSchema* schema);
+
+private:
+  INISchemaSection(const INISchemaSection&);
+  INISchemaSection& operator=(const INISchemaSection&);
+};
+
+class INISchema
+{
+private:
+  typedef std::map<std::string, INISchemaSection*> Sections;
+  Sections m_sections;
+
+public:
+  INISchema();
+  ~INISchema();
+
+  INISchemaSection& section(const std::string& name, 
+                            boost::function<void (const std::string&, const std::string&)> callback 
+                            = boost::function<void (const std::string&, const std::string&)>());
+
+  INISchemaSection* get_section(const std::string& name);
+
+private:
+  INISchema(const INISchema&);
+  INISchema& operator=(const INISchema&);
+};
+
+#endif
+
+/* EOF */
diff --git a/src/modifier.cpp b/src/modifier.cpp
index e6b8e47..013235c 100644
--- a/src/modifier.cpp
+++ b/src/modifier.cpp
@@ -22,7 +22,7 @@
 #include <stdexcept>
 #include <math.h>
 
-#include "command_line_options.hpp"
+#include "options.hpp"
 #include "helper.hpp"
 #include "modifier.hpp"
 
@@ -310,7 +310,7 @@ void apply_square_axis(XboxGenericMsg& msg)
   }
 }
 
-void apply_deadzone(XboxGenericMsg& msg, const CommandLineOptions& opts)
+void apply_deadzone(XboxGenericMsg& msg, const Options& opts)
 {
   switch (msg.type)
   {
@@ -350,7 +350,7 @@ void apply_deadzone(XboxGenericMsg& msg, const CommandLineOptions& opts)
   }
 }
 
-void apply_axis_sensitivity(XboxGenericMsg& msg, const CommandLineOptions& opts)
+void apply_axis_sensitivity(XboxGenericMsg& msg, const Options& opts)
 {
   for(std::vector<AxisSensitivityMapping>::const_iterator i = opts.axis_sensitivity_map.begin();
       i != opts.axis_sensitivity_map.end(); ++i)
@@ -371,7 +371,7 @@ void apply_axis_sensitivity(XboxGenericMsg& msg, const CommandLineOptions& opts)
   }
 }
 
-void apply_four_way_restrictor(XboxGenericMsg& msg, const CommandLineOptions& opts)
+void apply_four_way_restrictor(XboxGenericMsg& msg, const Options& opts)
 {
   // left Stick
   if (abs(get_axis(msg, XBOX_AXIS_X1)) > abs(get_axis(msg, XBOX_AXIS_Y1)))
@@ -402,7 +402,7 @@ void apply_four_way_restrictor(XboxGenericMsg& msg, const CommandLineOptions& op
   }
 }
 
-void apply_dpad_rotator(XboxGenericMsg& msg, const CommandLineOptions& opts)
+void apply_dpad_rotator(XboxGenericMsg& msg, const Options& opts)
 {
   int up    = get_button(msg, XBOX_DPAD_UP);
   int down  = get_button(msg, XBOX_DPAD_DOWN);
diff --git a/src/modifier.hpp b/src/modifier.hpp
index b22ea8f..282185e 100644
--- a/src/modifier.hpp
+++ b/src/modifier.hpp
@@ -24,7 +24,7 @@
 #include <vector>
 #include "xboxmsg.hpp"
 
-class CommandLineOptions;
+class Options;
 
 struct ButtonMapping {
   static ButtonMapping from_string(const std::string& str);
@@ -161,11 +161,11 @@ public:
 void apply_button_map(XboxGenericMsg& msg, const std::vector<ButtonMapping>& lst);
 void apply_axis_map(XboxGenericMsg& msg, const std::vector<AxisMapping>& lst);
 void apply_calibration_map(XboxGenericMsg& msg, const std::vector<CalibrationMapping>& lst);
-void apply_deadzone(XboxGenericMsg& msg, const CommandLineOptions& opts);
+void apply_deadzone(XboxGenericMsg& msg, const Options& opts);
 void apply_square_axis(XboxGenericMsg& msg);
-void apply_axis_sensitivity(XboxGenericMsg& msg, const CommandLineOptions& opts);
-void apply_four_way_restrictor(XboxGenericMsg& msg, const CommandLineOptions& opts);
-void apply_dpad_rotator(XboxGenericMsg& msg, const CommandLineOptions& opts);
+void apply_axis_sensitivity(XboxGenericMsg& msg, const Options& opts);
+void apply_four_way_restrictor(XboxGenericMsg& msg, const Options& opts);
+void apply_dpad_rotator(XboxGenericMsg& msg, const Options& opts);
 
 #endif
 
diff --git a/src/options.cpp b/src/options.cpp
new file mode 100644
index 0000000..72895ee
--- /dev/null
+++ b/src/options.cpp
@@ -0,0 +1,57 @@
+/*
+**  Xbox360 USB Gamepad Userspace Driver
+**  Copyright (C) 2010 Ingo Ruhnke <grumbel@gmx.de>
+**
+**  This program is free software: you can redistribute it and/or modify
+**  it under the terms of the GNU General Public License as published by
+**  the Free Software Foundation, either version 3 of the License, or
+**  (at your option) any later version.
+**
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+**
+**  You should have received a copy of the GNU General Public License
+**  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "options.hpp"
+
+Options* g_options;
+
+Options::Options() :
+  mode(RUN_DEFAULT),
+  verbose(false),
+  silent (false),
+  quiet  (false),
+  rumble (false),
+  led    (-1),
+  rumble_l(-1),
+  rumble_r(-1),
+  rumble_gain(255),
+  controller_id(0),
+  wireless_id(0),
+  instant_exit(false),
+  no_uinput(false),
+  detach_kernel_driver(),
+  gamepad_type(GAMEPAD_UNKNOWN),
+  vendor_id(-1),
+  product_id(-1),
+  uinput_config(),
+  deadzone(0),
+  deadzone_trigger(0),
+  button_map(),
+  axis_map(),
+  autofire_map(),
+  relative_axis_map(),
+  calibration_map(),
+  axis_sensitivity_map(),
+  square_axis(false),
+  four_way_restrictor(false),
+  dpad_rotation(0),
+  evdev_device()
+{
+}
+
+/* EOF */
diff --git a/src/options.hpp b/src/options.hpp
new file mode 100644
index 0000000..53847d1
--- /dev/null
+++ b/src/options.hpp
@@ -0,0 +1,89 @@
+/*
+**  Xbox360 USB Gamepad Userspace Driver
+**  Copyright (C) 2010 Ingo Ruhnke <grumbel@gmx.de>
+**
+**  This program is free software: you can redistribute it and/or modify
+**  it under the terms of the GNU General Public License as published by
+**  the Free Software Foundation, either version 3 of the License, or
+**  (at your option) any later version.
+**
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+**
+**  You should have received a copy of the GNU General Public License
+**  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef HEADER_XBOXDRV_OPTIONS_HPP
+#define HEADER_XBOXDRV_OPTIONS_HPP
+
+#include <string>
+#include <map>
+#include <vector>
+
+#include "xpad_device.hpp"
+#include "uinput_cfg.hpp"
+#include "modifier.hpp"
+
+class Options
+{
+public:
+  enum { RUN_DEFAULT,
+         RUN_DAEMON, 
+         RUN_LIST_CONTROLLER,
+         RUN_LIST_SUPPORTED_DEVICES,
+         RUN_LIST_SUPPORTED_DEVICES_XPAD,
+         PRINT_VERSION,
+         PRINT_HELP,
+         PRINT_HELP_DEVICES,
+         PRINT_LED_HELP
+  } mode;
+
+  bool verbose;
+  bool silent;
+  bool quiet;
+  bool rumble;
+  int  led;
+  int  rumble_l;
+  int  rumble_r;
+  int  rumble_gain;
+  int  controller_id;
+  int  wireless_id;
+  bool instant_exit;
+  bool no_uinput;
+  bool detach_kernel_driver;
+
+  GamepadType gamepad_type;
+  
+  std::string busid;
+  std::string devid;
+
+  int vendor_id;
+  int product_id;
+
+  uInputCfg uinput_config;
+  int deadzone;
+  int deadzone_trigger;
+  std::vector<ButtonMapping> button_map;
+  std::vector<AxisMapping>   axis_map;
+  std::vector<AutoFireMapping> autofire_map;
+  std::vector<RelativeAxisMapping> relative_axis_map;
+  std::vector<CalibrationMapping> calibration_map;
+  std::vector<AxisSensitivityMapping> axis_sensitivity_map;
+  bool square_axis;
+  bool four_way_restrictor;
+  int  dpad_rotation;
+  std::string evdev_device;
+  std::map<int, XboxAxis>   evdev_absmap;
+  std::map<int, XboxButton> evdev_keymap;
+
+  Options();
+};
+
+extern Options* g_options;
+
+#endif
+
+/* EOF */
diff --git a/src/xbox360_controller.cpp b/src/xbox360_controller.cpp
index 1aef03c..f9d8a13 100644
--- a/src/xbox360_controller.cpp
+++ b/src/xbox360_controller.cpp
@@ -24,7 +24,7 @@
 #include <iostream>
 #include <boost/format.hpp>
 
-#include "command_line_options.hpp"
+#include "options.hpp"
 #include "helper.hpp"
 #include "usb_helper.hpp"
 #include "usb_read_thread.hpp"
@@ -228,7 +228,7 @@ Xbox360Controller::read(XboxGenericMsg& msg, bool verbose, int timeout)
   }
   else if (ret == 3 && data[0] == 0x08 && data[1] == 0x03)
   {
-    if (!command_line_options->quiet)
+    if (!g_options->quiet)
     {
       if (data[2] == 0x00)
         std::cout << "Headset: none";
diff --git a/src/xboxdrv.cpp b/src/xboxdrv.cpp
index 8a729f4..c29bee6 100644
--- a/src/xboxdrv.cpp
+++ b/src/xboxdrv.cpp
@@ -44,6 +44,7 @@
 #include "helper.hpp"
 #include "evdev_helper.hpp"
 #include "command_line_options.hpp"
+#include "options.hpp"
 #include "xbox_generic_controller.hpp"
 
 #include "xboxdrv.hpp"
@@ -56,13 +57,13 @@ void on_sigint(int)
 {
   if (global_exit_xboxdrv)
   {
-    if (!command_line_options->quiet)
+    if (!g_options->quiet)
       std::cout << "Ctrl-c pressed twice, exiting hard" << std::endl;
     exit(EXIT_SUCCESS);
   }
   else
   {
-    if (!command_line_options->quiet)
+    if (!g_options->quiet)
       std::cout << "Shutdown initiated, press Ctrl-c again if nothing is happening" << std::endl;
 
     global_exit_xboxdrv = true; 
@@ -73,7 +74,7 @@ void on_sigint(int)
 
 void on_sigterm(int)
 {
-  if (!command_line_options->quiet)
+  if (!g_options->quiet)
     std::cout << "Shutdown initiated by SIGTERM" << std::endl;
 
   if (global_controller)
@@ -149,17 +150,17 @@ Xboxdrv::run_list_controller()
 }
 
 bool
-Xboxdrv::find_controller_by_path(const char* busid, const char* devid,struct usb_device** xbox_device) const
+Xboxdrv::find_controller_by_path(const std::string& busid, const std::string& devid,struct usb_device** xbox_device) const
 {
   struct usb_bus* busses = usb_get_busses();
 
   for (struct usb_bus* bus = busses; bus; bus = bus->next)
   {
-    if (strcmp(bus->dirname, busid) == 0)
+    if (bus->dirname == busid)
     {
       for (struct usb_device* dev = bus->devices; dev; dev = dev->next) 
       {
-        if (strcmp(dev->filename, devid) == 0)
+        if (dev->filename == devid)
         {
           *xbox_device = dev;
           return true;
@@ -272,7 +273,7 @@ Xboxdrv::find_xbox360_controller(int id, struct usb_device** xbox_device, XPadDe
 }
 
 void
-Xboxdrv::apply_modifier(XboxGenericMsg& msg, int msec_delta, const CommandLineOptions& opts) const
+Xboxdrv::apply_modifier(XboxGenericMsg& msg, int msec_delta, const Options& opts) const
 {
   apply_calibration_map(msg, opts.calibration_map);
 
@@ -293,7 +294,7 @@ Xboxdrv::apply_modifier(XboxGenericMsg& msg, int msec_delta, const CommandLineOp
 }
 
 void
-Xboxdrv::controller_loop(GamepadType type, uInput* uinput, XboxGenericController* controller, const CommandLineOptions& opts)
+Xboxdrv::controller_loop(GamepadType type, uInput* uinput, XboxGenericController* controller, const Options& opts)
 {
   int timeout = 0; // 0 == no timeout
   XboxGenericMsg oldmsg; // last data send to uinput
@@ -392,7 +393,7 @@ Xboxdrv::controller_loop(GamepadType type, uInput* uinput, XboxGenericController
 void
 Xboxdrv::find_controller(struct usb_device*& dev,
                          XPadDevice&         dev_type,
-                         const CommandLineOptions& opts) const
+                         const Options& opts) const
 {
   if (opts.busid[0] != '\0' && opts.devid[0] != '\0')
   {
@@ -453,11 +454,16 @@ Xboxdrv::find_controller(struct usb_device*& dev,
 }
 
 void
-Xboxdrv::run_main(const CommandLineOptions& opts)
+Xboxdrv::run_main(const Options& opts)
 {
   if (!opts.quiet)
   {
-    opts.print_version();
+    std::cout
+      << "xboxdrv " PACKAGE_VERSION " - http://pingus.seul.org/~grumbel/xboxdrv/\n"
+      << "Copyright © 2008-2010 Ingo Ruhnke <grumbel@gmx.de>\n"
+      << "Licensed under GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n"
+      << "This program comes with ABSOLUTELY NO WARRANTY.\n"
+      << "This is free software, and you are welcome to redistribute it under certain conditions; see the file COPYING for details.\n";
     std::cout << std::endl;
   }
 
@@ -601,7 +607,7 @@ Xboxdrv::run_main(const CommandLineOptions& opts)
 void
 Xboxdrv::print_info(struct usb_device* dev,
                     const XPadDevice& dev_type,
-                    const CommandLineOptions& opts) const
+                    const Options& opts) const
 {
   std::cout << "USB Device:        " << dev->bus->dirname << ":" << dev->filename << std::endl;
   std::cout << "Controller:        " << boost::format("\"%s\" (idVendor: 0x%04x, idProduct: 0x%04x)")
@@ -748,7 +754,7 @@ Xboxdrv::run_help_devices()
 }
 
 void
-Xboxdrv::run_daemon(const CommandLineOptions& opts)
+Xboxdrv::run_daemon(const Options& opts)
 {
   pid_t pid = fork();
 
@@ -773,45 +779,47 @@ Xboxdrv::main(int argc, char** argv)
     signal(SIGINT,  on_sigint);
     signal(SIGTERM, on_sigterm);
 
-    CommandLineOptions opts;
-    opts.parse_args(argc, argv);
-    command_line_options = &opts;
+    Options opts;
+    g_options = &opts;
+
+    CommandLineParser cmd_parser;
+    cmd_parser.parse_args(argc, argv, &opts);
 
     switch(opts.mode)
     {
-      case CommandLineOptions::PRINT_HELP_DEVICES:
+      case Options::PRINT_HELP_DEVICES:
         run_help_devices();
         break;
 
-      case CommandLineOptions::RUN_LIST_SUPPORTED_DEVICES:
+      case Options::RUN_LIST_SUPPORTED_DEVICES:
         run_list_supported_devices();
         break;
 
-      case CommandLineOptions::RUN_LIST_SUPPORTED_DEVICES_XPAD:
+      case Options::RUN_LIST_SUPPORTED_DEVICES_XPAD:
         run_list_supported_devices_xpad();
         break;
 
-      case CommandLineOptions::PRINT_VERSION:
-        opts.print_version();
+      case Options::PRINT_VERSION:
+        cmd_parser.print_version();
         break;
 
-      case CommandLineOptions::PRINT_HELP:
-        opts.print_help();
+      case Options::PRINT_HELP:
+        cmd_parser.print_help();
         break;
 
-      case CommandLineOptions::PRINT_LED_HELP:
-        opts.print_led_help();
+      case Options::PRINT_LED_HELP:
+        cmd_parser.print_led_help();
         break;
 
-      case CommandLineOptions::RUN_DEFAULT:
+      case Options::RUN_DEFAULT:
         run_main(opts);
         break;
 
-      case CommandLineOptions::RUN_DAEMON:
+      case Options::RUN_DAEMON:
         run_daemon(opts);
         break;
 
-      case CommandLineOptions::RUN_LIST_CONTROLLER:
+      case Options::RUN_LIST_CONTROLLER:
         run_list_controller();
         break;
     }
diff --git a/src/xboxdrv.hpp b/src/xboxdrv.hpp
index 1376700..1e9dbb4 100644
--- a/src/xboxdrv.hpp
+++ b/src/xboxdrv.hpp
@@ -22,15 +22,16 @@
 #include "xboxmsg.hpp"
 
 struct XPadDevice;
-class CommandLineOptions;
+class Options;
+class Options;
 class uInput;
 class XboxGenericController;
 
 class Xboxdrv
 {
 private:
-  void run_main(const CommandLineOptions& opts);
-  void run_daemon(const CommandLineOptions& opts);
+  void run_main(const Options& opts);
+  void run_daemon(const Options& opts);
   void run_list_supported_devices();
   void run_list_supported_devices_xpad();
   void run_help_devices();
@@ -38,16 +39,16 @@ private:
 
   void print_info(struct usb_device* dev,
                   const XPadDevice& dev_type,
-                  const CommandLineOptions& opts) const;
+                  const Options& opts) const;
   void controller_loop(GamepadType type, uInput* uinput,
                        XboxGenericController* controller, 
-                       const CommandLineOptions& opts);
-  void apply_modifier(XboxGenericMsg& msg, int msec_delta, const CommandLineOptions& opts) const;
+                       const Options& opts);
+  void apply_modifier(XboxGenericMsg& msg, int msec_delta, const Options& opts) const;
 
-  bool find_controller_by_path(const char* busid, const char* devid,struct usb_device** xbox_device) const;
+  bool find_controller_by_path(const std::string& busid, const std::string& devid,struct usb_device** xbox_device) const;
   void find_controller(struct usb_device*& dev,
                        XPadDevice&         dev_type,
-                       const CommandLineOptions& opts) const;
+                       const Options& opts) const;
   int  find_jsdev_number() const;
   int  find_evdev_number() const;
   bool find_controller_by_id(int id, int vendor_id, int product_id, struct usb_device** xbox_device) const;
diff --git a/src/xboxmsg.cpp b/src/xboxmsg.cpp
index 02bc76b..d4840d8 100644
--- a/src/xboxmsg.cpp
+++ b/src/xboxmsg.cpp
@@ -22,7 +22,7 @@
 #include <algorithm>
 
 #include "helper.hpp"
-#include "command_line_options.hpp"
+#include "options.hpp"
 #include "xboxmsg.hpp"
 
 std::string gamepadtype_to_string(const GamepadType& type)
@@ -152,7 +152,7 @@ std::ostream& operator<<(std::ostream& out, const Xbox360GuitarMsg& msg)
     % int(msg.blue)
     % int(msg.orange);
 
-  if (command_line_options->verbose)
+  if (g_options->verbose)
   {
     out << boost::format("| dummy: %d %d %d %d %02hhx %02hhx %04hx %04hx %02x %02x")
       % int(msg.thumb_l)
@@ -205,7 +205,7 @@ std::ostream& operator<<(std::ostream& out, const Xbox360Msg& msg)
   out << boost::format("  LT:%3d RT:%3d")
     % int(msg.lt) % int(msg.rt);
 
-  if (command_line_options->verbose)
+  if (g_options->verbose)
     out << " Dummy: " << msg.dummy1 << " " << msg.dummy2 << " " << msg.dummy3;
 
   return out;
@@ -245,7 +245,7 @@ std::ostream& operator<<(std::ostream& out, const XboxMsg& msg)
     % int(msg.lt) 
     % int(msg.rt);
 
-  if (command_line_options->verbose)
+  if (g_options->verbose)
     out << " Dummy: " << msg.dummy;
 
   return out;