+++ /dev/null
-#ifndef STLPLUS_CLI_PARSER\r
-#define STLPLUS_CLI_PARSER\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-// Author: Andy Rushton\r
-// Copyright: (c) Southampton University 1999-2004\r
-// (c) Andy Rushton 2004-2009\r
-// License: BSD License, see ../docs/license.html\r
-\r
-// A subsystem for managing command-line parsing, including using INI files to\r
-// control the default options.\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "subsystems_fixes.hpp"\r
-#include "message_handler.hpp"\r
-#include "ini_manager.hpp"\r
-#include "smart_ptr.hpp"\r
-#include <string>\r
-#include <stdexcept>\r
-\r
-namespace stlplus\r
-{\r
-\r
- ////////////////////////////////////////////////////////////////////////////////\r
- // Internals\r
-\r
- class cli_parser_data;\r
-\r
- ////////////////////////////////////////////////////////////////////////////////\r
- // declarations\r
-\r
- // enum to define the basic behaviour of an argument\r
- // - a switch is an option with no value but which can be switched on or off e.g. -help and -nohelp\r
- // - a value is an option followed by a value e.g. -output results.txt\r
- // (a default value can be removed by using the option as a negated switch e.g. -nooutput)\r
- // - command-line values (i.e. any strings not preceded by '-') are treated\r
- // internally as an option with no name and must be values\r
- enum cli_kind_t {cli_switch_kind, cli_value_kind};\r
-\r
- // the mode controls the behaviour if an option appears more than once in either the command-line or the ini files\r
- // - a single mode option overrides all previous values so will only be found once in the parsed result\r
- // - a multiple mode option can be repeated to define multiple values, but overrides values from ini files\r
- // - a cumulative mode option is a multiple mode option which keeps ini file values as well\r
- enum cli_mode_t {cli_single_mode, cli_multiple_mode, cli_cumulative_mode};\r
-\r
- // There are two structures used for defining command-line parameters\r
- // (1) a C struct which is used in a C array - this is used for declaring\r
- // command-line parameters in a static declaration\r
- // (2) a C++ class which is used in an STL vector - this is used for building\r
- // command-line parameters within code\r
-\r
- // The C struct for definitions\r
- struct cli_definition_t\r
- {\r
- // the name of the option, e.g. "help"\r
- const char* m_name;\r
-\r
- // the kind of the option, e.g. cli_switch_kind\r
- cli_kind_t m_kind;\r
-\r
- // the mode e.g. cli_single_mode\r
- cli_mode_t m_mode;\r
-\r
- // the mnemonic for the message giving usage information for this option\r
- const char* m_message;\r
-\r
- // built-in default value - null if not present\r
- const char* m_default;\r
- };\r
-\r
- // The C array of the C struct. The array must be terminated by END_CLI_DEFINITIONS.\r
- typedef cli_definition_t cli_definitions_t [];\r
-#define END_CLI_DEFINITIONS {0,stlplus::cli_switch_kind,stlplus::cli_single_mode,"",0}\r
-\r
- // The C++ class for definitions\r
- class cli_definition\r
- {\r
- public:\r
- // constructor that allows a definition to be created in one line\r
- cli_definition(const std::string& name, cli_kind_t kind, cli_mode_t mode, \r
- const std::string& message, const std::string& default_value = std::string()) : \r
- m_name(name), m_kind(kind), m_mode(mode), m_message(message), m_default(default_value) {}\r
-\r
- // the name of the option, e.g. "help"\r
- const std::string& name(void) const;\r
-\r
- // the kind of the option, e.g. switch_kind\r
- cli_kind_t kind(void) const;\r
-\r
- // the mode e.g. single_mode\r
- cli_mode_t mode(void) const;\r
-\r
- // the mnemonic for the message giving usage\r
- const std::string& message(void) const;\r
-\r
- // built-in default value - empty string if not present\r
- const std::string& default_value(void) const;\r
-\r
- private:\r
- std::string m_name;\r
- cli_kind_t m_kind;\r
- cli_mode_t m_mode;\r
- std::string m_message;\r
- std::string m_default;\r
- };\r
-\r
- // The C++ vector of the C++ class\r
- typedef std::vector<cli_definition> cli_definitions;\r
-\r
- //////////////////////////////////////////////////////////////////////////////\r
- // exceptions that can be thrown by the CLI parser\r
- // they are all derivatives of std::logic_error because all errors are predictable by code inspection\r
- // a correct program will never throw an exception\r
-\r
- // thrown if a command-line argument is accessed with the wrong mode - i.e. attempt to get the value of a switch\r
- class cli_mode_error : public std::invalid_argument\r
- {\r
- public:\r
- cli_mode_error(const std::string& arg) : std::invalid_argument(arg) {}\r
- ~cli_mode_error(void) throw() {}\r
- };\r
-\r
- // similar to std::out_of_range thrown for using an index out of range\r
- class cli_index_error : public std::out_of_range\r
- {\r
- public:\r
- cli_index_error(const std::string& arg) : std::out_of_range(arg) {}\r
- ~cli_index_error(void) throw() {}\r
- };\r
-\r
- // similar to std::invalid_argument - thrown for passing an illegal argument to a method\r
- class cli_argument_error : public std::invalid_argument\r
- {\r
- public:\r
- cli_argument_error(const std::string& arg) : std::invalid_argument(arg) {}\r
- ~cli_argument_error(void) throw() {}\r
- };\r
-\r
- ////////////////////////////////////////////////////////////////////////////////\r
-\r
- class cli_parser\r
- {\r
- public:\r
- // Type definitions map the global type names onto convenient scoped names\r
-\r
- typedef cli_kind_t kind_t;\r
- typedef cli_mode_t mode_t;\r
- typedef cli_definition_t definition_t;\r
- typedef cli_definitions_t definitions_t;\r
- typedef cli_definition definition;\r
- typedef cli_definitions definitions;\r
-\r
- ////////////////////////////////////////////////////////////////////////////////\r
- // Methods\r
-\r
- // various constructors\r
-\r
- // you have a choice of either creating an uninitialised CLI parser and then\r
- // calling separate functions to set it up or of calling one of the\r
- // composite constructors. However, you must set up the error handler in the\r
- // constructor.\r
-\r
- // set up the parser with its error handler\r
- // defer everything else\r
- cli_parser(message_handler& errors)\r
- throw();\r
-\r
- // constructors using the C definitions_t structure\r
-\r
- // set up the parser with the error handler and define all the command-line options\r
- // defer default values and parameter parsing\r
- cli_parser(cli_definitions_t, message_handler& errors)\r
- throw(cli_mode_error);\r
- // set up the parser with the error handler and define all the command-line\r
- // options and their default from the ini files\r
- // defer parameter parsing\r
- cli_parser(cli_definitions_t, const ini_manager& defaults, const std::string& ini_section, message_handler& errors)\r
- throw(cli_mode_error);\r
- // set up the parser with the error handler and define all the command-line\r
- // options no ini files used for default values, so only built-in defaults\r
- // supported then parse the command line\r
- cli_parser(char* argv[], cli_definitions_t, message_handler& errors)\r
- throw(cli_mode_error,message_handler_id_error,message_handler_format_error);\r
- // set up the parser with the error handler and define all the command-line\r
- // options and their default from the ini files then parse the command line\r
- cli_parser(char* argv[], cli_definitions_t, const ini_manager& defaults, const std::string& ini_section, message_handler& errors)\r
- throw(cli_mode_error,message_handler_id_error,message_handler_format_error);\r
-\r
- // constructors using the C++ definitions structure\r
-\r
- // set up the parser with the error handler and define all the command-line\r
- // options from a C array of structs\r
- // defer default values and parameter parsing\r
- cli_parser(cli_definitions, message_handler& errors)\r
- throw(cli_mode_error);\r
- // set up the parser with the error handler and define all the command-line\r
- // options and their default from the ini files\r
- // defer parameter parsing\r
- cli_parser(cli_definitions, const ini_manager& defaults, const std::string& ini_section, message_handler& errors)\r
- throw(cli_mode_error);\r
- // set up the parser with the error handler and define all the command-line\r
- // options no ini files used for default values, so only built-in defaults\r
- // supported then parse the command line\r
- cli_parser(char* argv[], cli_definitions, message_handler& errors)\r
- throw(cli_mode_error,message_handler_id_error,message_handler_format_error);\r
- // set up the parser with the error handler and define all the command-line\r
- // options and their default from the ini files then parse the command line\r
- cli_parser(char* argv[], cli_definitions, const ini_manager& defaults, const std::string& ini_section, message_handler& errors)\r
- throw(cli_mode_error,message_handler_id_error,message_handler_format_error);\r
-\r
- ~cli_parser(void)\r
- throw();\r
-\r
- // the separate functions for initialising the parser in steps. These are\r
- // declared in the order of use. Firts, add definitions of command-line\r
- // arguments. Then optionally load default values from ini files, then\r
- // finally parse the command line.\r
-\r
- // add a set of C definitions. The definitions will be given ID codes from 0\r
- // to the number of elements - 1 in the array\r
- void add_definitions(cli_definitions_t)\r
- throw(cli_mode_error);\r
- // add a single C definition, returning the ID code for it\r
- unsigned add_definition(const definition_t&)\r
- throw(cli_mode_error,cli_argument_error);\r
- // add a set of C++ definitions. The definitions will be given ID codes from\r
- // 0 to the number of elements - 1 in the array\r
- void add_definitions(cli_definitions)\r
- throw(cli_mode_error);\r
- // add a single C++ definition, returning the ID code for it\r
- unsigned add_definition(const definition&)\r
- throw(cli_mode_error);\r
-\r
- // All definitions have an optional built-in default value which is stored\r
- // in the definition types above. However, these can optionally be\r
- // overridden by a value from an ini file. If you want this functionality,\r
- // call this function. If you don't want ini file handling, simply don't\r
- // call it. The values will be searched for only in the named section of the\r
- // ini file (sections are labelled by e.g. [vassemble]), so in this case you\r
- // would specify the section name as "vassemble" (exclude the brackets).\r
- void set_defaults(const ini_manager& defaults, const std::string& ini_section)\r
- throw();\r
-\r
- // the final stage of initialisation is to read the command-line and extract\r
- // the values from it. If parse errors are found, this will report the\r
- // errors using the error handler and return false.\r
- bool parse(char* argv[])\r
- throw(cli_argument_error,message_handler_id_error,message_handler_format_error);\r
-\r
- // test for whether the CLI parser is still valid (no errors have happened)\r
- // after the initialisation phase\r
- bool valid(void)\r
- throw();\r
-\r
- // iteration functions avoiding the use of iterators. Just loop through the\r
- // arguments from 0 to size()-1 and use the index of the loop to interrogate\r
- // the command-line for the value at that position.\r
-\r
- // the number of values to read, indexed 0 to size()-1\r
- unsigned size(void) const\r
- throw();\r
-\r
- // the argument name\r
- std::string name(unsigned i) const\r
- throw(cli_index_error);\r
- // the argument ID, that is, the offset into the original definitions\r
- unsigned id(unsigned i) const\r
- throw(cli_index_error);\r
-\r
- // the kind (switch or value) and short-cut tests for the different kinds\r
- cli_kind_t kind(unsigned i) const\r
- throw(cli_index_error);\r
- bool switch_kind(unsigned i) const\r
- throw(cli_index_error);\r
- bool value_kind(unsigned i) const\r
- throw(cli_index_error);\r
-\r
- // the mode (single, multiple, cumulative) and short-cut tests for the\r
- // different modes - you rarely need to know this since it mainly controls\r
- // the parsing\r
- cli_mode_t mode(unsigned i) const \r
- throw(cli_index_error);\r
- bool single_mode(unsigned i) const\r
- throw(cli_index_error);\r
- bool multiple_mode(unsigned i) const\r
- throw(cli_index_error);\r
- bool cumulative_mode(unsigned i) const\r
- throw(cli_index_error);\r
-\r
- // get the switch's value, but only if the value is of switch kind\r
- bool switch_value(unsigned i) const\r
- throw(cli_mode_error,cli_index_error);\r
-\r
- // get the option's value, but only if it is of value kind\r
- std::string string_value(unsigned i) const\r
- throw(cli_mode_error,cli_index_error);\r
-\r
- // print the usage report - typically in response to the -help switch being on\r
- void usage(void) const\r
- throw(std::runtime_error);\r
-\r
- private:\r
- friend class cli_parser_data;\r
- smart_ptr_nocopy<cli_parser_data> m_data;\r
- };\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r