]> git.stg.codes - stg.git/commitdiff
Merge branch 'master' of gitorious.org:stg/stg
authorMaxim Mamontov <faust.madf@gmail.com>
Thu, 14 Nov 2013 20:01:56 +0000 (22:01 +0200)
committerMaxim Mamontov <faust.madf@gmail.com>
Thu, 14 Nov 2013 20:01:56 +0000 (22:01 +0200)
12 files changed:
include/stg/const.h
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 e882200df1c1783d2280088c4a79d21349c7987b..55f5b54bc9e6102f9cc1cb7f82e2aa5981964585 100644 (file)
@@ -80,8 +80,6 @@
 #define NO_TARIFF_NAME  "*_NO_TARIFF_*"
 #define NO_CORP_NAME    "*_NO_CORP_*"
 
-#define mega (1024 * 1024)
-
 #define MONITOR_TIME_DELAY_SEC  (60)
 
 #endif
index 096991221d761977ddd36c10897a4ff922d8ac55..0098ff5ef0b7adab9d1edd0e564ab22cdf69c20e 100644 (file)
@@ -7,7 +7,9 @@ include ../../Makefile.conf
 PROG = sgconf
 
 SRCS = ./main.cpp \
-       ./common_sg.cpp
+       ./common_sg.cpp \
+       ./options.cpp \
+       ./actions.cpp
 
 STGLIBS = conffiles \
           srvconf \
diff --git a/projects/sgconf/action.h b/projects/sgconf/action.h
new file mode 100644 (file)
index 0000000..64d7c1e
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ *    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 ACTION * Clone() const = 0;
+        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()) {}
+        };
+};
+
+template <typename T>
+class ACTION_CLONE_MIXIN : public ACTION
+{
+    public:
+        virtual ACTION * Clone() const { return new T(*this); }
+};
+
+} // namespace SGCONF
+
+#endif
diff --git a/projects/sgconf/actions.cpp b/projects/sgconf/actions.cpp
new file mode 100644 (file)
index 0000000..afa5162
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ *    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>
+ */
diff --git a/projects/sgconf/actions.h b/projects/sgconf/actions.h
new file mode 100644 (file)
index 0000000..c88de14
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ *    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)();
+
+template <typename F>
+class FUNC0_ACTION : public ACTION
+{
+    public:
+        FUNC0_ACTION(const F & func) : m_func(func) {}
+
+        virtual ACTION * Clone() const { return new FUNC0_ACTION<F>(*this); }
+
+        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)
+        {
+        m_func();
+        return PARSER_STATE(true, argc, argv);
+        }
+
+    private:
+        F m_func;
+        OPTION_BLOCK m_suboptions;
+};
+
+template <typename F>
+inline
+FUNC0_ACTION<F> * MakeFunc0Action(F func)
+{
+return new FUNC0_ACTION<F>(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 ACTION * Clone() const { return new PARAM_ACTION<T>(*this); }
+
+        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)
+{
+if (argc == 0 ||
+    argv == NULL ||
+    *argv == NULL)
+    throw ERROR("Missing argument.");
+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)
+{
+if (argc == 0 ||
+    argv == NULL ||
+    *argv == NULL)
+    throw ERROR("Missing argument.");
+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..c1fc4c3e58a34c3388ca97dfc48666a743456e78 100644 (file)
 
 /*
  *    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 "options.h"
+#include "actions.h"
+#include "config.h"
+
 #include "stg/user_conf.h"
 #include "stg/user_stat.h"
 #include "stg/common.h"
@@ -66,6 +65,65 @@ struct ARRAY_TYPE<T[N]>
 typedef T type;
 };
 
+template <typename T>
+struct nullary_function
+{
+typedef T result_type;
+};
+
+template <typename F>
+class binder0 : public nullary_function<typename F::result_type>
+{
+    public:
+        binder0(const F & func, const typename F::argument_type & arg)
+            : m_func(func), m_arg(arg) {}
+        typename F::result_type operator()() const { return m_func(m_arg); }
+    private:
+        F m_func;
+        typename F::argument_type m_arg;
+};
+
+template <typename F>
+inline
+binder0<F> bind0(const F & func, const typename F::argument_type & arg)
+{
+return binder0<F>(func, arg);
+}
+
+template <typename C, typename A, typename R>
+class METHOD1_ADAPTER : public std::unary_function<A, R>
+{
+    public:
+        METHOD1_ADAPTER(R (C::* func)(A), C & obj) : m_func(func), m_obj(obj) {}
+        R operator()(A arg) { return (m_obj.*m_func)(arg); }
+    private:
+        R (C::* m_func)(A);
+        C & m_obj;
+};
+
+template <typename C, typename A, typename R>
+class CONST_METHOD1_ADAPTER : public std::unary_function<A, R>
+{
+    public:
+        CONST_METHOD1_ADAPTER(R (C::* func)(A) const, C & obj) : m_func(func), m_obj(obj) {}
+        R operator()(A arg) const { return (m_obj.*m_func)(arg); }
+    private:
+        R (C::* m_func)(A) const;
+        C & m_obj;
+};
+
+template <typename C, typename A, typename R>
+METHOD1_ADAPTER<C, A, R> Method1Adapt(R (C::* func)(A), C & obj)
+{
+return METHOD1_ADAPTER<C, A, R>(func, obj);
+}
+
+template <typename C, typename A, typename R>
+CONST_METHOD1_ADAPTER<C, A, R> Method1Adapt(R (C::* func)(A) const, C & obj)
+{
+return CONST_METHOD1_ADAPTER<C, A, R>(func, obj);
+}
+
 template <typename T>
 bool SetArrayItem(T & array, const char * index, const typename ARRAY_TYPE<T>::type & value)
 {
@@ -76,7 +134,9 @@ array[pos] = value;
 return true;
 }
 
-void Usage(bool full);
+void Usage();
+void UsageAll();
+void UsageImpl(bool full);
 void UsageConnection();
 void UsageAdmins(bool full);
 void UsageTariffs(bool full);
@@ -84,8 +144,97 @@ void UsageUsers(bool full);
 void UsageServices(bool full);
 void UsageCorporations(bool full);
 
+void Version();
+
 } // 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 ACTION * Clone() const { return new CONFIG_ACTION(*this); }
+
+        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)
+{
+if (argc == 0 ||
+    argv == NULL ||
+    *argv == NULL)
+    throw ERROR("Missing argument.");
+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[] = {
@@ -1052,66 +1201,50 @@ if (isMessage)
 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)
+int main(int argc, char **argv)
 {
-if (pos == 0)
-    ++pos;
+SGCONF::CONFIG config;
 
-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);
+SGCONF::OPTION_BLOCKS blocks;
+blocks.Add("General options")
+      .Add("c", "config", SGCONF::MakeParamAction(config.configFile, std::string("~/.config/stg/sgconf.conf"), "<config file>"), "override default config file")
+      .Add("h", "help", SGCONF::MakeFunc0Action(bind0(Method1Adapt(&SGCONF::OPTION_BLOCKS::Help, blocks), 0)), "\t\tshow this help and exit")
+      .Add("help-all", SGCONF::MakeFunc0Action(UsageAll), "\t\tshow full help and exit")
+      .Add("v", "version", SGCONF::MakeFunc0Action(Version), "\t\tshow version information and exit");
+blocks.Add("Connection options")
+      .Add("s", "server", SGCONF::MakeParamAction(config.server, std::string("localhost"), "<address>"), "\t\thost to connect")
+      .Add("p", "port", SGCONF::MakeParamAction(config.port, uint16_t(5555), "<port>"), "\t\tport to connect")
+      .Add("u", "username", SGCONF::MakeParamAction(config.userName, std::string("admin"), "<username>"), "\tadministrative login")
+      .Add("w", "userpass", SGCONF::MakeParamAction(config.userPass, "<password>"), "\tpassword for the administrative login")
+      .Add("a", "address", SGCONF::MakeParamAction(config, "<connection string>"), "connection params as a single string in format: <login>:<password>@<host>:<port>");
 
-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();
+SGCONF::PARSER_STATE state(false, argc, argv);
+
+try
+{
+state = blocks.Parse(--argc, ++argv); // Skipping self name
 }
-//-----------------------------------------------------------------------------
-int main(int argc, char **argv)
+catch (const SGCONF::OPTION::ERROR& ex)
 {
-Usage(true);
-exit(0);
+std::cerr << ex.what() << "\n";
+return -1;
+}
 
-// Ok - succesfully parsed
-// Done - don't continue, return 0
-// Error - don't continue, return -1
-// No-op - nothing changed
+if (state.stop)
+    return 0;
 
-return COMPOSER(argv).compose(ParseCommon)
-                     .compose(ReadConfig)
-                     .compose(ParseCommand)
-                     .exec();
+if (state.argc > 0)
+    {
+    std::cerr << "Unknown option: '" << *state.argv << "'\n";
+    return -1;
+    }
 
+return 0;
 
 if (argc < 2)
     {
-    // TODO: no arguments
-    Usage(false);
+    Usage();
     return 1;
     }
 
@@ -1145,7 +1278,17 @@ return UNKNOWN_ERR_CODE;
 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"
@@ -1336,4 +1479,9 @@ if (full)
               << "\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
diff --git a/projects/sgconf/options.cpp b/projects/sgconf/options.cpp
new file mode 100644 (file)
index 0000000..6fddaf3
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ *    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::OPTION_BLOCKS;
+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->Clone()),
+      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)
+    {
+    if (m_longName.empty())
+        throw ERROR("-" + m_shortName + ": " + ex.what());
+    else
+        throw ERROR("--" + m_longName + ", -" + m_shortName + ": " + ex.what());
+    }
+}
+
+OPTION_BLOCK & 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));
+return *this;
+}
+
+OPTION_BLOCK & OPTION_BLOCK::Add(const std::string & longName,
+                                 ACTION * action,
+                                 const std::string & description)
+{
+m_options.push_back(OPTION(longName, action, description));
+return *this;
+}
+
+void OPTION_BLOCK::Help(size_t level) const
+{
+if (m_options.empty())
+    return;
+std::cout << m_description << ":\n";
+std::for_each(m_options.begin(),
+              m_options.end(),
+              std::bind2nd(std::mem_fun_ref(&OPTION::Help), level + 1));
+}
+
+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;
+    ++it;
+    }
+return state;
+}
+
+void OPTION_BLOCKS::Help(size_t level) const
+{
+std::list<OPTION_BLOCK>::const_iterator it(m_blocks.begin());
+while (it != m_blocks.end())
+    {
+    it->Help(level);
+    std::cout << "\n";
+    ++it;
+    }
+}
+
+PARSER_STATE OPTION_BLOCKS::Parse(int argc, char ** argv)
+{
+PARSER_STATE state(false, argc, argv);
+std::list<OPTION_BLOCK>::iterator it(m_blocks.begin());
+while (!state.stop && it != m_blocks.end())
+    {
+    state = it->Parse(state.argc, state.argv);
+    ++it;
+    }
+return state;
+}
diff --git a/projects/sgconf/options.h b/projects/sgconf/options.h
new file mode 100644 (file)
index 0000000..3d4bdd6
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ *    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 <list>
+#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:
+        OPTION_BLOCK() {}
+        OPTION_BLOCK(const std::string & description)
+            : m_description(description) {}
+        OPTION_BLOCK & Add(const std::string & shortName,
+                           const std::string & longName,
+                           ACTION * action,
+                           const std::string & description);
+        OPTION_BLOCK & 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;
+        std::string m_description;
+};
+
+class OPTION_BLOCKS
+{
+    public:
+        OPTION_BLOCK & Add(const std::string & description)
+        { m_blocks.push_back(OPTION_BLOCK(description)); return m_blocks.back(); }
+        void Help(size_t level) const;
+        PARSER_STATE Parse(int argc, char ** argv);
+
+    private:
+        std::list<OPTION_BLOCK> m_blocks;
+};
+
+} // namespace SGCONF
+
+#endif
index 1482133e3087c01e2f539f84145a594141259ccc..22ad794f4e1c9b43ef8415d624f1e32eb7fb0292 100644 (file)
 #ifndef __STG_SGCONF_PARSER_STATE_H__
 #define __STG_SGCONF_PARSER_STATE_H__
 
-#include "config.h"
-
 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;
 };
 
 }
+
+#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:
-};
-
-}