]> git.stg.codes - stg.git/commitdiff
Implemented new command line options parser.
authorMaxim Mamontov <faust.madf@gmail.com>
Sat, 9 Nov 2013 13:40:07 +0000 (15:40 +0200)
committerMaxim Mamontov <faust.madf@gmail.com>
Sat, 9 Nov 2013 13:40:07 +0000 (15:40 +0200)
projects/sgconf/Makefile
projects/sgconf/action.h [new file with mode: 0644]
projects/sgconf/actions.cpp [new file with mode: 0644]
projects/sgconf/actions.h [new file with mode: 0644]
projects/sgconf/composer.h [deleted file]
projects/sgconf/config.h
projects/sgconf/main.cpp
projects/sgconf/options.cpp [new file with mode: 0644]
projects/sgconf/options.h [new file with mode: 0644]
projects/sgconf/parser_state.h
projects/sgconf/parsers.h [deleted file]

index 096991221d761977ddd36c10897a4ff922d8ac55..0098ff5ef0b7adab9d1edd0e564ab22cdf69c20e 100644 (file)
@@ -7,7 +7,9 @@ include ../../Makefile.conf
 PROG = sgconf
 
 SRCS = ./main.cpp \
 PROG = sgconf
 
 SRCS = ./main.cpp \
-       ./common_sg.cpp
+       ./common_sg.cpp \
+       ./options.cpp \
+       ./actions.cpp
 
 STGLIBS = conffiles \
           srvconf \
 
 STGLIBS = conffiles \
           srvconf \
diff --git a/projects/sgconf/action.h b/projects/sgconf/action.h
new file mode 100644 (file)
index 0000000..469d746
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *    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 2 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, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_SGCONF_ACTION_H__
+#define __STG_SGCONF_ACTION_H__
+
+#include <string>
+#include <stdexcept>
+
+namespace SGCONF
+{
+
+class OPTION_BLOCK;
+struct PARSER_STATE;
+
+class ACTION
+{
+    public:
+        virtual ~ACTION() {}
+
+        virtual std::string ParamDescription() const = 0;
+        virtual std::string DefaultDescription() const = 0;
+        virtual OPTION_BLOCK & Suboptions() = 0;
+        virtual PARSER_STATE Parse(int argc, char ** argv) = 0;
+
+        class ERROR : public std::runtime_error
+        {
+            public:
+                ERROR(const std::string & message)
+                    : std::runtime_error(message.c_str()) {}
+        };
+};
+
+} // namespace SGCONF
+
+#endif
diff --git a/projects/sgconf/actions.cpp b/projects/sgconf/actions.cpp
new file mode 100644 (file)
index 0000000..742ff04
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ *    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 2 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, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#include "actions.h"
+
+using SGCONF::FUNC0_ACTION;
+using SGCONF::PARSER_STATE;
+
+PARSER_STATE FUNC0_ACTION::Parse(int argc, char ** argv)
+{
+m_func();
+return PARSER_STATE(true, argc, argv);
+}
diff --git a/projects/sgconf/actions.h b/projects/sgconf/actions.h
new file mode 100644 (file)
index 0000000..739fbf1
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ *    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 2 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, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_SGCONF_ACTIONS_H__
+#define __STG_SGCONF_ACTIONS_H__
+
+#include "action.h"
+#include "options.h"
+#include "parser_state.h"
+
+#include "stg/common.h"
+#include "stg/resetable.h"
+
+#include <string>
+
+namespace SGCONF
+{
+
+typedef void (* FUNC0)();
+
+class FUNC0_ACTION : public ACTION
+{
+    public:
+        FUNC0_ACTION(FUNC0 func) : m_func(func) {}
+
+        virtual std::string ParamDescription() const { return ""; }
+        virtual std::string DefaultDescription() const { return ""; }
+        virtual OPTION_BLOCK & Suboptions() { return m_suboptions; }
+        virtual PARSER_STATE Parse(int argc, char ** argv);
+
+    private:
+        FUNC0 m_func;
+        OPTION_BLOCK m_suboptions;
+};
+
+inline
+FUNC0_ACTION * MakeFunc0Action(FUNC0 func)
+{
+return new FUNC0_ACTION(func);
+}
+
+template <typename T>
+class PARAM_ACTION: public ACTION
+{
+    public:
+        PARAM_ACTION(RESETABLE<T> & param,
+                     const T & defaultValue,
+                     const std::string & paramDescription)
+            : m_param(param),
+              m_defaltValue(defaultValue),
+              m_description(paramDescription),
+              m_hasDefault(true)
+        {}
+        PARAM_ACTION(RESETABLE<T> & param,
+                     const std::string & paramDescription)
+            : m_param(param),
+              m_description(paramDescription),
+              m_hasDefault(false)
+        {}
+
+        virtual std::string ParamDescription() const { return m_description; }
+        virtual std::string DefaultDescription() const;
+        virtual OPTION_BLOCK & Suboptions() { return m_suboptions; }
+        virtual PARSER_STATE Parse(int argc, char ** argv);
+
+    private:
+        RESETABLE<T> & m_param;
+        T m_defaltValue;
+        std::string m_description;
+        bool m_hasDefault;
+        OPTION_BLOCK m_suboptions;
+};
+
+template <typename T>
+inline
+std::string PARAM_ACTION<T>::DefaultDescription() const
+{
+return m_hasDefault ? " (default: '" + x2str(m_defaltValue) + "')"
+                    : "";
+}
+
+template <>
+inline
+std::string PARAM_ACTION<std::string>::DefaultDescription() const
+{
+return m_hasDefault ? " (default: '" + m_defaltValue + "')"
+                    : "";
+}
+
+template <typename T>
+inline
+PARSER_STATE PARAM_ACTION<T>::Parse(int argc, char ** argv)
+{
+T value;
+if (str2x(*argv, value))
+    throw ERROR(std::string("Bad argument: '") + *argv + "'");
+m_param = value;
+return PARSER_STATE(false, --argc, ++argv);
+}
+
+template <>
+inline
+PARSER_STATE PARAM_ACTION<std::string>::Parse(int argc, char ** argv)
+{
+m_param = *argv;
+return PARSER_STATE(false, --argc, ++argv);
+}
+
+template <typename T>
+inline
+PARAM_ACTION<T> * MakeParamAction(RESETABLE<T> & param,
+                                  const T & defaultValue,
+                                  const std::string & paramDescription)
+{
+return new PARAM_ACTION<T>(param, defaultValue, paramDescription);
+}
+
+template <typename T>
+inline
+PARAM_ACTION<T> * MakeParamAction(RESETABLE<T> & param,
+                                  const std::string & paramDescription)
+{
+return new PARAM_ACTION<T>(param, paramDescription);
+}
+
+} // namespace SGCONF
+
+#endif
diff --git a/projects/sgconf/composer.h b/projects/sgconf/composer.h
deleted file mode 100644 (file)
index a68bce9..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- *    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 2 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, write to the Free Software
- *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-/*
- *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
- */
-
-#ifndef __STG_SGCONF_COMPOSER_H__
-#define __STG_SGCONF_COMPOSER_H__
-
-#include "parser_state.h"
-
-namespace SGCONF
-{
-
-class COMPOSER
-{
-    public:
-        typedef PARSER_STATE (* FUNC)(int, char **, CONFIG&);
-        COMPOSER(int argc, char ** argv)
-            : m_done(false), m_result(0)
-        { mstate.argc = argc; m_state.argv = argv; }
-        COMPOSER compose(FUNC func)
-        {
-        if (m_done)
-            return COMPOSER(m_result);
-        try
-            {
-            PARSER_STATE state(func(m_state.argc, m_state.argv, m_state.config));
-            if (state.result)
-                return COMPOSER(0);
-            else
-                return COMPOSER(state);
-            }
-        catch (const PARSER_ERROR& ex)
-            {
-            std::cerr << ex.what() << "\n";
-            return COMPOSER(-1);
-            }
-        }
-        int exec()
-        {
-        if (m_done)
-            return m_result;
-        Usage();
-        return -1;
-        }
-
-    private:
-        bool m_done;
-        int m_result;
-        PARSER_STATE m_state;
-
-        COMPOSER(int result)
-            : m_done(true),
-              m_result(result)
-        {
-        }
-
-        COMPOSER(const PARSER_STATE& state)
-            : m_done(false),
-              m_result(0),
-              m_state(state)
-};
-
-}
index 68aade1d18b4d931902586969d6bd87cfb457ebf..9ed90c737a21b78855abe833f395d787428fb499 100644 (file)
@@ -39,3 +39,5 @@ struct CONFIG
 };
 
 }
 };
 
 }
+
+#endif
index c0debdc11ac901d943264fa122d994610564e998..8644e690ddd5dcd693c92730c7c4f225b6793e9d 100644 (file)
 
 /*
  *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
 
 /*
  *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-
- /*
- $Author: faust $
- $Revision: 1.25 $
- $Date: 2010/03/25 14:37:43 $
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
  */
 
 #include "request.h"
 #include "common_sg.h"
 #include "sg_error_codes.h"
 
  */
 
 #include "request.h"
 #include "common_sg.h"
 #include "sg_error_codes.h"
 
+#include "options.h"
+#include "actions.h"
+#include "config.h"
+
 #include "stg/user_conf.h"
 #include "stg/user_stat.h"
 #include "stg/common.h"
 #include "stg/user_conf.h"
 #include "stg/user_stat.h"
 #include "stg/common.h"
@@ -76,7 +75,9 @@ array[pos] = value;
 return true;
 }
 
 return true;
 }
 
-void Usage(bool full);
+void Usage();
+void UsageAll();
+void UsageImpl(bool full);
 void UsageConnection();
 void UsageAdmins(bool full);
 void UsageTariffs(bool full);
 void UsageConnection();
 void UsageAdmins(bool full);
 void UsageTariffs(bool full);
@@ -84,8 +85,91 @@ void UsageUsers(bool full);
 void UsageServices(bool full);
 void UsageCorporations(bool full);
 
 void UsageServices(bool full);
 void UsageCorporations(bool full);
 
+void Version();
+
 } // namespace anonymous
 
 } // namespace anonymous
 
+namespace SGCONF
+{
+
+class CONFIG_ACTION: public ACTION
+{
+    public:
+        CONFIG_ACTION(CONFIG & config,
+                      const std::string & paramDescription)
+            : m_config(config),
+              m_description(paramDescription)
+        {}
+
+        virtual std::string ParamDescription() const { return m_description; }
+        virtual std::string DefaultDescription() const { return ""; }
+        virtual OPTION_BLOCK & Suboptions() { return m_suboptions; }
+        virtual PARSER_STATE Parse(int argc, char ** argv);
+
+    private:
+        CONFIG & m_config;
+        std::string m_description;
+        OPTION_BLOCK m_suboptions;
+
+        void ParseCredentials(const std::string & credentials);
+        void ParseHostAndPort(const std::string & hostAndPort);
+};
+
+PARSER_STATE CONFIG_ACTION::Parse(int argc, char ** argv)
+{
+char * pos = strchr(*argv, '@');
+if (pos != NULL)
+    {
+    ParseCredentials(std::string(*argv, pos));
+    ParseHostAndPort(std::string(pos + 1));
+    }
+else
+    {
+    ParseHostAndPort(std::string(*argv));
+    }
+return PARSER_STATE(false, --argc, ++argv);
+}
+
+void CONFIG_ACTION::ParseCredentials(const std::string & credentials)
+{
+std::string::size_type pos = credentials.find_first_of(':');
+if (pos != std::string::npos)
+    {
+    m_config.userName = credentials.substr(0, pos);
+    m_config.userPass = credentials.substr(pos + 1);
+    }
+else
+    {
+    m_config.userName = credentials;
+    }
+}
+
+void CONFIG_ACTION::ParseHostAndPort(const std::string & hostAndPort)
+{
+std::string::size_type pos = hostAndPort.find_first_of(':');
+if (pos != std::string::npos)
+    {
+    m_config.server = hostAndPort.substr(0, pos);
+    uint16_t port = 0;
+    if (str2x(hostAndPort.substr(pos + 1), port))
+        throw ERROR("Invalid port value: '" + hostAndPort.substr(pos + 1) + "'");
+    m_config.port = port;
+    }
+else
+    {
+    m_config.server = hostAndPort;
+    }
+}
+
+inline
+CONFIG_ACTION * MakeParamAction(CONFIG & config,
+                                const std::string & paramDescription)
+{
+return new CONFIG_ACTION(config, paramDescription);
+}
+
+} // namespace SGCONF
+
 time_t stgTime;
 
 struct option long_options_get[] = {
 time_t stgTime;
 
 struct option long_options_get[] = {
@@ -1052,66 +1136,29 @@ if (isMessage)
 return ProcessSetUser(req.server.data(), req.port.data(), req.admLogin.data(), req.admPasswd.data(), req.login.data(), conf, stat);
 }
 //-----------------------------------------------------------------------------
 return ProcessSetUser(req.server.data(), req.port.data(), req.admLogin.data(), req.admPasswd.data(), req.login.data(), conf, stat);
 }
 //-----------------------------------------------------------------------------
-PARSER_STATE TryParse(const PARSERS& parsers, char ** argv, int argc)
-{
-PARSERS::const_iterator it = parsers.find(*argv);
-if (it != parsers.end())
-    return it->second(++argv, --argc);
-PARSER_STATE state;
-state.argc = argc;
-state.argv = argv;
-state.result = false;
-return state;
-}
-//-----------------------------------------------------------------------------
-PARSER_STATE ParseCommon(int argc, char ** argv, CONFIG& config)
-{
-if (pos == 0)
-    ++pos;
-
-PARSERS parsers;
-parsers.add<std::string>("-c", "--config", config.configFile);
-parsers.add<void>("-h", "--help", Usage, false);
-parsers.add<void>("--help-all", Usage, true);
-parsers.add<void>("-v", "--version", Version);
-
-while (true)
-    {
-    PARSER_STATE state(TryParse(parsers, argv, argc, config));
-    if (state.argv == argv)
-        return state; // No-op
-    if (state.argc == 0)
-        return state; // EOF
-    if (state.result)
-        return state; // Done
-    argv = state.argv;
-    argc = state.argc;
-    }
-
-assert(0 && "Can't be here.");
-return PARSER_STATE();
-}
-//-----------------------------------------------------------------------------
 int main(int argc, char **argv)
 {
 int main(int argc, char **argv)
 {
-Usage(true);
+UsageAll();
 exit(0);
 
 exit(0);
 
-// Ok - succesfully parsed
-// Done - don't continue, return 0
-// Error - don't continue, return -1
-// No-op - nothing changed
+SGCONF::CONFIG config;
 
 
-return COMPOSER(argv).compose(ParseCommon)
-                     .compose(ReadConfig)
-                     .compose(ParseCommand)
-                     .exec();
+SGCONF::OPTION_BLOCK generalOptions;
+generalOptions.Add("c", "config", SGCONF::MakeParamAction(config.configFile, std::string("~/.config/stg/sgconf.conf"), "<config file>"), "override default config file");
+generalOptions.Add("h", "help", SGCONF::MakeFunc0Action(Usage), "show this help and exit");
+generalOptions.Add("help-all", SGCONF::MakeFunc0Action(UsageAll), "show full help and exit");
+generalOptions.Add("v", "version", SGCONF::MakeFunc0Action(Version), "show version information and exit");
 
 
+SGCONF::OPTION_BLOCK connOptions;
+connOptions.Add("s", "server", SGCONF::MakeParamAction(config.server, std::string("localhost"), "<address>"), "host to connect");
+connOptions.Add("p", "port", SGCONF::MakeParamAction(config.port, uint16_t(5555), "<port>"), "port to connect");
+connOptions.Add("u", "username", SGCONF::MakeParamAction(config.userName, std::string("admin"), "<username>"), "administrative login");
+connOptions.Add("w", "userpass", SGCONF::MakeParamAction(config.userPass, "<password>"), "password for the administrative login");
+connOptions.Add("a", "address", SGCONF::MakeParamAction(config, "<connection string>"), "connection params as a single string in format: <login>:<password>@<host>:<port>");
 
 if (argc < 2)
     {
 
 if (argc < 2)
     {
-    // TODO: no arguments
-    Usage(false);
+    Usage();
     return 1;
     }
 
     return 1;
     }
 
@@ -1145,7 +1192,17 @@ return UNKNOWN_ERR_CODE;
 namespace
 {
 
 namespace
 {
 
-void Usage(bool full)
+void Usage()
+{
+UsageImpl(false);
+}
+
+void UsageAll()
+{
+UsageImpl(true);
+}
+
+void UsageImpl(bool full)
 {
 std::cout << "sgconf is the Stargazer management utility.\n\n"
           << "Usage:\n"
 {
 std::cout << "sgconf is the Stargazer management utility.\n\n"
           << "Usage:\n"
@@ -1336,4 +1393,9 @@ if (full)
               << "\t\t--set-cash <cash>[:<message>]\tnew corporation's cash and optional comment message\n\n";
 }
 
               << "\t\t--set-cash <cash>[:<message>]\tnew corporation's cash and optional comment message\n\n";
 }
 
+void Version()
+{
+std::cout << "sgconf, version: 2.0.0-alpha.\n";
+}
+
 } // namespace anonymous
 } // namespace anonymous
diff --git a/projects/sgconf/options.cpp b/projects/sgconf/options.cpp
new file mode 100644 (file)
index 0000000..71f9687
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ *    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 2 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, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#include "options.h"
+
+#include "action.h"
+#include "parser_state.h"
+
+#include <iostream>
+#include <functional>
+#include <algorithm>
+
+using SGCONF::OPTION;
+using SGCONF::OPTION_BLOCK;
+using SGCONF::ACTION;
+using SGCONF::PARSER_STATE;
+
+OPTION::OPTION(const std::string & shortName,
+               const std::string & longName,
+               ACTION * action,
+               const std::string & description)
+    : m_shortName(shortName),
+      m_longName(longName),
+      m_action(action),
+      m_description(description)
+{
+}
+
+OPTION::OPTION(const std::string & longName,
+               ACTION * action,
+               const std::string & description)
+    : m_longName(longName),
+      m_action(action),
+      m_description(description)
+{
+}
+
+OPTION::OPTION(const OPTION & rhs)
+    : m_shortName(rhs.m_shortName),
+      m_longName(rhs.m_longName),
+      m_action(rhs.m_action),
+      m_description(rhs.m_description)
+{
+}
+
+OPTION::~OPTION()
+{
+delete m_action;
+}
+
+void OPTION::Help(size_t level) const
+{
+if (!m_action)
+    throw ERROR("Option is not defined.");
+std::string indent(level, '\t');
+std::cout << indent << "\t";
+if (!m_shortName.empty())
+    std::cout << "-" << m_shortName << ", ";
+std::cout << "--" << m_longName << " " << m_action->ParamDescription()
+          << "\t" << m_description << m_action->DefaultDescription() << "\n";
+m_action->Suboptions().Help(level + 1);
+}
+
+bool OPTION::Check(const char * arg) const
+{
+if (arg == NULL)
+    return false;
+
+if (*arg++ != '-')
+    return false;
+
+if (*arg == '-')
+    return m_longName == arg + 1;
+
+return m_shortName == arg;
+}
+
+PARSER_STATE OPTION::Parse(int argc, char ** argv)
+{
+if (!m_action)
+    throw ERROR("Option is not defined.");
+try
+    {
+    return m_action->Parse(argc, argv);
+    }
+catch (const ACTION::ERROR & ex)
+    {
+    throw ERROR(m_longName + ": " + ex.what());
+    }
+}
+
+void OPTION_BLOCK::Add(const std::string & shortName,
+                       const std::string & longName,
+                       ACTION * action,
+                       const std::string & description)
+{
+m_options.push_back(OPTION(shortName, longName, action, description));
+}
+
+void OPTION_BLOCK::Add(const std::string & longName,
+                       ACTION * action,
+                       const std::string & description)
+{
+m_options.push_back(OPTION(longName, action, description));
+}
+
+void OPTION_BLOCK::Help(size_t level) const
+{
+std::for_each(m_options.begin(),
+              m_options.end(),
+              std::bind2nd(std::mem_fun_ref(&OPTION::Help), level));
+}
+
+PARSER_STATE OPTION_BLOCK::Parse(int argc, char ** argv)
+{
+PARSER_STATE state(false, argc, argv);
+while (state.argc > 0 && !state.stop)
+    {
+    std::vector<OPTION>::iterator it = std::find_if(m_options.begin(), m_options.end(), std::bind2nd(std::mem_fun_ref(&OPTION::Check), *state.argv));
+    if (it != m_options.end())
+        state = it->Parse(--state.argc, ++state.argv);
+    else
+        break;
+    }
+return state;
+}
diff --git a/projects/sgconf/options.h b/projects/sgconf/options.h
new file mode 100644 (file)
index 0000000..696255f
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ *    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 2 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, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_SGCONF_OPTIONS_H__
+#define __STG_SGCONF_OPTIONS_H__
+
+#include <string>
+#include <vector>
+#include <stdexcept>
+#include <cstddef> // size_t
+
+namespace SGCONF
+{
+
+class ACTION;
+struct PARSER_STATE;
+
+class OPTION
+{
+    public:
+        OPTION(const std::string & shortName,
+               const std::string & longName,
+               ACTION * action,
+               const std::string & description);
+        OPTION(const std::string & longName,
+               ACTION * action,
+               const std::string & description);
+        OPTION(const OPTION & rhs);
+        ~OPTION();
+
+        OPTION & operator=(const OPTION & rhs);
+
+        void Help(size_t level = 0) const;
+        PARSER_STATE Parse(int argc, char ** argv);
+        bool Check(const char * arg) const;
+
+        class ERROR : public std::runtime_error
+        {
+            public:
+                ERROR(const std::string & message)
+                    : std::runtime_error(message.c_str()) {}
+        };
+
+    private:
+        std::string m_shortName;
+        std::string m_longName;
+        ACTION * m_action;
+        std::string m_description;
+};
+
+class OPTION_BLOCK
+{
+    public:
+        void Add(const std::string & shortName,
+                 const std::string & longName,
+                 ACTION * action,
+                 const std::string & description);
+        void Add(const std::string & longName,
+                 ACTION * action,
+                 const std::string & description);
+
+        void Help(size_t level) const;
+
+        PARSER_STATE Parse(int argc, char ** argv);
+
+    private:
+        std::vector<OPTION> m_options;
+};
+
+} // namespace SGCONF
+
+#endif
index 1482133e3087c01e2f539f84145a594141259ccc..22ad794f4e1c9b43ef8415d624f1e32eb7fb0292 100644 (file)
 #ifndef __STG_SGCONF_PARSER_STATE_H__
 #define __STG_SGCONF_PARSER_STATE_H__
 
 #ifndef __STG_SGCONF_PARSER_STATE_H__
 #define __STG_SGCONF_PARSER_STATE_H__
 
-#include "config.h"
-
 namespace SGCONF
 {
 
 struct PARSER_STATE
 {
 namespace SGCONF
 {
 
 struct PARSER_STATE
 {
-    CONFIG config;
-    bool result;
+    PARSER_STATE(bool s, int c, char ** v) : stop(s), argc(c), argv(v) {}
+    bool stop;
     int argc;
     char ** argv;
 };
 
 }
     int argc;
     char ** argv;
 };
 
 }
+
+#endif
diff --git a/projects/sgconf/parsers.h b/projects/sgconf/parsers.h
deleted file mode 100644 (file)
index 3ecb18a..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- *    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 2 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, write to the Free Software
- *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-/*
- *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
- */
-
-#ifndef __STG_SGCONF_PARSERS_H__
-#define __STG_SGCONF_PARSERS_H__
-
-namespace SGCONF
-{
-
-typedef void (*FUNC0)();
-
-template <typename T>
-struct FUNC1
-{
-typedef void (*type)(T);
-};
-
-class PARSER
-{
-    public:
-        virtual PARSER_STATE parse(int, char **, CONFIG&) = 0;
-};
-
-template <typename T>
-class PARAM_PARSER : public PARSER
-{
-    public:
-        PARAM_PARSER(T& var) : m_var(var) {}
-        virtual PARSER_STATE parse(int argc, char ** argv, CONFIG& config)
-        {
-        std::istringstream stream(argv[0]);
-        stream >> m_var;
-        PARSER_STATE state;
-        state.argc = argc - 1;
-        state.argv = argv + 1;
-        state.config = config;
-        state.result = false;
-        return state;
-        }
-
-    private:
-        T& m_var;
-};
-
-class FUNC0_PARSER
-{
-    public:
-        FUNC0_PARSER(FUNC0 func) : m_func(func) {}
-        virtual PARSER_STATE parse(int argc, char ** argv, CONFIG& config)
-        {
-        m_func();
-        PARSER_STATE state;
-        state.argc = argc - 1;
-        state.argv = argv + 1;
-        state.config = config;
-        state.result = true;
-        return state;
-        }
-
-    private:
-        FUNC0 m_func;
-};
-
-template <typename T>
-class FUNC1_PARSER
-{
-    public:
-        FUNC1_PARSER(typename FUNC1<T>::type func, const T & arg) : m_func(func), m_arg(arg) {}
-        virtual PARSER_STATE parse(int argc, char ** argv, CONFIG& config)
-        {
-        m_func(m_arg);
-        PARSER_STATE state;
-        state.argc = argc - 1;
-        state.argv = argv + 1;
-        state.config = config;
-        state.result = true;
-        return state;
-        }
-
-    private:
-        typename FUNC1<T>::type m_func;
-        T m_arg;
-}
-
-class PARSERS
-{
-    public:
-        typedef PARSER_STATE (* FUNC)(int, char **, CONFIG&);
-
-        template <typename T>
-        void add(const std::string & shortToken,
-                 const std::string & fullToken,
-                 T& var);
-
-        template <>
-        void add<void>(const std:string & shortToken,
-                       const std::string & fullToken,
-                       FUNC0 func);
-        template <typename V>
-        void add<void>(const std:string & shortToken,
-                       const std::string & fullToken,
-                       FUNC1 func, const V& v);
-
-    private:
-};
-
-}