summaryrefslogtreecommitdiff
path: root/gpr/source/app/common/argument_parser
diff options
context:
space:
mode:
Diffstat (limited to 'gpr/source/app/common/argument_parser')
-rw-r--r--gpr/source/app/common/argument_parser/CMakeLists.txt16
-rwxr-xr-xgpr/source/app/common/argument_parser/argument_parser.cpp125
-rwxr-xr-xgpr/source/app/common/argument_parser/argument_parser.h51
-rwxr-xr-xgpr/source/app/common/argument_parser/program_options_lite.cpp491
-rwxr-xr-xgpr/source/app/common/argument_parser/program_options_lite.h231
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__