diff options
author | randomdan <randomdan@localhost> | 2011-12-08 16:46:11 +0000 |
---|---|---|
committer | randomdan <randomdan@localhost> | 2011-12-08 16:46:11 +0000 |
commit | c9990b16272d9c9a55f1f7be1fdef5b625ad27aa (patch) | |
tree | 15b804e78d42233d736351569ec893280d1d7a5f | |
parent | Send the expiry time to CouchDB when deleting old sessions (it's time seems o... (diff) | |
download | project2-c9990b16272d9c9a55f1f7be1fdef5b625ad27aa.tar.bz2 project2-c9990b16272d9c9a55f1f7be1fdef5b625ad27aa.tar.xz project2-c9990b16272d9c9a55f1f7be1fdef5b625ad27aa.zip |
Drop Boost::program_options in favour of our own, pluggable system which integrates application platforms properly
42 files changed, 740 insertions, 427 deletions
diff --git a/project2/cgi/Jamfile.jam b/project2/cgi/Jamfile.jam index 261e992..48225cb 100644 --- a/project2/cgi/Jamfile.jam +++ b/project2/cgi/Jamfile.jam @@ -2,7 +2,6 @@ alias libxmlpp : : : : <cflags>"`pkg-config --cflags libxml++-2.6`" <linkflags>"`pkg-config --libs libxml++-2.6`" ; lib boost_filesystem : : <name>boost_filesystem ; -lib boost_program_options : : <name>boost_program_options ; lib cgicc : : <name>cgicc ; lib fcgi : : <name>fcgi ; lib fcgi++ : : <name>fcgi++ ; @@ -12,7 +11,6 @@ cpp-pch pch : pch.hpp : <library>cgicc <library>libxmlpp <library>../common//p2common - <library>boost_program_options <library>boost_filesystem <library>../xml//p2xml ; @@ -24,7 +22,6 @@ lib p2web : <library>cgicc <library>libxmlpp <library>../common//p2common - <library>boost_program_options <library>boost_filesystem <library>../xml//p2xml : : diff --git a/project2/cgi/cgiAppEngine.cpp b/project2/cgi/cgiAppEngine.cpp index 779b25a..7fd7c33 100644 --- a/project2/cgi/cgiAppEngine.cpp +++ b/project2/cgi/cgiAppEngine.cpp @@ -9,7 +9,6 @@ #include <boost/foreach.hpp> #include "ostreamWrapper.h" #include <boost/date_time/microsec_time_clock.hpp> -#include <glibmm/regex.h> const std::string SESSIONID = "sessionID"; typedef UUID SIDKey; @@ -27,7 +26,6 @@ getSessionID(const std::vector<cgicc::HTTPCookie> & cookies) { return UUID(); } CgiApplicationEngine::CgiApplicationEngine(const CgiEnvironment * e, std::ostream & io) : - ApplicationEngine("web/host"), _env(e), sessionsContainer(LoaderBase::getLoader<SessionContainerLoader, NotSupported>(e->sessionModule)->open()), IO(io) @@ -200,27 +198,3 @@ CgiApplicationEngine::session() const return cursession; } -bool -CgiApplicationEngine::checkDomain(const DomainPlatforms::value_type & i) const -{ - Glib::RefPtr<Glib::Regex> reg = Glib::Regex::create(i.first, Glib::REGEX_CASELESS | Glib::REGEX_DOTALL); - return reg->match(_env->getServerName()); -} - -Glib::ustring -CgiApplicationEngine::resolveCurrentConfig() const -{ - DomainPlatforms::const_iterator i = std::find_if(domplat.begin(), domplat.end(), boost::bind(&CgiApplicationEngine::checkDomain, this, _1)); - if (i != domplat.end()) { - return i->second; - } - throw UnknownDomain(_env->getServerName()); -} - -void -CgiApplicationEngine::loadEngineSection(const xmlpp::Element * e) const -{ - domplat.push_back(DomainPlatforms::value_type(e->get_attribute_value("name"), e->get_attribute_value("platform"))); -} - - diff --git a/project2/cgi/cgiAppEngine.h b/project2/cgi/cgiAppEngine.h index e837b9d..25d3b93 100644 --- a/project2/cgi/cgiAppEngine.h +++ b/project2/cgi/cgiAppEngine.h @@ -36,7 +36,6 @@ class CgiApplicationEngine : public ApplicationEngine, public TransformChainLink void process() const; const Environment * env() const; SessionPtr session() const; - virtual Glib::ustring resolveCurrentConfig() const; void addAppData(const MultiRowSetPresenter * p, OutputOptionsPtr) const; void addEnvData(const MultiRowSetPresenter * p, OutputOptionsPtr) const; const CgiEnvironment * _env; @@ -44,10 +43,6 @@ class CgiApplicationEngine : public ApplicationEngine, public TransformChainLink private: mutable boost::posix_time::ptime startTime; mutable boost::posix_time::ptime endTime; - typedef std::pair<Glib::ustring, Glib::ustring> DomainPlatform; - typedef std::list<DomainPlatform> DomainPlatforms; - mutable DomainPlatforms domplat; - bool checkDomain(const DomainPlatforms::value_type & i) const; void loadEngineSection(const xmlpp::Element *) const; SessionContainerPtr sessionsContainer; // Helpers diff --git a/project2/cgi/cgiCommon.cpp b/project2/cgi/cgiCommon.cpp index 579e3f4..3664e9f 100644 --- a/project2/cgi/cgiCommon.cpp +++ b/project2/cgi/cgiCommon.cpp @@ -34,7 +34,7 @@ doExceptionReporting(const E & e, std::ostream & IO) IO << "Kaboom!" << std::endl << std::endl << buf << std::endl - << e.what() << std::endl; + << "what '" << e.what() << "'" << std::endl; free(buf); } diff --git a/project2/cgi/cgiEnvironment.cpp b/project2/cgi/cgiEnvironment.cpp index 541e7ae..ae7ad52 100644 --- a/project2/cgi/cgiEnvironment.cpp +++ b/project2/cgi/cgiEnvironment.cpp @@ -1,9 +1,11 @@ #include <pch.hpp> +#include <boost/version.hpp> #include "cgiEnvironment.h" #include "appEngine.h" #include "exceptions.h" #include <map> #include <cgicc/Cgicc.h> +#include <glibmm/regex.h> std::vector<std::string> makeVector(const boost::filesystem::path & y) @@ -22,53 +24,56 @@ makeVector(const boost::filesystem::path & y) } CgiEnvironment::CgiEnvironment(cgicc::Cgicc * c) : - Environment(0, NULL), cgicc::CgiEnvironment(c->getEnvironment()), elems(makeVector(boost::filesystem::path(getRedirectURL()))), - cgi(c) + cgi(c), + cgiOptions("Project2 CGI options"), + hpi(new HostnamePlatformIdentifier()) { -} - -CgiEnvironment::~CgiEnvironment() -{ -} - -boost::program_options::options_description -CgiEnvironment::addOptions(boost::program_options::positional_options_description &) -{ - boost::program_options::options_description cgi("Project2 CGI options"); - cgi.add_options() - ("defaultpresenter", boost::program_options::value(&defaultPresenter)->default_value("xml"), + cgiOptions + ("cgi.defaultPresenter", Options::value(&defaultPresenter, "xml"), "The default engine for formatting presentations") - ("defaultpresent", boost::program_options::value(&defaultPresent)->default_value("index"), + ("cgi.defaultPresent", Options::value(&defaultPresent, "index"), "The present script to use when no other is specified") - ("presentroot", boost::program_options::value(&presentRoot)->default_value("present"), + ("cgi.presentRoot", Options::value(&presentRoot, "present"), "The folder in which to find presentation scripts") - ("requestroot", boost::program_options::value(&requestRoot)->default_value("request"), + ("cgi.requestRoot", Options::value(&requestRoot, "request"), "The folder in which to find request scripts") - ("errorpresentroot", boost::program_options::value(&errorPresentRoot)->default_value("error"), + ("cgi.errorPresentRoot", Options::value(&errorPresentRoot, "error"), "The folder in which to find presentation scripts for error handling") - ("errorcontenttype", boost::program_options::value(&errorContentType)->default_value("text/xml"), + ("cgi.errorContentType", Options::value(&errorContentType, "text/xml"), "The Content-Type to use in HTTP headers in event of an error") - ("errortransformstyle", boost::program_options::value(&errorTransformStyle), + ("cgi.errorTransformStyle", Options::value(&errorTransformStyle), "The xml-stylesheet to specify in the data document in event of an error") - ("notfoundpresent", boost::program_options::value(¬FoundPresent), + ("cgi.notFoundPresent", Options::value(¬FoundPresent), "The present script to use when the requested script does not exist") - ("onerrorpresent", boost::program_options::value(&onErrorPresent), + ("cgi.onErrorPresent", Options::value(&onErrorPresent), "The present script to use when the requested script (or child) fails") - ("dumpdatadoc", boost::program_options::value(&dumpdatadoc), + ("cgi.dumpDataDoc", Options::value(&dumpdatadoc), "Write a copy of the data document before sending it to the web server") - ("sessionModule", boost::program_options::value(&sessionModule)->default_value("xml"), + ("cgi.sessionModule", Options::value(&sessionModule, "xml"), "The module with which to implement session management") + ("cgi.hostRegex", hpi, + "Regular expression used to define a hostname -> platform association") ; - return cgi; } -void -CgiEnvironment::postinit(const boost::program_options::options_description &, const boost::program_options::variables_map &) +const Options & +CgiEnvironment::engineOptions() const { + return cgiOptions; +} + +CgiEnvironment::~CgiEnvironment() +{ +} + +const Glib::ustring & +CgiEnvironment::platform() const { + return hpi->derivedPlatform(); } + Glib::ustring CgiEnvironment::getParamUri(unsigned int p) const { @@ -88,3 +93,38 @@ CgiEnvironment::getParamQuery(const std::string & p) const return (*cgi)(p); } +HostnamePlatformIdentifier::HostnamePlatformIdentifier() : + platform(NULL) +{ +} + +HostnamePlatformIdentifier::~HostnamePlatformIdentifier() +{ + reset(); +} + +const Glib::ustring & +HostnamePlatformIdentifier::derivedPlatform() const +{ + if (platform) { + return *platform; + } + throw NoSuchPlatform(Environment::getCurrent()->getServerName()); +} + +void +HostnamePlatformIdentifier::reset() const +{ + if (platform) { + delete platform; + } +} + +void +HostnamePlatformIdentifier::consume(const Glib::ustring & p, const Glib::ustring & r) const +{ + if (!platform && Glib::Regex::create(r, Glib::REGEX_CASELESS | Glib::REGEX_DOTALL)->match(Environment::getCurrent()->getServerName())) { + platform = new Glib::ustring(p); + } +} + diff --git a/project2/cgi/cgiEnvironment.h b/project2/cgi/cgiEnvironment.h index fe99f5e..654f772 100644 --- a/project2/cgi/cgiEnvironment.h +++ b/project2/cgi/cgiEnvironment.h @@ -10,6 +10,17 @@ namespace cgicc { class Cgicc; } +class HostnamePlatformIdentifier : public Options::Target { + public: + HostnamePlatformIdentifier(); + virtual ~HostnamePlatformIdentifier(); + void reset() const; + void consume(const Glib::ustring &, const Glib::ustring &) const; + const Glib::ustring & derivedPlatform() const; + private: + mutable Glib::ustring * platform; +}; + class CgiEnvironment : public Environment, public cgicc::CgiEnvironment { public: CgiEnvironment(cgicc::Cgicc *); @@ -24,8 +35,11 @@ class CgiEnvironment : public Environment, public cgicc::CgiEnvironment { const cgicc::Cgicc * const cgi; private: - boost::program_options::options_description addOptions(boost::program_options::positional_options_description &); - void postinit(const boost::program_options::options_description &, const boost::program_options::variables_map &); + const Options & engineOptions() const; + const Glib::ustring & platform() const; + Options cgiOptions; + boost::intrusive_ptr<HostnamePlatformIdentifier> hpi; + public: std::string dumpdatadoc; Glib::ustring errorContentType; diff --git a/project2/cgi/cgiOutputOptions.cpp b/project2/cgi/cgiOutputOptions.cpp index eb07b25..add1671 100644 --- a/project2/cgi/cgiOutputOptions.cpp +++ b/project2/cgi/cgiOutputOptions.cpp @@ -20,13 +20,13 @@ OutputOptions::OutputOptions(const xmlpp::Element * p) : OutputOptionsLoader::OutputOptionsLoader() : opts("CGI default output options") { - opts.add_options() - ("cgi.output.core", po::value(&OutputOptions::core)->default_value(true), "Core messages") - ("cgi.output.session", po::value(&OutputOptions::core)->default_value(true), "Session values") - ("cgi.output.timing", po::value(&OutputOptions::core)->default_value(true), "Timing") - ("cgi.output.environment", po::value(&OutputOptions::core)->default_value(true), "Environment") - ("cgi.output.url", po::value(&OutputOptions::core)->default_value(true), "URL breakdown") - ("cgi.output.parameters", po::value(&OutputOptions::core)->default_value(true), "Parameters") + opts + ("cgi.output.core", Options::value(&OutputOptions::core, true), "Core messages") + ("cgi.output.session", Options::value(&OutputOptions::core, true), "Session values") + ("cgi.output.timing", Options::value(&OutputOptions::core, true), "Timing") + ("cgi.output.environment", Options::value(&OutputOptions::core, true), "Environment") + ("cgi.output.url", Options::value(&OutputOptions::core, true), "URL breakdown") + ("cgi.output.parameters", Options::value(&OutputOptions::core, true), "Parameters") ; } @@ -35,8 +35,8 @@ OutputOptionsLoader::createFrom(const xmlpp::Element * e) const { return new OutputOptions(e); } -po::options_description * -OutputOptionsLoader::options() +const Options * +OutputOptionsLoader::options() const { return &opts; } diff --git a/project2/cgi/cgiOutputOptions.h b/project2/cgi/cgiOutputOptions.h index 540764e..a1ff62d 100644 --- a/project2/cgi/cgiOutputOptions.h +++ b/project2/cgi/cgiOutputOptions.h @@ -2,7 +2,7 @@ #define OUTPUTOPTIONS_H #include "intrusivePtrBase.h" -#include <boost/program_options.hpp> +#include "options.h" #include "variables.h" namespace xmlpp { @@ -32,15 +32,14 @@ class OutputOptions : public IntrusivePtrBase { }; typedef boost::intrusive_ptr<OutputOptions> OutputOptionsPtr; -namespace po = boost::program_options; class OutputOptionsLoader : public ComponentLoader { public: OutputOptionsLoader(); OutputOptionsPtr createFrom(const xmlpp::Element * e) const; - po::options_description * options(); + const Options * options() const; private: - po::options_description opts; + Options opts; }; #endif diff --git a/project2/cgi/cgiStageFail.cpp b/project2/cgi/cgiStageFail.cpp index 97ac22a..87aba66 100644 --- a/project2/cgi/cgiStageFail.cpp +++ b/project2/cgi/cgiStageFail.cpp @@ -1,4 +1,5 @@ #include <pch.hpp> +#include <boost/lexical_cast.hpp> #include "cgiAppEngine.h" #include "cgiEnvironment.h" #include "cgiHttpHeader.h" diff --git a/project2/cgi/pch.hpp b/project2/cgi/pch.hpp index b3c7108..ff0b175 100644 --- a/project2/cgi/pch.hpp +++ b/project2/cgi/pch.hpp @@ -13,7 +13,7 @@ #include "xmlObjectLoader.h" #include <boost/bind.hpp> #include <boost/foreach.hpp> -#include <boost/program_options.hpp> +#include "options.h" #include <cgicc/CgiEnvironment.h> #include <cgicc/Cgicc.h> #include <cgicc/HTTPContentHeader.h> diff --git a/project2/cgi/testCgi.cpp b/project2/cgi/testCgi.cpp index 438e1b0..c2e8d4e 100644 --- a/project2/cgi/testCgi.cpp +++ b/project2/cgi/testCgi.cpp @@ -1,70 +1,71 @@ #include <iostream> -#include <boost/program_options.hpp> -#include <boost/filesystem/convenience.hpp> +#include <boost/bind.hpp> +#include <map> +#include "options.h" +#include "safeMapFind.h" #include "cgiCommon.h" +#include "../files/optionsSource.h" -namespace po = boost::program_options; - +#define TESTOPT(name, def, desc) \ + (name, Options::value(optStore.insert(OptStore::value_type(name, new std::string())).first->second, def), desc) class TestInput : public cgicc::CgiInput { public: - TestInput(int argc, char ** argv) + typedef std::string * StrPtr; + typedef std::map<std::string, StrPtr> OptStore; + OptStore optStore; + TestInput() : + opts("Project2 CGI test options") { - po::options_description test("Project2 CGI test options"); - test.add_options() - ("help,h", "Print usage and exit") - ("SERVER_NAME", "FQDN of web service") - ("SERVER_SOFTWARE", po::value<std::string>()->default_value("Apache"), "") - ("GATEWAY_INTERFACE", po::value<std::string>()->default_value("CGI/1.1"), "") - ("SERVER_PROTOCOL", po::value<std::string>()->default_value("HTTP/1.1"), "") - ("SERVER_PORT", po::value<std::string>()->default_value("80"), "") - ("REQUEST_METHOD", po::value<std::string>()->default_value("GET"), "") - ("PATH_INFO", "") - ("PATH_TRANSLATED", "") - ("SCRIPT_NAME", po::value<std::string>()->default_value("p2fcgi"), "") - ("QUERY_STRING", "") - ("REMOTE_HOST", "") - ("REMOTE_ADDR", "") - ("AUTH_TYPE", "") - ("REMOTE_USER", "") - ("REMOTE_IDENT", "") - ("CONTENT_TYPE", "") - ("CONTENT_LENGTH", "") - ("HTTP_ACCEPT", po::value<std::string>()->default_value("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"), "") - ("HTTP_USER_AGENT", po::value<std::string>()->default_value("Mozilla/5.0"), "") - ("REDIRECT_REQUEST", "") - ("REDIRECT_URL", "") - ("REDIRECT_STATUS", "") - ("HTTP_REFERER", "") - ("HTTP_COOKIE", "") - ("HTTPS", po::value<std::string>()->default_value("No"), "") + opts + TESTOPT("SERVER_NAME", "localhost", "FQDN of web service") + TESTOPT("SERVER_SOFTWARE", "Apache", "Web server version string") + TESTOPT("GATEWAY_INTERFACE", "CGI/1.1", "Web server/script interface version") + TESTOPT("SERVER_PROTOCOL", "HTTP/1.1", "Web server/client interface version") + TESTOPT("SERVER_PORT", "80", "Server Port") + TESTOPT("REQUEST_METHOD", "GET", "Request method") + TESTOPT("PATH_INFO", "", "Path info") + TESTOPT("PATH_TRANSLATED", "", "Path translated") + TESTOPT("SCRIPT_NAME", "p2fcgi", "Script name") + TESTOPT("QUERY_STRING", "", "Query string") + TESTOPT("REMOTE_HOST", "", "Remote host") + TESTOPT("REMOTE_ADDR", "", "Remote address") + TESTOPT("AUTH_TYPE", "", "Authentication type") + TESTOPT("REMOTE_USER", "", "Remote user") + TESTOPT("REMOTE_IDENT", "", "Remote ident") + TESTOPT("CONTENT_TYPE", "", "Content type") + TESTOPT("CONTENT_LENGTH", "", "Content length") + TESTOPT("HTTP_ACCEPT", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accepted MIME types") + TESTOPT("HTTP_USER_AGENT", "Mozilla/5.0", "User agent") + TESTOPT("REDIRECT_REQUEST", "", "Redirect request") + TESTOPT("REDIRECT_URL", "", "Redirect URL") + TESTOPT("REDIRECT_STATUS", "", "Redirect status") + TESTOPT("HTTP_REFERER", "", "Referrer") + TESTOPT("HTTP_COOKIE", "", "Cookie") + TESTOPT("HTTPS", "No", "HTTPS?") ; - po::parsed_options parsed = po::command_line_parser(argc, argv).options(test).allow_unregistered().run(); - po::store(parsed, settings); - if (boost::filesystem::exists("testCgi.settings")) { - std::ifstream f("testCgi.settings"); - po::store(po::parse_config_file(f, test, true), settings); - } - po::notify(settings); - if (settings.count("help")) { - std::cout << test; - exit(1); - } + FileOptions fo(".testCgi.settings"); + opts.reset(); + fo.loadInto(boost::bind(&Options::consume, &opts, _1, _2, _3)); + } + + const Options * options() const { + return &opts; } - virtual std::string getenv(const char *varName) + + virtual std::string getenv(const char * varName) { - if (settings.count(varName)) { - return settings[varName].as<std::string>(); - } - return ""; + StrPtr def(new std::string()); + return *defaultMapFind(optStore, varName, def); } + private: - po::variables_map settings; + Options opts; }; int -main(int argc, char ** argv) +main(int, char **) { - TestInput ti(argc, argv); + TestInput ti; cgiServe(&ti, std::cout); } diff --git a/project2/common/Jamfile.jam b/project2/common/Jamfile.jam index f08a2ff..4964ea1 100644 --- a/project2/common/Jamfile.jam +++ b/project2/common/Jamfile.jam @@ -5,7 +5,6 @@ lib dl : : <name>dl ; lib boost_system : : <name>boost_system ; lib boost_filesystem : : <name>boost_filesystem ; lib boost_date_time : : <name>boost_date_time ; -lib boost_program_options : : <name>boost_program_options ; cpp-pch pch : pch.hpp : <include>../../libmisc @@ -24,12 +23,10 @@ lib p2common : <library>boost_system <library>boost_filesystem <library>boost_date_time - <library>boost_program_options <library>../uuid//p2uuid : : <include>. <include>../../libmisc <library>boost_system - <library>boost_program_options ; diff --git a/project2/common/appEngine.cpp b/project2/common/appEngine.cpp index 245f4e5..db44a94 100644 --- a/project2/common/appEngine.cpp +++ b/project2/common/appEngine.cpp @@ -7,8 +7,7 @@ ApplicationEngine * ApplicationEngine::currentEngine = NULL; -ApplicationEngine::ApplicationEngine(const Glib::ustring & engineKeys) : - Configuration(engineKeys) +ApplicationEngine::ApplicationEngine() { if (currentEngine) { throw std::runtime_error("One application at a time, please"); diff --git a/project2/common/appEngine.h b/project2/common/appEngine.h index 85e7229..6de21e1 100644 --- a/project2/common/appEngine.h +++ b/project2/common/appEngine.h @@ -3,11 +3,10 @@ #include "environment.h" #include "session.h" -#include "config.h" class MultiRowSetPresenter; -class ApplicationEngine : public Configuration { +class ApplicationEngine { public: class Message : public IntrusivePtrBase { public: @@ -19,7 +18,7 @@ class ApplicationEngine : public Configuration { typedef boost::intrusive_ptr<Message> MessagePtr; typedef std::list<MessagePtr> Messages; - ApplicationEngine(const Glib::ustring & engineKeys); + ApplicationEngine(); virtual ~ApplicationEngine() = 0; void logMessage(bool writeLog, const Glib::ustring & g, const Glib::ustring & m); diff --git a/project2/common/config.cpp b/project2/common/config.cpp deleted file mode 100644 index cb316e5..0000000 --- a/project2/common/config.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include <pch.hpp> -#include "config.h" -#include "safeMapFind.h" -#include "exceptions.h" -#include <boost/filesystem/operations.hpp> -#include <boost/foreach.hpp> -#include "xmlScriptParser.h" - -SimpleMessageException(NoSuchPlatform); -SimpleMessageException(NoSuchConfigurationValue); - -Configuration::Configuration(const Glib::ustring & ek) : - loaded(false), - engineKeys(ek) -{ -} - -void -Configuration::load() const -{ - if (loaded) { - return; - } - loaded = true; - if (!boost::filesystem::exists("config.xml")) { - return; - } - XmlScriptParser configxml("config.xml", true); - xmlpp::NodeSet ps(configxml.get_document()->get_root_node()->find("platform")); - BOOST_FOREACH(const xmlpp::Node * p, ps) { - const xmlpp::Element * pe = dynamic_cast<const xmlpp::Element *>(p); - if (pe) { - platforms[pe->get_attribute_value("name")] = new Platform(pe); - } - } - xmlpp::NodeSet eks(configxml.get_document()->get_root_node()->find(engineKeys)); - BOOST_FOREACH(const xmlpp::Node * ek, eks) { - const xmlpp::Element * eke = dynamic_cast<const xmlpp::Element *>(ek); - if (eke) { - loadEngineSection(eke); - } - } -} - -Configuration::~Configuration() -{ -} - -Configuration::PlatformPtr -Configuration::getCurrentConfig() const -{ - load(); - Glib::ustring platformName(resolveCurrentConfig()); - return safeMapLookup<NoSuchPlatform>(platforms, platformName); -} - -const Glib::ustring & -Configuration::Platform::getValue(const Glib::ustring & key) const -{ - return safeMapLookup<NoSuchConfigurationValue>(values, key); -} - -Configuration::Platform::Platform(const xmlpp::Element * e) -{ - xmlpp::NodeSet vs(e->find("variable")); - BOOST_FOREACH(const xmlpp::Node * v, vs) { - const xmlpp::Element * ve = dynamic_cast<const xmlpp::Element *>(v); - if (ve) { - values.insert(Values::value_type(ve->get_attribute_value("name"), ve->get_attribute_value("value"))); - } - } -} - diff --git a/project2/common/config.h b/project2/common/config.h deleted file mode 100644 index 9f6cd5d..0000000 --- a/project2/common/config.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef CONFIG_H -#define CONFIG_H - -#include <string> -#include <libxml++/nodes/element.h> -#include "intrusivePtrBase.h" -#include <boost/function.hpp> - -class Configuration { - public: - class Platform : public virtual IntrusivePtrBase { - public: - typedef std::map<Glib::ustring, const Glib::ustring> Values; - - Platform(const xmlpp::Element * instanceRoot); - const Glib::ustring & getValue(const Glib::ustring & key) const; - - private: - Values values; - }; - typedef boost::intrusive_ptr<const Platform> PlatformPtr; - - typedef std::map<Glib::ustring, PlatformPtr> Platforms; - - Configuration(const Glib::ustring & engineKeys); - virtual ~Configuration() = 0; - - PlatformPtr getCurrentConfig() const; - - protected: - virtual Glib::ustring resolveCurrentConfig() const = 0; - void load() const; - - private: - virtual void loadEngineSection(const xmlpp::Element *) const = 0; - - mutable bool loaded; - mutable Platforms platforms; - const Glib::ustring engineKeys; -}; - -#endif - diff --git a/project2/common/environment.cpp b/project2/common/environment.cpp index 3106e9a..18d60a0 100644 --- a/project2/common/environment.cpp +++ b/project2/common/environment.cpp @@ -1,5 +1,6 @@ #include <pch.hpp> #include "environment.h" +#include "optionsSource.h" #include "loggers.h" #include "xmlObjectLoader.h" #include <stdio.h> @@ -8,73 +9,66 @@ #include <boost/foreach.hpp> #include <boost/bind.hpp> -namespace po = boost::program_options; - const Environment * Environment::currentEnv(NULL); int Environment::clLevel(-1); int Environment::slLevel(-1); -bool Environment::optionsBuilt(false); -po::options_description Environment::allOptions("Project2 options"); -po::positional_options_description Environment::posOptions; -Environment::Environment(int c, char ** v) : - argc(c), - argv(v) +Environment::Environment() : + commonOptions("Project2 Common options") { currentEnv = this; + commonOptions + ("common.syslogLevel", Options::value(&slLevel, -1), + "Log to syslog with level <arg> (default OFF)")("s") + ("common.consolelogLevel", Options::value(&clLevel, LOG_WARNING), + "Log to console with level <arg> (default WARNING)")("c") + ("common.datasourceRoot", Options::value(&datasourceRoot, "datasources"), + "The folder in which to find datasource definitions") + ("common.namespace", Options::value(&xmlNamespace, "http://project2.randomdan.homeip.net"), + "The namespace to use for Project2 components and responses") + ("common.namespacePrefix", Options::value(&xmlPrefix, "project2"), + "The namespace prefix to use for the Project2 namespace") + ("common.sessionTimeOut", Options::value(&sessionTimeOut, 3600), + "The time after which idle sessions are forgetten") + ; } +typedef std::vector<const Options *> AllOptions; + static -po::variables_map -injectSettingsHelper(int argc, char ** argv, const po::options_description * opts, po::positional_options_description * posOpts) +void +optionsHelper(AllOptions * ao, const Options * options) { - po::variables_map settings; - if (!opts) { - return settings; - } - if (argc > 0 && argv != NULL) { - if (posOpts) { - po::store(po::command_line_parser(argc, argv).options(*opts).positional(*posOpts).allow_unregistered().run(), settings); - } - else { - po::store(po::command_line_parser(argc, argv).options(*opts).allow_unregistered().run(), settings); - } + if (options) { + ao->push_back(options); } - po::store(po::parse_environment(*opts, "P2_"), settings); - if (boost::filesystem::exists(".p2config")) { - std::ifstream f(".p2config"); - po::store(po::parse_config_file(f, *opts, true), settings); +} + +static +void +consumeIntoAll(const AllOptions * ao, const Glib::ustring & n, const Glib::ustring & p, const Glib::ustring & v) +{ + BOOST_FOREACH(const Options * o, *ao) { + o->consume(n, p, v); } - po::notify(settings); - return settings; } void Environment::init() { - if (!optionsBuilt) { - po::options_description common("Project2 Common options"); - common.add_options() - ("sysloglevel,s", po::value(&slLevel)->default_value(-1), - "Log to syslog with level <arg> (default OFF)") - ("consoleloglevel,c", po::value(&clLevel)->default_value(LOG_WARNING), - "Log to console with level <arg> (default WARNING)") - ("datasourceroot", boost::program_options::value(&datasourceRoot)->default_value("datasources"), - "The folder in which to find datasource definitions") - ("xmlnamespace", boost::program_options::value(&xmlNamespace)->default_value("http://project2.randomdan.homeip.net"), - "The XML namespace to use for Project2 components and responses") - ("xmlprefix", boost::program_options::value(&xmlPrefix)->default_value("project2"), - "The XML namespace prefix to use for the Project2 XML namespace") - ("sessionTimeOut", boost::program_options::value(&sessionTimeOut)->default_value(3600), - "The time after which idle sessions are forgetten") - ; - allOptions.add(common).add(addOptions(posOptions)); - optionsBuilt = true; + AllOptions allOptions; + allOptions.push_back(&commonOptions); + allOptions.push_back(&engineOptions()); + LoaderBase::onAllComponents(boost::bind(optionsHelper, &allOptions, boost::bind(&ComponentLoader::options, _1))); + + BOOST_FOREACH(const AllOptions::value_type & v, allOptions) { + v->reset(); + } + + typedef std::map<std::string, boost::shared_ptr<OptionsSourceLoader> > ConfigParsersMap; + BOOST_FOREACH(const ConfigParsersMap::value_type & cp, *LoaderBase::objLoaders<OptionsSourceLoader>()) { + cp.second->create()->loadInto(boost::bind(&consumeIntoAll, &allOptions, _1, _2, _3)); } - po::variables_map settings(injectSettingsHelper(argc, argv, &allOptions, &posOptions)); - postinit(allOptions, settings); - LoaderBase::onAllComponents(boost::bind( - injectSettingsHelper, argc, argv, boost::bind(&ComponentLoader::options, _1), (po::positional_options_description*)NULL)); Logger()->clear(); if (clLevel >= 0) { diff --git a/project2/common/environment.h b/project2/common/environment.h index 367d800..6185178 100644 --- a/project2/common/environment.h +++ b/project2/common/environment.h @@ -3,13 +3,16 @@ #include <string> #include <glibmm/ustring.h> -#include <boost/program_options.hpp> #include <boost/function.hpp> #include <boost/filesystem/path.hpp> +#include "options.h" +#include "exceptions.h" + +SimpleMessageException(NoSuchPlatform); class Environment { public: - Environment(int argc, char ** argv); + Environment(); virtual ~Environment() = 0; void init(); @@ -21,20 +24,15 @@ class Environment { virtual std::string getServerName() const = 0; virtual std::string getScriptName() const = 0; + virtual const Glib::ustring & platform() const = 0; boost::filesystem::path resolveScript(const std::string & group, const std::string & name) const; private: - static const Environment * currentEnv; + Options commonOptions; + virtual const Options & engineOptions() const = 0; - virtual boost::program_options::options_description addOptions(boost::program_options::positional_options_description &) = 0; - virtual void postinit(const boost::program_options::options_description &, const boost::program_options::variables_map &) = 0; - int argc; - char ** argv; - - static bool optionsBuilt; - static boost::program_options::options_description allOptions; - static boost::program_options::positional_options_description posOptions; + static const Environment * currentEnv; static int clLevel; static int slLevel; diff --git a/project2/common/memoryCache.cpp b/project2/common/memoryCache.cpp index 34d2cf9..5942cb8 100644 --- a/project2/common/memoryCache.cpp +++ b/project2/common/memoryCache.cpp @@ -2,7 +2,7 @@ #include "logger.h" #include "cache.h" #include <boost/foreach.hpp> -#include <boost/program_options.hpp> +#include "options.h" #include "rowSet.h" #include "presenter.h" #include "safeMapFind.h" @@ -145,19 +145,18 @@ class MemoryCache : public Cache { time_t MemoryCache::CacheLife; MemoryCache::CacheStore MemoryCache::Store; -namespace po = boost::program_options; class CustomMemoryCacheLoader : public ElementLoaderImpl<MemoryCache> { public: CustomMemoryCacheLoader() : opts("Memory Cache options") { - opts.add_options() - ("cache.memory.life", po::value(&MemoryCache::CacheLife)->default_value(3600), + opts + ("cache.memory.life", Options::value(&MemoryCache::CacheLife, 3600), "The age of cache entries after which they are removed (seconds)") ; } - po::options_description * options() { + const Options * options() const { return &opts; } @@ -169,7 +168,7 @@ class CustomMemoryCacheLoader : public ElementLoaderImpl<MemoryCache> { } private: - po::options_description opts; + Options opts; }; DECLARE_CUSTOM_LOADER("memorycache", CustomMemoryCacheLoader); diff --git a/project2/common/options.cpp b/project2/common/options.cpp new file mode 100644 index 0000000..a99c78e --- /dev/null +++ b/project2/common/options.cpp @@ -0,0 +1,110 @@ +#include <pch.hpp> +#include "options.h" +#include "environment.h" +#include <boost/foreach.hpp> + +class NamedOption : public Options::Option { + public: + NamedOption(Glib::ustring const & n, Options::TargetPtr t, Glib::ustring const & d) : + name(n), + target(t), + desc(d) + { + } + void consume(const Glib::ustring & n, const Glib::ustring & p, const Glib::ustring & v) const { + if (n == name) { + target->consume(p, v); + } + } + void reset() const { + target->reset(); + } + + const Glib::ustring name; + const Options::TargetPtr target; + const Glib::ustring desc; +}; + +class OptionAlias : public Options::Option { + public: + OptionAlias(const Glib::ustring & a, Options::TargetPtr t) : + alias(a), + target(t) + { + } + void consume(const Glib::ustring & a, const Glib::ustring & p, const Glib::ustring & v) const { + if (a == alias) { + target->consume(p, v); + } + } + void reset() const { + target->reset(); + } + const Glib::ustring alias; + const Options::TargetPtr target; +}; + +Options::Options(Glib::ustring const&) +{ +} + +Options & +Options::operator()(const Glib::ustring & n, TargetPtr t, const Glib::ustring & d) +{ + options.push_back(new NamedOption(n, t, d)); + return *this; +} + +Options & +Options::operator()(const Glib::ustring & a) +{ + for (OptionList::const_reverse_iterator i = options.rbegin(); i != options.rend(); i++) { + if (const NamedOption * no = dynamic_cast<const NamedOption *>(i->get())) { + options.push_back(new OptionAlias(a, no->target)); + break; + } + } + return *this; +} + +Options & +Options::operator()(OptionPtr o) +{ + options.push_back(o); + return *this; +} + +void +Options::reset() const +{ + BOOST_FOREACH(const OptionPtr & o, options) { + o->reset(); + } +} + +void +Options::consume(const Glib::ustring & n, const Glib::ustring & p, const Glib::ustring & v) const +{ + BOOST_FOREACH(const OptionPtr & o, options) { + o->consume(n, p, v); + } +} + +Options::InstanceTarget::InstanceTarget() : + ts(Default) +{ +} + +void +Options::InstanceTarget::consume(const Glib::ustring & p, const Glib::ustring & v) const +{ + if (ts != Platform && p.empty()) { + assign(v); + ts = Global; + } + else if (!p.empty() && p == Environment::getCurrent()->platform()) { + assign(v); + ts = Platform; + } +} + diff --git a/project2/common/options.h b/project2/common/options.h new file mode 100644 index 0000000..77c71b5 --- /dev/null +++ b/project2/common/options.h @@ -0,0 +1,110 @@ +#ifndef OPTIONS_H +#define OPTIONS_H + +#include <glibmm/ustring.h> +#include <intrusivePtrBase.h> +#include <vector> +#include <list> +#include <boost/lexical_cast.hpp> + +class Options { + public: + class Target; + template <typename T> class TypedTarget; + + enum TargetState { Default = 1, Global = 2, Platform = 3 }; + class Target : public IntrusivePtrBase { + public: + virtual void reset() const = 0; + virtual void consume(const Glib::ustring & platform, const Glib::ustring & value) const = 0; + }; + typedef boost::intrusive_ptr<Target> TargetPtr; + + class InstanceTarget : public Target { + public: + InstanceTarget(); + void consume(const Glib::ustring & platform, const Glib::ustring & value) const; + protected: + virtual void assign(const Glib::ustring & value) const = 0; + mutable TargetState ts; + }; + + template <typename T> class TypedTarget : public InstanceTarget { + public: + TypedTarget(T * t) : + target(t) { + } + void reset() const { + ts = Default; + *target = T(); + } + void assign(const Glib::ustring & value) const { + *target = boost::lexical_cast<T>(value); + } + protected: + T * target; + }; + + template <typename T> class TypedTarget<std::vector<T> > : public InstanceTarget { + public: + typedef std::vector<T> VofT; + TypedTarget(VofT * t) : + target(t) { + } + void reset() const { + ts = Default; + target->clear(); + } + void assign(const Glib::ustring & value) const { + target->push_back(boost::lexical_cast<T>(value)); + } + protected: + VofT * target; + }; + + template <typename T> class DefaultTypedTarget : public TypedTarget<T> { + public: + DefaultTypedTarget(T * t, const T & d) : + TypedTarget<T>(t), + defValue(d) { + } + void reset() const { + InstanceTarget::ts = Default; + *TypedTarget<T>::target = defValue; + } + private: + T defValue; + }; + + class Option : public IntrusivePtrBase { + public: + virtual void reset() const = 0; + virtual void consume(const Glib::ustring & name, const Glib::ustring & platform, const Glib::ustring & value) const = 0; + }; + typedef boost::intrusive_ptr<Option> OptionPtr; + + Options(const Glib::ustring & name); + + Options & operator()(const Glib::ustring & optionName, TargetPtr target, const Glib::ustring & description); + Options & operator()(const Glib::ustring & optionName); + Options & operator()(OptionPtr); + template <typename T> + static + TargetPtr value(T * t) { + return new TypedTarget<T>(t); + } + template <typename T, typename D> + static + TargetPtr value(T * t, const D & d) { + return new DefaultTypedTarget<T>(t, d); + } + + void reset() const; + void consume(const Glib::ustring & name, const Glib::ustring & platform, const Glib::ustring & value) const; + private: + typedef std::list<OptionPtr> OptionList; + OptionList options; +}; + +#endif + diff --git a/project2/common/optionsSource.h b/project2/common/optionsSource.h new file mode 100644 index 0000000..73335d8 --- /dev/null +++ b/project2/common/optionsSource.h @@ -0,0 +1,35 @@ +#ifndef OPTIONSSOURCE_H +#define OPTIONSSOURCE_H + +#include <boost/function.hpp> +#include <glibmm/ustring.h> +#include <intrusivePtrBase.h> +#include "xmlObjectLoader.h" + +typedef boost::function3<void, const Glib::ustring &, const Glib::ustring &, const Glib::ustring &> ConfigConsumer; + +/// Base class of things that load options +class OptionsSource : public IntrusivePtrBase { + public: + virtual void loadInto(const ConfigConsumer &) const = 0; +}; +typedef boost::intrusive_ptr<OptionsSource> OptionsSourcePtr; + +/// Base class to implement presenter modules +class OptionsSourceLoader : public ComponentLoader { + public: + virtual OptionsSourcePtr create() const = 0; +}; + +/// Helper implemention for specific presenters +template <class OptionsSourceType> +class OptionsSourceLoaderImpl : public OptionsSourceLoader { + public: + virtual OptionsSourcePtr create() const + { + return new OptionsSourceType(); + } +}; + +#endif + diff --git a/project2/common/pch.hpp b/project2/common/pch.hpp index 708b437..536dc5a 100644 --- a/project2/common/pch.hpp +++ b/project2/common/pch.hpp @@ -8,7 +8,7 @@ #include <boost/foreach.hpp> #include <boost/function.hpp> #include <boost/intrusive_ptr.hpp> -#include <boost/program_options.hpp> +#include "options.h" #include <boost/shared_ptr.hpp> #include <boost/variant.hpp> #include <glibmm/ustring.h> diff --git a/project2/common/variables-modconfig.cpp b/project2/common/variables-modconfig.cpp index c9a6b2c..c44daf2 100644 --- a/project2/common/variables-modconfig.cpp +++ b/project2/common/variables-modconfig.cpp @@ -2,8 +2,14 @@ #include "variables.h" #include "xmlObjectLoader.h" #include "xmlStorage.h" +#include <boost/algorithm/string/predicate.hpp> #include "appEngine.h" +typedef std::map<Glib::ustring, Glib::ustring> ConfigOptions; +static ConfigOptions cfgOpts; + +SimpleMessageException(NoSuchConfigurationValue); + /// Variable implementation to access platform configuration values class VariableConfig : public VariableImplDyn { public: @@ -14,10 +20,56 @@ class VariableConfig : public VariableImplDyn { } VariableType value() const { - return ApplicationEngine::getCurrent()->getCurrentConfig()->getValue(name); + const ConfigOptions::const_iterator i = cfgOpts.find(name); + if (i != cfgOpts.end()) { + return i->second; + } + if (defaultValue) { + return defaultValue.get()(); + } + throw NoSuchConfigurationValue(name); } private: const Glib::ustring name; }; -DECLARE_COMPONENT_LOADER("config", VariableConfig, VariableLoader); + +class VariableConfigLoader : public VariableLoaderImpl<VariableConfig> { + public: + class AppSettings : public Options::Option { + public: + void reset() const { + cfgOpts.clear(); + } + void consume(const Glib::ustring & n, const Glib::ustring & p, const Glib::ustring & v) const { + if (boost::algorithm::starts_with(n, "application.")) { + Glib::ustring k(n.substr(12)); + const ConfigOptions::iterator i = cfgOpts.find(k); + if (i == cfgOpts.end()) { + if (p.empty() || p == Environment::getCurrent()->platform()) { + cfgOpts.insert(ConfigOptions::value_type(k, v)); + } + } + else { + if (p == Environment::getCurrent()->platform()) { + i->second = v; + } + } + } + } + }; + VariableConfigLoader() : + opts("Variables - ModConfig options") + { + opts(new AppSettings()); + } + + const Options * options() const { + return &opts; + } + + private: + Options opts; +}; + +DECLARE_CUSTOM_COMPONENT_LOADER("config", VariableConfigLoader, VariableConfigLoader, VariableLoader); diff --git a/project2/common/xmlObjectLoader.cpp b/project2/common/xmlObjectLoader.cpp index 81cab9e..d430194 100644 --- a/project2/common/xmlObjectLoader.cpp +++ b/project2/common/xmlObjectLoader.cpp @@ -158,8 +158,8 @@ ComponentLoader::onPeriodic() { } -boost::program_options::options_description * -ComponentLoader::options() +const Options * +ComponentLoader::options() const { return NULL; } diff --git a/project2/common/xmlObjectLoader.h b/project2/common/xmlObjectLoader.h index 0552a9e..3c6fa34 100644 --- a/project2/common/xmlObjectLoader.h +++ b/project2/common/xmlObjectLoader.h @@ -108,7 +108,7 @@ class LoaderBase { DECLARE_COMPONENT_LOADER(N, T, ElementLoader) /// Helper for loading and maintaining Project2 components -namespace boost { namespace program_options { class options_description; } } +class Options; class ComponentLoader { public: virtual void onBegin(); // App engine start up (before settings are processed) @@ -116,8 +116,7 @@ class ComponentLoader { virtual void onIdle(); // When the app engine goes idle virtual void onIteration(); // When the app engine has completed an iteration virtual void onPeriodic(); // When the app engine feels like it - virtual boost::program_options::options_description * - options(); // Options to be populated from the common config file/env/etc + virtual const Options * options() const; // Options to be populated from the common config file/env/etc }; /// Helper for loading and maintaining Project2 script components class ElementLoader : public ComponentLoader { diff --git a/project2/console/claOptions.cpp b/project2/console/claOptions.cpp new file mode 100644 index 0000000..135eebc --- /dev/null +++ b/project2/console/claOptions.cpp @@ -0,0 +1,61 @@ +#include <pch.hpp> +#include <boost/foreach.hpp> +#include "../common/optionsSource.h" +#include "consoleEnvironment.h" + +class CommandLineArguments : public OptionsSource { + public: + typedef std::list<Glib::ustring> optionList; + void loadInto(const ConfigConsumer & consume) const { + int argc = ConsoleEnvironment::argc; + char ** argv = ConsoleEnvironment::argv; + bool moreopts = true; + optionList opts, values; + + for (int x = 1; x < argc; x += 1) { + if (moreopts && strcmp(argv[x], "--") == 0) { + moreopts = false; + } + else if (moreopts && strncmp(argv[x], "--", 2) == 0) { + opts.push_back(argv[x] + 2); + } + else if (moreopts && *(argv[x]) == '-') { + const char * o = argv[x] + 1; + while (*o) { + opts.push_back(Glib::ustring(1, *o)); + o += 1; + } + } + else { + values.push_back(argv[x]); + } + } + + BOOST_FOREACH (const optionList::value_type & i, opts) { + Glib::ustring name, plat; + Glib::ustring::size_type sl = i.find('/'); + if (sl != (Glib::ustring::size_type)-1) { + name = i.substr(0, sl); + plat = i.substr(sl + 1); + } + else { + name = i; + } + if (values.size()) { + consume(name, plat, values.front()); + values.pop_front(); + } + else { + consume(name, plat, Glib::ustring()); + } + } + + BOOST_FOREACH (const optionList::value_type & i, values) { + ConsoleEnvironment::todolist.push_back(i.raw()); + } + } +}; + +// A... process first :) +DECLARE_COMPONENT_LOADER("A_commandLineArguments", CommandLineArguments, OptionsSourceLoader) + diff --git a/project2/console/consoleAppEngine.cpp b/project2/console/consoleAppEngine.cpp index 83ab311..40d369e 100644 --- a/project2/console/consoleAppEngine.cpp +++ b/project2/console/consoleAppEngine.cpp @@ -16,7 +16,6 @@ ConsoleApplicationEngine::ConsoleApplicationEngine(const ConsoleEnvironment * en XmlScriptParser(f, false), SourceObject(get_document()->get_root_node()), CheckHost(f), - ApplicationEngine("console/environment"), TaskHost(f), ViewHost(f), _env(env), @@ -77,12 +76,6 @@ ConsoleApplicationEngine::addAppData(const MultiRowSetPresenter *) const { } -Glib::ustring -ConsoleApplicationEngine::resolveCurrentConfig() const -{ - return safeMapLookup<UnknownPlatformAlias>(conplat, _env->getPlatform()); -} - void ConsoleApplicationEngine::loadEngineSection(const xmlpp::Element * e) const { diff --git a/project2/console/consoleAppEngine.h b/project2/console/consoleAppEngine.h index 681f4a9..f2a0519 100644 --- a/project2/console/consoleAppEngine.h +++ b/project2/console/consoleAppEngine.h @@ -22,7 +22,6 @@ class ConsoleApplicationEngine : public ApplicationEngine, TaskHost, ViewHost { void process() const; const Environment * env() const; SessionPtr session() const; - virtual Glib::ustring resolveCurrentConfig() const; virtual void addAppData(const MultiRowSetPresenter * p) const; virtual void addEnvData(const MultiRowSetPresenter * p) const; diff --git a/project2/console/consoleEnvironment.cpp b/project2/console/consoleEnvironment.cpp index fa2748e..6c407b3 100644 --- a/project2/console/consoleEnvironment.cpp +++ b/project2/console/consoleEnvironment.cpp @@ -10,10 +10,12 @@ #include <iostream> #include <string> #include <boost/algorithm/string/predicate.hpp> -#include <boost/program_options.hpp> +#include "options.h" #include <boost/bind.hpp> -namespace po = boost::program_options; +int ConsoleEnvironment::argc; +char ** ConsoleEnvironment::argv; +ConsoleEnvironment::ToDoList ConsoleEnvironment::todolist; template<typename _CharT, typename _Traits> std::basic_istream<_CharT, _Traits> & @@ -24,53 +26,37 @@ operator>>(std::basic_istream<_CharT, _Traits> & s, ConsoleEnvironment::QueryPar return s; } -ConsoleEnvironment::ConsoleEnvironment(int argc, char ** argv) : - Environment(argc, argv) -{ -} - -ConsoleEnvironment::~ConsoleEnvironment() -{ -} +class ShowHelpTrigger : public Options::Target { + public: + void reset() const { } + void consume(const Glib::ustring &, const Glib::ustring &) const { + fprintf(stdout, "Help\n"); + exit(1); + } +}; -boost::program_options::options_description -ConsoleEnvironment::addOptions(boost::program_options::positional_options_description & poptions) +ConsoleEnvironment::ConsoleEnvironment(int c, char ** v) : + consoleOptions("Project2 Console options"), + help(false) { - boost::program_options::options_description console("Project2 Console options"); - console.add_options() - //("version,v", "Print version and exit") - ("help,h", "Print usage and exit") - ("syslogident,i", po::value(&scriptname)->default_value(scriptname), "Log to syslog with ident <arg>") - ("platform,p", po::value(&platform), "Platform") - ("queryparam,q", po::value(&queryParams), "Query parameter") - ("uriparam,u", po::value(&uriParams), "URL paramater") - ("file,f", po::value(&todolist), "File to process") + argc = c; + argv = v; + consoleOptions + ("help", new ShowHelpTrigger(), "Print usage and exit")("h") + ("console.syslogIdent", Options::value(&scriptname, scriptname), "Log to syslog with ident <arg>") + ("console.platform", Options::value(&reqPlatform), "Platform")("p") + ("console.queryParam", Options::value(&queryParams), "Query parameter")("q") + ("console.uriParam", Options::value(&uriParams), "URL paramater")("u") ; - poptions.add("file", -1); - return console; } -static -void -showHelpHelper(const boost::program_options::options_description * options) -{ - if (options) { - std::cout << *options << std::endl; - } +const Options & +ConsoleEnvironment::engineOptions() const { + return consoleOptions; } -void -ConsoleEnvironment::postinit(const boost::program_options::options_description & options, const boost::program_options::variables_map & settings) +ConsoleEnvironment::~ConsoleEnvironment() { - if (settings.count("version")) { - //show_version(version); - exit(1); - } - if (settings.count("help")) { - showHelpHelper(&options); - LoaderBase::onAllComponents(boost::bind(showHelpHelper, boost::bind(&ComponentLoader::options, _1))); - exit(1); - } } Glib::ustring @@ -94,10 +80,10 @@ ConsoleEnvironment::getParamQuery(const std::string & p) const throw ParamNotFound(p); } -const std::string & -ConsoleEnvironment::getPlatform() const +const Glib::ustring & +ConsoleEnvironment::platform() const { - return platform; + return reqPlatform; } std::string diff --git a/project2/console/consoleEnvironment.h b/project2/console/consoleEnvironment.h index 363090d..5f4545c 100644 --- a/project2/console/consoleEnvironment.h +++ b/project2/console/consoleEnvironment.h @@ -20,17 +20,22 @@ class ConsoleEnvironment : public Environment { Glib::ustring getParamQuery(const std::string & idx) const; std::string getServerName() const; std::string getScriptName() const; - const std::string & getPlatform() const; const ToDoList & todoList() const; private: - boost::program_options::options_description addOptions(boost::program_options::positional_options_description &); - void postinit(const boost::program_options::options_description &, const boost::program_options::variables_map &); + const Options & engineOptions() const; + const Glib::ustring & platform() const; + + friend class CommandLineArguments; + static int argc; + static char ** argv; + Options consoleOptions; + bool help; std::string scriptname; - std::string platform; + Glib::ustring reqPlatform; QueryParams queryParams; UriParams uriParams; - ToDoList todolist; + static ToDoList todolist; }; #endif diff --git a/project2/console/pch.hpp b/project2/console/pch.hpp index 39cc465..6e6ee96 100644 --- a/project2/console/pch.hpp +++ b/project2/console/pch.hpp @@ -11,7 +11,7 @@ #include "xmlObjectLoader.h" #include <boost/bind.hpp> #include <boost/foreach.hpp> -#include <boost/program_options.hpp> +#include "options.h" #include <iostream> #include <string> diff --git a/project2/files/Jamfile.jam b/project2/files/Jamfile.jam index ec1e19e..1b34e3c 100644 --- a/project2/files/Jamfile.jam +++ b/project2/files/Jamfile.jam @@ -5,9 +5,7 @@ lib boost_system : : <name>boost_system ; lib boost_filesystem : : <name>boost_filesystem ; lib p2files : - fsRows.cpp - fileRows.cpp - streamRows.cpp + [ glob *.cpp ] : <include>../libmisc <library>libxmlpp diff --git a/project2/files/optionsSource.cpp b/project2/files/optionsSource.cpp new file mode 100644 index 0000000..95c2a57 --- /dev/null +++ b/project2/files/optionsSource.cpp @@ -0,0 +1,62 @@ +#include "optionsSource.h" +#include <glibmm/iochannel.h> +#include <glibmm/fileutils.h> +#include <boost/algorithm/string/trim.hpp> + +FileOptions::FileOptions() : + file(".p2config") +{ +} + +FileOptions::FileOptions(const Glib::ustring & f) : + file(f) +{ +} + +void +FileOptions::loadInto(const ConfigConsumer & consume) const { + try { + Glib::RefPtr<Glib::IOChannel> cfg = Glib::IOChannel::create_from_file(file, "r"); + Glib::ustring line; + Glib::ustring prefix; + while (cfg->read_line(line) != Glib::IO_STATUS_EOF) { + switch (line[0]) { + case '#': + continue; + case '[': + prefix = line.substr(1, line.find(']', 2) - 1); + boost::algorithm::trim_if(prefix, Glib::Unicode::isspace); + if (!prefix.empty()) { + prefix += '.'; + } + break; + default: + Glib::ustring name, plat; + Glib::ustring::size_type eq = line.find('='); + Glib::ustring::size_type sl = line.find('/'); + if (sl < eq && sl != (Glib::ustring::size_type)-1) { + name = line.substr(0, sl); + plat = line.substr(sl + 1, eq - sl - 1); + } + else { + name = line.substr(0, eq); + } + boost::algorithm::trim_if(name, Glib::Unicode::isspace); + if (name.empty()) { + continue; + } + Glib::ustring val = line.substr(eq + 1); + boost::algorithm::trim_if(plat, Glib::Unicode::isspace); + boost::algorithm::trim_if(val, Glib::Unicode::isspace); + consume(prefix + name, plat, val); + break; + } + } + } + catch (const Glib::FileError &) { + } +} + +// Z... process last :) +DECLARE_COMPONENT_LOADER("Z_configfile", FileOptions, OptionsSourceLoader) + diff --git a/project2/files/optionsSource.h b/project2/files/optionsSource.h new file mode 100644 index 0000000..722d7b9 --- /dev/null +++ b/project2/files/optionsSource.h @@ -0,0 +1,17 @@ +#ifndef FILES_OPTIONSSOURCE_H +#define FILES_OPTIONSSOURCE_H + +#include "../common/optionsSource.h" + +class FileOptions : public OptionsSource { + public: + FileOptions(); + FileOptions(const Glib::ustring & file); + + void loadInto(const ConfigConsumer & consume) const; + private: + const Glib::ustring file; +}; + +#endif + diff --git a/project2/json/couchSession.cpp b/project2/json/couchSession.cpp index 1f6c444..8a4436b 100644 --- a/project2/json/couchSession.cpp +++ b/project2/json/couchSession.cpp @@ -11,7 +11,7 @@ #include "json.h" #include "safeMapFind.h" #include "conversion.h" -#include <boost/program_options.hpp> +#include "options.h" class CouchDBFailure : public std::exception { }; @@ -105,19 +105,18 @@ class CouchSessionContainer : public SessionContainer { std::vector<std::string> CouchSessionContainer::baseUrls; const Glib::ustring CouchSessionContainer::ExpiryKey("project2:expires"); -namespace po = boost::program_options; class CustomCouchSessionLoader : public SessionContainerLoaderImpl<CouchSessionContainer> { public: CustomCouchSessionLoader() : opts("Session CouchDB options") { - opts.add_options() - ("session.couchdb.baseurl", po::value(&CouchSessionContainer::baseUrls)->composing(), + opts + ("session.couchdb.baseUrl", Options::value(&CouchSessionContainer::baseUrls), "Base URL to store sessions in") ; } - po::options_description * - options() + const Options * + options() const { return &opts; } @@ -184,7 +183,7 @@ class CustomCouchSessionLoader : public SessionContainerLoaderImpl<CouchSessionC return; } } - po::options_description opts; + Options opts; }; DECLARE_CUSTOM_COMPONENT_LOADER("couchsession", CouchSessionContainer, CustomCouchSessionLoader, SessionContainerLoader); diff --git a/project2/mail/sendmailTask.cpp b/project2/mail/sendmailTask.cpp index 18be222..e2ca703 100644 --- a/project2/mail/sendmailTask.cpp +++ b/project2/mail/sendmailTask.cpp @@ -13,25 +13,24 @@ std::string SendMailTask::defaultMailServer; -namespace po = boost::program_options; class CustomSendMailTaskLoader : public ElementLoaderImpl<SendMailTask> { public: CustomSendMailTaskLoader() : opts("Send Email Task options") { - opts.add_options() - ("sendmail.defaultserver", po::value(&SendMailTask::defaultMailServer), + opts + ("sendmail.defaultServer", Options::value(&SendMailTask::defaultMailServer), "The address of the default mail relay server") ; } - po::options_description * - options() + const Options * + options() const { return &opts; } private: - po::options_description opts; + Options opts; }; DECLARE_CUSTOM_LOADER("sendmail", CustomSendMailTaskLoader); diff --git a/project2/sql/pch.hpp b/project2/sql/pch.hpp index f009f1c..a212245 100644 --- a/project2/sql/pch.hpp +++ b/project2/sql/pch.hpp @@ -23,7 +23,7 @@ #include "xmlObjectLoader.h" #include <boost/bind.hpp> #include <boost/foreach.hpp> -#include <boost/program_options.hpp> +#include "options.h" #include <buffer.h> #include <column.h> #include <errno.h> diff --git a/project2/sql/sqlCache.cpp b/project2/sql/sqlCache.cpp index 5435dc4..d1ae930 100644 --- a/project2/sql/sqlCache.cpp +++ b/project2/sql/sqlCache.cpp @@ -13,7 +13,7 @@ #include "iHaveParameters.h" #include "rowSet.h" #include <boost/foreach.hpp> -#include <boost/program_options.hpp> +#include "options.h" #include <boost/algorithm/string/predicate.hpp> typedef boost::shared_ptr<DB::SelectCommand> SelectPtr; @@ -257,23 +257,22 @@ std::string SqlCache::DataSource; std::string SqlCache::HeaderTable; time_t SqlCache::CacheLife; -namespace po = boost::program_options; class CustomSqlCacheLoader : public ElementLoaderImpl<SqlCache> { public: CustomSqlCacheLoader() : opts("SQL Cache options") { - opts.add_options() - ("cache.sql.datasource", po::value(&SqlCache::DataSource), + opts + ("cache.sql.dataSource", Options::value(&SqlCache::DataSource), "The default datasource to connect to") - ("cache.sql.headertable", po::value(&SqlCache::HeaderTable)->default_value("p2cache"), + ("cache.sql.headerTable", Options::value(&SqlCache::HeaderTable, "p2cache"), "The filename to store the data in") - ("cache.sql.life", po::value(&SqlCache::CacheLife)->default_value(3600), + ("cache.sql.life", Options::value(&SqlCache::CacheLife, 3600), "The age of cache entries after which they are removed (seconds)") ; } - po::options_description * options() + const Options * options() const { return &opts; } @@ -293,7 +292,7 @@ class CustomSqlCacheLoader : public ElementLoaderImpl<SqlCache> { } private: - po::options_description opts; + Options opts; }; DECLARE_CUSTOM_LOADER("sqlcache", CustomSqlCacheLoader); diff --git a/project2/xml/pch.hpp b/project2/xml/pch.hpp index 911d45c..329d949 100644 --- a/project2/xml/pch.hpp +++ b/project2/xml/pch.hpp @@ -15,7 +15,7 @@ #include "variables.h" #include <boost/filesystem/path.hpp> #include <boost/foreach.hpp> -#include <boost/program_options.hpp> +#include "options.h" #include <libxml++/document.h> #include <libxml++/nodes/element.h> #include <libxml++/nodes/textnode.h> diff --git a/project2/xml/sessionXml.cpp b/project2/xml/sessionXml.cpp index 12235b1..b66a812 100644 --- a/project2/xml/sessionXml.cpp +++ b/project2/xml/sessionXml.cpp @@ -6,16 +6,15 @@ #include <boost/foreach.hpp> #include <boost/filesystem/convenience.hpp> #include <boost/lexical_cast.hpp> -#include <boost/program_options.hpp> +#include "options.h" -namespace po = boost::program_options; class CustomSessionContainerLoaderXml : public SessionContainerLoaderImpl<SessionContainerXml> { public: CustomSessionContainerLoaderXml() : opts("SessionXML options") { - opts.add_options() - ("session.xml.path", po::value(&SessionContainerXml::xmlDir)->default_value("/tmp/project2.sessions"), + opts + ("session.xml.path", Options::value(&SessionContainerXml::xmlDir, "/tmp/project2.sessions"), "Path of the folder in which to store XML files for session information") ; } @@ -35,14 +34,14 @@ class CustomSessionContainerLoaderXml : public SessionContainerLoaderImpl<Sessio } } } - po::options_description * - options() + const Options * + options() const { return &opts; } private: - po::options_description opts; + Options opts; }; boost::filesystem::path SessionContainerXml::xmlDir; diff --git a/project2/xml/xmlCache.cpp b/project2/xml/xmlCache.cpp index 64e5f86..8c0dd00 100644 --- a/project2/xml/xmlCache.cpp +++ b/project2/xml/xmlCache.cpp @@ -7,7 +7,7 @@ #include "xmlPresenter.h" #include <sys/stat.h> #include <boost/foreach.hpp> -#include <boost/program_options.hpp> +#include "options.h" #include <boost/filesystem/path.hpp> #include <boost/filesystem/convenience.hpp> #include <libxml++/document.h> @@ -84,23 +84,22 @@ boost::filesystem::path XmlCache::Store; std::string XmlCache::FileName; time_t XmlCache::CacheLife; -namespace po = boost::program_options; class CustomXmlCacheLoader : public ElementLoaderImpl<XmlCache> { public: CustomXmlCacheLoader() : opts("XML Cache options") { - opts.add_options() - ("cache.xml.store", po::value(&XmlCache::Store)->default_value("/tmp/project2.cache"), + opts + ("cache.xml.store", Options::value(&XmlCache::Store, "/tmp/project2.cache"), "The root folder of the cache storage area") - ("cache.xml.filename", po::value(&XmlCache::FileName)->default_value("cache.xml"), + ("cache.xml.filename", Options::value(&XmlCache::FileName, "cache.xml"), "The filename to store the data in") - ("cache.xml.life", po::value(&XmlCache::CacheLife)->default_value(3600), + ("cache.xml.life", Options::value(&XmlCache::CacheLife, 3600), "The age of cache entries after which they are removed (seconds)") ; } - po::options_description * options() + const Options * options() const { return &opts; } @@ -138,7 +137,7 @@ class CustomXmlCacheLoader : public ElementLoaderImpl<XmlCache> { } private: - po::options_description opts; + Options opts; }; DECLARE_CUSTOM_LOADER("xmlcache", CustomXmlCacheLoader); |