diff options
Diffstat (limited to 'gpr/source/app/common/argument_parser')
5 files changed, 914 insertions, 0 deletions
diff --git a/gpr/source/app/common/argument_parser/CMakeLists.txt b/gpr/source/app/common/argument_parser/CMakeLists.txt new file mode 100644 index 0000000..e965221 --- /dev/null +++ b/gpr/source/app/common/argument_parser/CMakeLists.txt @@ -0,0 +1,16 @@ +# library +set( LIB_NAME argument_parser ) + +# get source files +file( GLOB SRC_FILES "*.c" "*.cpp" ) + +# get include files +file( GLOB INC_FILES "*.h" ) + +# library +add_library( ${LIB_NAME} STATIC ${SRC_FILES} ${INC_FILES} ) + +target_link_libraries( ${LIB_NAME} ) + +# set the folder where to place the projects +set_target_properties( ${LIB_NAME} PROPERTIES FOLDER lib ) diff --git a/gpr/source/app/common/argument_parser/argument_parser.cpp b/gpr/source/app/common/argument_parser/argument_parser.cpp new file mode 100755 index 0000000..ead5a28 --- /dev/null +++ b/gpr/source/app/common/argument_parser/argument_parser.cpp @@ -0,0 +1,125 @@ +/*! @file argument_parser.cpp + * + * @brief Implement class to handle argument parsing + * + * (C) Copyright 2018 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "argument_parser.h" + +#include <stdio.h> + +using namespace std; + +#ifdef __GNUC__ +#define COMPILER "[GCC %d.%d.%d]", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__ +#elif __INTEL_COMPILER +#define COMPILER "[ICC %d]", __INTEL_COMPILER +#elif _MSC_VER +#define COMPILER "[VS %d]", _MSC_VER +#else +#define COMPILER "[Unknown-CXX]" +#endif + +#ifdef _WIN32 +#define OPERATING_SYSTEM "[Windows]" +#elif __linux +#define OPERATING_SYSTEM "[Linux]" +#elif __CYGWIN__ +#define OPERATING_SYSTEM "[Cygwin]" +#elif __APPLE__ +#define OPERATING_SYSTEM "[Mac OS X]" +#else +#define OPERATING_SYSTEM "[Unknown-OS]" +#endif + +#define NUMBER_OF_BITS "[%d bit] ", (sizeof(void*) == 8 ? 64 : 32) ///< used for checking 64-bit O/S + +argument_parser::argument_parser(bool verbose) +{ +} + +void argument_parser::set_options() +{ +} + +int argument_parser::parse(int argc, char *argv [], const char* application_text, const char* prefix_text) +{ + argument_count = argc; + + for (int i = 0; i < argument_count; i++) + arguments[i] = argv[i]; + + set_options(); + + program_options_lite::setDefaults(command_options); + + const list<const char*>& argv_unhandled = program_options_lite::scanArgv(command_options, argument_count, (const char**) arguments); + + for (list<const char*>::const_iterator it = argv_unhandled.begin(); it != argv_unhandled.end(); it++) + { + fprintf(stderr, "Unhandled argument ignored: `%s'\n", *it); + } + + bool show_help = get_argument_count() == 1 || get_help(); + + if( get_verbose() || show_help ) + { + if( application_text ) + { + fprintf( stderr, "%s", application_text ); + fprintf( stderr, OPERATING_SYSTEM ); + fprintf( stderr, COMPILER ); + fprintf( stderr, NUMBER_OF_BITS ); + fprintf( stderr, "\n" ); + } + + printf("Executable: %s \n", get_application_path() ); + printf("Arguments: "); + + for (int i = 1; i < get_argument_count(); i++) + { + printf("%s ", get_argument(i)); + } + + printf("\n"); + } + + if ( show_help ) + { + print_help(); + return -1; + } + + if( application_text ) + { + if( prefix_text ) + fprintf( stderr, "%s %s", prefix_text, application_text ); + else + fprintf( stderr, "%s", application_text ); + + fprintf( stderr, OPERATING_SYSTEM ); + fprintf( stderr, COMPILER ); + fprintf( stderr, NUMBER_OF_BITS ); + fprintf( stderr, "\n" ); + } + + return 0; +} + +void argument_parser::print_help() +{ + doHelp(cout, command_options); +} + diff --git a/gpr/source/app/common/argument_parser/argument_parser.h b/gpr/source/app/common/argument_parser/argument_parser.h new file mode 100755 index 0000000..bc08a4c --- /dev/null +++ b/gpr/source/app/common/argument_parser/argument_parser.h @@ -0,0 +1,51 @@ +/*! @file argument_parser.h + * + * @brief Declare class to handle argument parsing + * + * (C) Copyright 2018 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define MAX_ARGC 100 + +#include "program_options_lite.h" + +class argument_parser +{ +private: + char* application_path; + int argument_count; + char* arguments[MAX_ARGC]; + +protected: + program_options_lite::Options command_options; + +public: + argument_parser(bool verbose = true); + + const int get_argument_count() { return argument_count; } + const char* get_argument(int index) { return arguments[index]; } + + const char* get_application_path() { return application_path; } + + virtual int parse(int argc, char *argv [], const char* application_text = NULL, const char* prefix_text = NULL ); + + virtual void set_options(); + + virtual void print_help(); + + virtual bool get_verbose() { return false; } + + virtual bool get_help() { return false; } + +}; diff --git a/gpr/source/app/common/argument_parser/program_options_lite.cpp b/gpr/source/app/common/argument_parser/program_options_lite.cpp new file mode 100755 index 0000000..ec3fbc5 --- /dev/null +++ b/gpr/source/app/common/argument_parser/program_options_lite.cpp @@ -0,0 +1,491 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2015, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +#include <stdlib.h> +#include <iostream> +#include <fstream> +#include <sstream> +#include <string> +#include <list> +#include <map> +#include <algorithm> +#include "program_options_lite.h" + +using namespace std; + +namespace program_options_lite +{ + + Options::~Options() + { + for(Options::NamesPtrList::iterator it = opt_list.begin(); it != opt_list.end(); it++) + { + delete *it; + } + } + + void Options::addOption(OptionBase *opt) + { + Names* names = new Names(); + names->opt = opt; + string& opt_string = opt->opt_string; + + size_t opt_start = 0; + for (size_t opt_end = 0; opt_end != string::npos;) + { + opt_end = opt_string.find_first_of(',', opt_start); + bool force_short = 0; + if (opt_string[opt_start] == '-') + { + opt_start++; + force_short = 1; + } + string opt_name = opt_string.substr(opt_start, opt_end - opt_start); + if (force_short || opt_name.size() == 1) + { + names->opt_short.push_back(opt_name); + opt_short_map[opt_name].push_back(names); + } + else + { + names->opt_long.push_back(opt_name); + opt_long_map[opt_name].push_back(names); + } + opt_start += opt_end + 1; + } + opt_list.push_back(names); + } + + /* Helper method to initiate adding options to Options */ + OptionSpecific Options::addOptions() + { + return OptionSpecific(*this); + } + + static void setOptions(Options::NamesPtrList& opt_list, const string& value) + { + /* multiple options may be registered for the same name: + * allow each to parse value */ + for (Options::NamesPtrList::iterator it = opt_list.begin(); it != opt_list.end(); ++it) + { + (*it)->opt->parse(value); + } + } + + static const char spaces[41] = " "; + + /* format help text for a single option: + * using the formatting: "-x, --long", + * if a short/long option isn't specified, it is not printed + */ + static void doHelpOpt(ostream& out, const Options::Names& entry, unsigned pad_short = 0) + { + pad_short = min(pad_short, 8u); + + if (!entry.opt_short.empty()) + { + unsigned pad = max((int)pad_short - (int)entry.opt_short.front().size(), 0); + out << "-" << entry.opt_short.front(); + if (!entry.opt_long.empty()) + { + out << ", "; + } + out << &(spaces[40 - pad]); + } + else + { + out << " "; + out << &(spaces[40 - pad_short]); + } + + if (!entry.opt_long.empty()) + { + out << "--" << entry.opt_long.front(); + } + } + + /* format the help text */ + void doHelp(ostream& out, Options& opts, unsigned columns) + { + const unsigned pad_short = 3; + /* first pass: work out the longest option name */ + unsigned max_width = 0; + for(Options::NamesPtrList::iterator it = opts.opt_list.begin(); it != opts.opt_list.end(); it++) + { + ostringstream line(ios_base::out); + doHelpOpt(line, **it, pad_short); + max_width = max(max_width, (unsigned) line.tellp()); + } + + unsigned opt_width = min(max_width+2, 28u + pad_short) + 2; + unsigned desc_width = columns - opt_width; + + /* second pass: write out formatted option and help text. + * - align start of help text to start at opt_width + * - if the option text is longer than opt_width, place the help + * text at opt_width on the next line. + */ + for(Options::NamesPtrList::iterator it = opts.opt_list.begin(); it != opts.opt_list.end(); it++) + { + ostringstream line(ios_base::out); + line << " "; + doHelpOpt(line, **it, pad_short); + + const string& opt_desc = (*it)->opt->opt_desc; + if (opt_desc.empty()) + { + /* no help text: output option, skip further processing */ + cout << line.str() << endl; + continue; + } + size_t currlength = size_t(line.tellp()); + if (currlength > opt_width) + { + /* if option text is too long (and would collide with the + * help text, split onto next line */ + line << endl; + currlength = 0; + } + /* split up the help text, taking into account new lines, + * (add opt_width of padding to each new line) */ + for (size_t newline_pos = 0, cur_pos = 0; cur_pos != string::npos; currlength = 0) + { + /* print any required padding space for vertical alignment */ + line << &(spaces[40 - opt_width + currlength]); + newline_pos = opt_desc.find_first_of('\n', newline_pos); + if (newline_pos != string::npos) + { + /* newline found, print substring (newline needn't be stripped) */ + newline_pos++; + line << opt_desc.substr(cur_pos, newline_pos - cur_pos); + cur_pos = newline_pos; + continue; + } + if (cur_pos + desc_width > opt_desc.size()) + { + /* no need to wrap text, remainder is less than avaliable width */ + line << opt_desc.substr(cur_pos); + break; + } + /* find a suitable point to split text (avoid spliting in middle of word) */ + size_t split_pos = opt_desc.find_last_of(' ', cur_pos + desc_width); + if (split_pos != string::npos) + { + /* eat up multiple space characters */ + split_pos = opt_desc.find_last_not_of(' ', split_pos) + 1; + } + + /* bad split if no suitable space to split at. fall back to width */ + bool bad_split = split_pos == string::npos || split_pos <= cur_pos; + if (bad_split) + { + split_pos = cur_pos + desc_width; + } + line << opt_desc.substr(cur_pos, split_pos - cur_pos); + + /* eat up any space for the start of the next line */ + if (!bad_split) + { + split_pos = opt_desc.find_first_not_of(' ', split_pos); + } + cur_pos = newline_pos = split_pos; + + if (cur_pos >= opt_desc.size()) + { + break; + } + line << endl; + } + + cout << line.str() << endl; + } + } + + bool storePair(Options& opts, bool allow_long, bool allow_short, const string& name, const string& value) + { + bool found = false; + Options::NamesMap::iterator opt_it; + if (allow_long) + { + opt_it = opts.opt_long_map.find(name); + if (opt_it != opts.opt_long_map.end()) + { + found = true; + } + } + + /* check for the short list */ + if (allow_short && !(found && allow_long)) + { + opt_it = opts.opt_short_map.find(name); + if (opt_it != opts.opt_short_map.end()) + { + found = true; + } + } + + if (!found) + { + /* not found */ + cerr << "Unknown option: `" << name << "' (value:`" << value << "')" << endl; + return false; + } + + setOptions((*opt_it).second, value); + return true; + } + + bool storePair(Options& opts, const string& name, const string& value) + { + return storePair(opts, true, true, name, value); + } + + /** + * returns number of extra arguments consumed + */ + unsigned parseGNU(Options& opts, unsigned argc, const char* argv[]) + { + /* gnu style long options can take the forms: + * --option=arg + * --option arg + */ + string arg(argv[0]); + size_t arg_opt_start = arg.find_first_not_of('-'); + size_t arg_opt_sep = arg.find_first_of('='); + string option = arg.substr(arg_opt_start, arg_opt_sep - arg_opt_start); + + unsigned extra_argc_consumed = 0; + if (arg_opt_sep == string::npos) + { + /* no argument found => argument in argv[1] (maybe) */ + /* xxx, need to handle case where option isn't required */ +#if 0 + /* commented out, to return to true GNU style processing + * where longopts have to include an =, otherwise they are + * booleans */ + if (argc == 1) + { + return 0; /* run out of argv for argument */ + } + extra_argc_consumed = 1; +#endif + if(!storePair(opts, true, false, option, "1")) + { + return 0; + } + } + else + { + /* argument occurs after option_sep */ + string val = arg.substr(arg_opt_sep + 1); + storePair(opts, true, false, option, val); + } + + return extra_argc_consumed; + } + + unsigned parseSHORT(Options& opts, unsigned argc, const char* argv[]) + { + /* short options can take the forms: + * --option arg + * -option arg + */ + string arg(argv[0]); + size_t arg_opt_start = arg.find_first_not_of('-'); + string option = arg.substr(arg_opt_start); + /* lookup option */ + + /* argument in argv[1] */ + /* xxx, need to handle case where option isn't required */ + if (argc == 1) + { + cerr << "Not processing option without argument `" << option << "'" << endl; + return 0; /* run out of argv for argument */ + } + storePair(opts, false, true, option, string(argv[1])); + + return 1; + } + + list<const char*> + scanArgv(Options& opts, unsigned argc, const char* argv[]) + { + /* a list for anything that didn't get handled as an option */ + list<const char*> non_option_arguments; + + for(unsigned i = 1; i < argc; i++) + { + if (argv[i][0] != '-') + { + non_option_arguments.push_back(argv[i]); + continue; + } + + if (argv[i][1] == 0) + { + /* a lone single dash is an argument (usually signifying stdin) */ + non_option_arguments.push_back(argv[i]); + continue; + } + + if (argv[i][1] != '-') + { + /* handle short (single dash) options */ +#if 0 + i += parsePOSIX(opts, argc - i, &argv[i]); +#else + i += parseSHORT(opts, argc - i, &argv[i]); +#endif + continue; + } + + if (argv[i][2] == 0) + { + /* a lone double dash ends option processing */ + while (++i < argc) + { + non_option_arguments.push_back(argv[i]); + } + break; + } + + /* handle long (double dash) options */ + i += parseGNU(opts, argc - i, &argv[i]); + } + + return non_option_arguments; + } + + void scanLine(Options& opts, string& line) + { + /* strip any leading whitespace */ + size_t start = line.find_first_not_of(" \t\n\r"); + if (start == string::npos) + { + /* blank line */ + return; + } + if (line[start] == '#') + { + /* comment line */ + return; + } + /* look for first whitespace or ':' after the option end */ + size_t option_end = line.find_first_of(": \t\n\r",start); + string option = line.substr(start, option_end - start); + + /* look for ':', eat up any whitespace first */ + start = line.find_first_not_of(" \t\n\r", option_end); + if (start == string::npos) + { + /* error: badly formatted line */ + return; + } + if (line[start] != ':') + { + /* error: badly formatted line */ + return; + } + + /* look for start of value string -- eat up any leading whitespace */ + start = line.find_first_not_of(" \t\n\r", ++start); + if (start == string::npos) + { + /* error: badly formatted line */ + return; + } + + /* extract the value part, which may contain embedded spaces + * by searching for a word at a time, until we hit a comment or end of line */ + size_t value_end = start; + do + { + if (line[value_end] == '#') + { + /* rest of line is a comment */ + value_end--; + break; + } + value_end = line.find_first_of(" \t\n\r", value_end); + /* consume any white space, incase there is another word. + * any trailing whitespace will be removed shortly */ + value_end = line.find_first_not_of(" \t\n\r", value_end); + } while (value_end != string::npos); + /* strip any trailing space from value*/ + value_end = line.find_last_not_of(" \t\n\r", value_end); + + string value; + if (value_end >= start) + { + value = line.substr(start, value_end +1 - start); + } + else + { + /* error: no value */ + return; + } + + /* store the value in option */ + storePair(opts, true, false, option, value); + } + + void scanFile(Options& opts, istream& in) + { + do + { + string line; + getline(in, line); + scanLine(opts, line); + } while(!!in); + } + + /* for all options in opts, set their storage to their specified + * default value */ + void setDefaults(Options& opts) + { + for(Options::NamesPtrList::iterator it = opts.opt_list.begin(); it != opts.opt_list.end(); it++) + { + (*it)->opt->setDefault(); + } + } + + void parseConfigFile(Options& opts, const string& filename) + { + ifstream cfgstream(filename.c_str(), ifstream::in); + if (!cfgstream) + { + cerr << "Failed to open config file: `" << filename << "'" << endl; + exit(EXIT_FAILURE); + } + scanFile(opts, cfgstream); + } +} diff --git a/gpr/source/app/common/argument_parser/program_options_lite.h b/gpr/source/app/common/argument_parser/program_options_lite.h new file mode 100755 index 0000000..901c816 --- /dev/null +++ b/gpr/source/app/common/argument_parser/program_options_lite.h @@ -0,0 +1,231 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2015, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +#include <iostream> +#include <sstream> +#include <string> +#include <list> +#include <map> + +#ifndef __PROGRAM_OPTIONS_LITE__ +#define __PROGRAM_OPTIONS_LITE__ + +namespace program_options_lite +{ + struct Options; + + struct ParseFailure : public std::exception + { + ParseFailure(std::string arg0, std::string val0) throw() + : arg(arg0), val(val0) + {} + + ~ParseFailure() throw() {}; + + std::string arg; + std::string val; + + const char* what() const throw() { return "Option Parse Failure"; } + }; + + void doHelp(std::ostream& out, Options& opts, unsigned columns = 80); + unsigned parseGNU(Options& opts, unsigned argc, const char* argv[]); + unsigned parseSHORT(Options& opts, unsigned argc, const char* argv[]); + std::list<const char*> scanArgv(Options& opts, unsigned argc, const char* argv[]); + void scanLine(Options& opts, std::string& line); + void scanFile(Options& opts, std::istream& in); + void setDefaults(Options& opts); + void parseConfigFile(Options& opts, const std::string& filename); + bool storePair(Options& opts, const std::string& name, const std::string& value); + + /** OptionBase: Virtual base class for storing information relating to a + * specific option This base class describes common elements. Type specific + * information should be stored in a derived class. */ + struct OptionBase + { + OptionBase(const std::string& name, const std::string& desc) + : opt_string(name), opt_desc(desc) + {}; + + virtual ~OptionBase() {} + + /* parse argument arg, to obtain a value for the option */ + virtual void parse(const std::string& arg) = 0; + /* set the argument to the default value */ + virtual void setDefault() = 0; + + std::string opt_string; + std::string opt_desc; + }; + + /** Type specific option storage */ + template<typename T> + struct Option : public OptionBase + { + Option(const std::string& name, T& storage, T default_val, const std::string& desc) + : OptionBase(name, desc), opt_storage(storage), opt_default_val(default_val) + {} + + void parse(const std::string& arg); + + void setDefault() + { + opt_storage = opt_default_val; + } + + T& opt_storage; + T opt_default_val; + }; + + /* Generic parsing */ + template<typename T> + inline void + Option<T>::parse(const std::string& arg) + { + std::istringstream arg_ss (arg,std::istringstream::in); + arg_ss.exceptions(std::ios::failbit); + try + { + arg_ss >> opt_storage; + } + catch (...) + { + throw ParseFailure(opt_string, arg); + } + } + + /* string parsing is specialized -- copy the whole string, not just the + * first word */ + template<> + inline void + Option<std::string>::parse(const std::string& arg) + { + opt_storage = arg; + } + + /** Option class for argument handling using a user provided function */ + struct OptionFunc : public OptionBase + { + typedef void (Func)(Options&, const std::string&); + + OptionFunc(const std::string& name, Options& parent_, Func *func_, const std::string& desc) + : OptionBase(name, desc), parent(parent_), func(func_) + {} + + void parse(const std::string& arg) + { + func(parent, arg); + } + + void setDefault() + { + return; + } + + private: + Options& parent; + void (*func)(Options&, const std::string&); + }; + + class OptionSpecific; + struct Options + { + ~Options(); + + OptionSpecific addOptions(); + + struct Names + { + Names() : opt(0) {}; + ~Names() + { + if (opt) + { + delete opt; + } + } + std::list<std::string> opt_long; + std::list<std::string> opt_short; + OptionBase* opt; + }; + + void addOption(OptionBase *opt); + + typedef std::list<Names*> NamesPtrList; + NamesPtrList opt_list; + + typedef std::map<std::string, NamesPtrList> NamesMap; + NamesMap opt_long_map; + NamesMap opt_short_map; + }; + + /* Class with templated overloaded operator(), for use by Options::addOptions() */ + class OptionSpecific + { + public: + OptionSpecific(Options& parent_) : parent(parent_) {} + + /** + * Add option described by name to the parent Options list, + * with storage for the option's value + * with default_val as the default value + * with desc as an optional help description + */ + template<typename T> + OptionSpecific& + operator()(const std::string& name, T& storage, T default_val, const std::string& desc = "") + { + parent.addOption(new Option<T>(name, storage, default_val, desc)); + return *this; + } + + /** + * Add option described by name to the parent Options list, + * with desc as an optional help description + * instead of storing the value somewhere, a function of type + * OptionFunc::Func is called. It is upto this function to correctly + * handle evaluating the option's value. + */ + OptionSpecific& + operator()(const std::string& name, OptionFunc::Func *func, const std::string& desc = "") + { + parent.addOption(new OptionFunc(name, parent, func, desc)); + return *this; + } + private: + Options& parent; + }; + +} /* namespace: program_options_lite */ + + +#endif // __PROGRAM_OPTIONS_LITE__ |