X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fstlplus%2Fsubsystems%2Fcli_parser.cpp;fp=src%2Fstlplus%2Fsubsystems%2Fcli_parser.cpp;h=0000000000000000000000000000000000000000;hb=5846afb00833cc72fe72422ca896d2387c712cb4;hp=1088f3897fa442cecb548c0488debcb144309d91;hpb=a97500609dc3c1b11f9786d32bc458eb00de4c36;p=chaz%2Fyoink diff --git a/src/stlplus/subsystems/cli_parser.cpp b/src/stlplus/subsystems/cli_parser.cpp deleted file mode 100644 index 1088f38..0000000 --- a/src/stlplus/subsystems/cli_parser.cpp +++ /dev/null @@ -1,637 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// - -// Author: Andy Rushton -// Copyright: (c) Southampton University 1999-2004 -// (c) Andy Rushton 2004-2009 -// License: BSD License, see ../docs/license.html - -//////////////////////////////////////////////////////////////////////////////// -#include "cli_parser.hpp" -#include "file_system.hpp" -#include "dprintf.hpp" -//////////////////////////////////////////////////////////////////////////////// - -namespace stlplus -{ - - //////////////////////////////////////////////////////////////////////////////// - // cli_definition internals - - const std::string& stlplus::cli_definition::name(void) const - { - return m_name; - } - - stlplus::cli_kind_t stlplus::cli_definition::kind(void) const - { - return m_kind; - } - - stlplus::cli_mode_t stlplus::cli_definition::mode(void) const - { - return m_mode; - } - - const std::string& stlplus::cli_definition::message(void) const - { - return m_message; - } - - const std::string& stlplus::cli_definition::default_value(void) const - { - return m_default; - } - - //////////////////////////////////////////////////////////////////////////////// - // internal data structures - - class cli_value - { - public: - unsigned m_definition; - std::string m_value; - unsigned m_level; - std::string m_source; - - cli_value(unsigned definition, const std::string& value, unsigned level, const std::string& source) : - m_definition(definition), m_value(value), m_level(level), m_source(source) - { - } - }; - - //////////////////////////////////////////////////////////////////////////////// - - class cli_parser_data - { - public: - message_handler& m_messages; - std::string m_executable; - cli_parser::definitions m_definitions; - std::vector m_values; - unsigned m_level; - bool m_valid; - std::vector m_ini_files; - - public: - - cli_parser_data(message_handler& messages) : - m_messages(messages), m_level(1), m_valid(true) - { - // ensure that the CLI's messages are in the message handler - these - // can be overridden from a file later - see message_handler - if (!m_messages.message_present("CLI_VALUE_MISSING")) - m_messages.add_message("CLI_VALUE_MISSING", "option @0 requires a value - end of line was reached instead"); - if (!m_messages.message_present("CLI_UNRECOGNISED_OPTION")) - m_messages.add_message("CLI_UNRECOGNISED_OPTION", "@0 is not a recognised option for this command"); - if (!m_messages.message_present("CLI_NO_VALUES")) - m_messages.add_message("CLI_NO_VALUES", "argument @0 is invalid - this program doesn't take command-line arguments"); - if (!m_messages.message_present("CLI_USAGE_PROGRAM")) - m_messages.add_message("CLI_USAGE_PROGRAM", "usage:\n\t@0 { arguments }"); - if (!m_messages.message_present("CLI_USAGE_DEFINITIONS")) - m_messages.add_message("CLI_USAGE_DEFINITIONS", "arguments:"); - if (!m_messages.message_present("CLI_USAGE_VALUES")) - m_messages.add_message("CLI_USAGE_VALUES", "values:"); - if (!m_messages.message_present("CLI_USAGE_VALUE_RESULT")) - m_messages.add_message("CLI_USAGE_VALUE_RESULT", "\t@0 : from @1"); - if (!m_messages.message_present("CLI_USAGE_SWITCH_RESULT")) - m_messages.add_message("CLI_USAGE_SWITCH_RESULT", "\t-@0 : from @1"); - if (!m_messages.message_present("CLI_USAGE_OPTION_RESULT")) - m_messages.add_message("CLI_USAGE_OPTION_RESULT", "\t-@0 @1 : from @2"); - if (!m_messages.message_present("CLI_INI_HEADER")) - m_messages.add_message("CLI_INI_HEADER", "configuration files:"); - if (!m_messages.message_present("CLI_INI_FILE_PRESENT")) - m_messages.add_message("CLI_INI_FILE_PRESENT", "\t@0"); - if (!m_messages.message_present("CLI_INI_FILE_ABSENT")) - m_messages.add_message("CLI_INI_FILE_ABSENT", "\t@0 (not found)"); - if (!m_messages.message_present("CLI_INI_VARIABLE")) - m_messages.add_message("CLI_INI_VARIABLE", "unknown variable \"@0\" found in Ini file"); - } - - unsigned add_definition(const cli_parser::definition& definition) - { - m_definitions.push_back(definition); - return m_definitions.size()-1; - } - - std::string name(unsigned i) const throw(cli_index_error) - { - if (i >= m_values.size()) throw cli_index_error("Index " + dformat("%u",i) + " out of range"); - return m_definitions[m_values[i].m_definition].name(); - } - - unsigned id(unsigned i) const throw(cli_index_error) - { - if (i >= m_values.size()) throw cli_index_error("Index " + dformat("%u",i) + " out of range"); - return m_values[i].m_definition; - } - - cli_parser::kind_t kind(unsigned i) const throw(cli_index_error) - { - if (i >= m_values.size()) throw cli_index_error("Index " + dformat("%u",i) + " out of range"); - return m_definitions[m_values[i].m_definition].kind(); - } - - cli_parser::mode_t mode(unsigned i) const throw(cli_index_error) - { - if (i >= m_values.size()) throw cli_index_error("Index " + dformat("%u",i) + " out of range"); - return m_definitions[m_values[i].m_definition].mode(); - } - -// unsigned add_definition(const std::string& name, -// cli_parser::kind_t kind, -// cli_parser::mode_t mode, -// const std::string& message) -// { -// return add_definition(cli_parser::definition(name, kind, mode, message)); -// } - - unsigned find_definition(const std::string& name) - { - // this does substring matching on the definitions and returns the first - // match - however, it requires at least one character in the substring so - // that the "" convention for command line arguments doesn't match with - // anything. It returns size() if it fails - for (unsigned i = 0; i < m_definitions.size(); i++) - { - std::string candidate = m_definitions[i].name(); - if ((candidate.empty() && name.empty()) || - (!name.empty() && candidate.size() >= name.size() && candidate.substr(0,name.size()) == name)) - return i; - } - return m_definitions.size(); - } - - void clear_definitions(void) - { - m_definitions.clear(); - m_values.clear(); - reset_level(); - set_valid(); - } - - void reset_level(void) - { - // the starting level is 1 so that later functions can call clear_level with - // a value of m_level-1 without causing underflow - m_level = 1; - } - - void increase_level(void) - { - m_level++; - } - - void clear_level(unsigned definition, unsigned level) - { - // clears all values with this definition at the specified level or below - for (std::vector::iterator i = m_values.begin(); i != m_values.end(); ) - { - if (i->m_definition == definition && i->m_level <= level) - i = m_values.erase(i); - else - i++; - } - } - - void set_valid(void) - { - m_valid = true; - } - - void set_invalid(void) - { - m_valid = false; - } - - bool valid(void) const - { - return m_valid; - } - - unsigned add_value(unsigned definition, const std::string& value, const std::string& source) - { - // behaviour depends on mode: - // - single: erase all previous values - // - multiple: erase values at a lower level than current - // - cumulative: erase no previous values - switch (m_definitions[definition].mode()) - { - case cli_single_mode: - clear_level(definition, m_level); - break; - case cli_multiple_mode: - clear_level(definition, m_level-1); - break; - case cli_cumulative_mode: - break; - } - m_values.push_back(cli_value(definition,value,m_level,source)); - return m_values.size()-1; - } - - unsigned add_switch(unsigned definition, bool value, const std::string& source) - { - return add_value(definition, value ? "on" : "off", source); - } - - void erase_value(unsigned definition) - { - // this simply erases all previous values - clear_level(definition, m_level); - } - - void add_ini_file(const std::string& file) - { - m_ini_files.push_back(file); - } - - unsigned ini_file_size(void) const - { - return m_ini_files.size(); - } - - const std::string& ini_file(unsigned i) const - { - return m_ini_files[i]; - } - - unsigned add_checked_definition(const cli_parser::definition& definition) throw(cli_mode_error) - { - // check for stupid combinations - // at this stage the only really stupid one is to declare command line arguments to be switch mode - if (definition.name().empty() && definition.kind() == cli_switch_kind) - { - set_invalid(); - throw cli_mode_error("CLI arguments cannot be switch kind"); - } - // add the definition to the set of all definitions - unsigned i = add_definition(definition); - // also add it to the list of values, but only if it has a default value - if (!definition.default_value().empty()) - add_value(i, definition.default_value(), "builtin default"); - return i; - } - - bool switch_value(unsigned i) const throw(cli_mode_error,cli_index_error) - { - if (i >= m_values.size()) throw cli_index_error("Index " + dformat("%u",i) + " out of range"); - if (kind(i) != cli_switch_kind) throw cli_mode_error(name(i) + " is not a switch kind"); - std::string value = m_values[i].m_value; - return value == "on" || value == "true" || value == "1"; - } - - std::string string_value(unsigned i) const throw(cli_mode_error,cli_index_error) - { - if (i >= m_values.size()) throw cli_index_error("Index " + dformat("%u",i) + " out of range"); - if (kind(i) != cli_value_kind) throw cli_mode_error(name(i) + " is not a value kind"); - return m_values[i].m_value; - } - - void set_defaults(const ini_manager& defaults, const std::string& ini_section) throw() - { - // import default values from the Ini Manager - increase_level(); - // get the set of all names from the Ini manager so that illegal names generate meaningful error messages - std::vector names = defaults.variable_names(ini_section); - for (unsigned i = 0; i < names.size(); i++) - { - std::string name = names[i]; - unsigned definition = find_definition(name); - if (definition == (unsigned)-1) - { - // not found - give an error report - message_position position(defaults.variable_filename(ini_section,name), - defaults.variable_linenumber(ini_section,name), - 0); - m_messages.error(position,"CLI_INI_VARIABLE", name); - } - else - { - // found - so add the value - // multi-valued variables are entered as a comma-separated list and this is then turned into a vector - // the vector is empty if the value was empty - std::vector values = defaults.variable_values(ini_section, name); - // an empty string is used to negate the value - if (values.empty()) - erase_value(definition); - else - { - std::string source = filespec_to_relative_path(defaults.variable_filename(ini_section, name)); - for (unsigned j = 0; j < values.size(); j++) - add_value(definition, values[j], source); - } - } - } - // add the set of ini files to the list for usage reports - for (unsigned j = 0; j < defaults.size(); j++) - add_ini_file(defaults.filename(j)); - } - - bool parse(char* argv[]) throw(cli_argument_error,message_handler_id_error,message_handler_format_error) - { - bool result = true; - if (!argv) throw cli_argument_error("Argument vector cannot be null"); - increase_level(); - if (argv[0]) - m_executable = argv[0]; - for (unsigned i = 1; argv[i]; i++) - { - std::string name = argv[i]; - if (!name.empty() && name[0] == '-') - { - // we have a command line option - unsigned found = find_definition(name.substr(1, name.size()-1)); - if (found < m_definitions.size()) - { - // found it in its positive form - switch (m_definitions[found].kind()) - { - case cli_switch_kind: - add_switch(found, true, "command line"); - break; - case cli_value_kind: - // get the next argument in argv as the value of this option - // first check that there is a next value - if (!argv[i+1]) - result &= m_messages.error("CLI_VALUE_MISSING", name); - else - add_value(found, argv[++i], "command line"); - break; - } - } - else if (name.size() > 3 && name.substr(1,2) == "no") - { - found = find_definition(name.substr(3, name.size()-3)); - if (found < m_definitions.size()) - { - // found it in its negated form - switch (m_definitions[found].kind()) - { - case cli_switch_kind: - add_switch(found, false, "command line"); - break; - case cli_value_kind: - erase_value(found); - break; - } - } - else - { - // could not find this option in either its true or negated form - result &= m_messages.error("CLI_UNRECOGNISED_OPTION", name); - } - } - else - { - // could not find this option and it could not be negated - result &= m_messages.error("CLI_UNRECOGNISED_OPTION", name); - } - } - else - { - // we have a command-line value which is represented internally as an option with an empty string as its name - // some very obscure commands do not have values - only options, so allow for that case too - unsigned found = find_definition(""); - if (found < m_definitions.size()) - add_value(found, name, "command line"); - else - result &= m_messages.error("CLI_NO_VALUES", name); - } - } - if (!result) set_invalid(); - return result; - } - - void usage(void) const throw(std::runtime_error) - { - m_messages.information("CLI_USAGE_PROGRAM", m_executable); - m_messages.information("CLI_USAGE_DEFINITIONS"); - for (unsigned d = 0; d < m_definitions.size(); d++) - m_messages.information(m_definitions[d].message()); - if (m_values.size() != 0) - { - m_messages.information("CLI_USAGE_VALUES"); - for (unsigned v = 0; v < m_values.size(); v++) - { - std::string source = m_values[v].m_source; - std::string key = name(v); - if (key.empty()) - { - // command-line values - m_messages.information("CLI_USAGE_VALUE_RESULT", string_value(v), source); - } - else if (kind(v) == cli_switch_kind) - { - // a switch - m_messages.information("CLI_USAGE_SWITCH_RESULT", (switch_value(v) ? name(v) : "no" + name(v)), source); - } - else - { - // other values - std::vector args; - args.push_back(name(v)); - args.push_back(string_value(v)); - args.push_back(source); - m_messages.information("CLI_USAGE_OPTION_RESULT", args); - } - } - } - if (ini_file_size() > 0) - { - m_messages.information("CLI_INI_HEADER"); - for (unsigned i = 0; i < ini_file_size(); i++) - { - if (file_exists(ini_file(i))) - m_messages.information("CLI_INI_FILE_PRESENT", filespec_to_relative_path(ini_file(i))); - else - m_messages.information("CLI_INI_FILE_ABSENT", filespec_to_relative_path(ini_file(i))); - } - } - } - - private: - // make this class uncopyable - cli_parser_data(const cli_parser_data&); - cli_parser_data& operator = (const cli_parser_data&); - }; - - //////////////////////////////////////////////////////////////////////////////// - - cli_parser::cli_parser(message_handler& messages) throw() : - m_data(new cli_parser_data(messages)) - { - } - - cli_parser::cli_parser(cli_parser::definitions_t definitions, message_handler& messages) throw(cli_mode_error) : - m_data(new cli_parser_data(messages)) - { - add_definitions(definitions); - } - - cli_parser::cli_parser(cli_parser::definitions_t definitions, const ini_manager& defaults, const std::string& ini_section, message_handler& messages) throw(cli_mode_error) : - m_data(new cli_parser_data(messages)) - { - add_definitions(definitions); - set_defaults(defaults, ini_section); - } - - cli_parser::cli_parser(char* argv[], cli_parser::definitions_t definitions, message_handler& messages) throw(cli_mode_error,message_handler_id_error,message_handler_format_error) : - m_data(new cli_parser_data(messages)) - { - add_definitions(definitions); - parse(argv); - } - - cli_parser::cli_parser(char* argv[], cli_parser::definitions_t definitions, const ini_manager& defaults, const std::string& ini_section, message_handler& messages) throw(cli_mode_error,message_handler_id_error,message_handler_format_error) : - m_data(new cli_parser_data(messages)) - { - add_definitions(definitions); - set_defaults(defaults, ini_section); - parse(argv); - } - - cli_parser::cli_parser(cli_parser::definitions definitions, message_handler& messages) throw(cli_mode_error) : - m_data(new cli_parser_data(messages)) - { - add_definitions(definitions); - } - - cli_parser::cli_parser(cli_parser::definitions definitions, const ini_manager& defaults, const std::string& ini_section, message_handler& messages) throw(cli_mode_error) : - m_data(new cli_parser_data(messages)) - { - add_definitions(definitions); - set_defaults(defaults, ini_section); - } - - cli_parser::cli_parser(char* argv[], cli_parser::definitions definitions, message_handler& messages) throw(cli_mode_error,message_handler_id_error,message_handler_format_error) : - m_data(new cli_parser_data(messages)) - { - add_definitions(definitions); - parse(argv); - } - - cli_parser::cli_parser(char* argv[], cli_parser::definitions definitions, const ini_manager& defaults, const std::string& ini_section, message_handler& messages) throw(cli_mode_error,message_handler_id_error,message_handler_format_error) : - m_data(new cli_parser_data(messages)) - { - add_definitions(definitions); - set_defaults(defaults, ini_section); - parse(argv); - } - - cli_parser::~cli_parser(void) throw() - { - } - - void cli_parser::add_definitions(cli_parser::definitions_t definitions) throw(cli_mode_error) - { - m_data->clear_definitions(); - // the definitions array is terminated by a definition with a null name pointer - for (unsigned i = 0; definitions[i].m_name; i++) - add_definition(definitions[i]); - } - - unsigned cli_parser::add_definition(const cli_parser::definition_t& definition) throw(cli_mode_error,cli_argument_error) - { - std::string name = definition.m_name ? definition.m_name : ""; - std::string message = definition.m_message ? definition.m_message : ""; - std::string value = definition.m_default ? definition.m_default : ""; - return add_definition(cli_parser::definition(name, definition.m_kind, definition.m_mode, message, value)); - } - - void cli_parser::add_definitions(cli_parser::definitions definitions) throw(cli_mode_error) - { - m_data->clear_definitions(); - for (unsigned i = 0; i < definitions.size(); i++) - add_definition(definitions[i]); - } - - unsigned cli_parser::add_definition(const cli_parser::definition& definition) throw(cli_mode_error) - { - return m_data->add_checked_definition(definition); - } - - void cli_parser::set_defaults(const ini_manager& defaults, const std::string& ini_section) throw() - { - m_data->set_defaults(defaults, ini_section); - } - - bool cli_parser::parse(char* argv[]) throw(cli_argument_error,message_handler_id_error,message_handler_format_error) - { - return m_data->parse(argv); - } - - bool cli_parser::valid(void) throw() - { - return m_data->valid(); - } - - unsigned cli_parser::size(void) const throw() - { - return m_data->m_values.size(); - } - - std::string cli_parser::name(unsigned i) const throw(cli_index_error) - { - return m_data->name(i); - } - - unsigned cli_parser::id(unsigned i) const throw(cli_index_error) - { - return m_data->id(i); - } - - cli_parser::kind_t cli_parser::kind(unsigned i) const throw(cli_index_error) - { - return m_data->kind(i); - } - - bool cli_parser::switch_kind(unsigned i) const throw(cli_index_error) - { - return kind(i) == cli_switch_kind; - } - - bool cli_parser::value_kind(unsigned i) const throw(cli_index_error) - { - return kind(i) == cli_value_kind; - } - - cli_parser::mode_t cli_parser::mode(unsigned i) const throw(cli_index_error) - { - return m_data->mode(i); - } - - bool cli_parser::single_mode(unsigned i) const throw(cli_index_error) - { - return mode(i) == cli_single_mode; - } - - bool cli_parser::multiple_mode(unsigned i) const throw(cli_index_error) - { - return mode(i) == cli_multiple_mode; - } - - bool cli_parser::cumulative_mode(unsigned i) const throw(cli_index_error) - { - return mode(i) == cli_cumulative_mode; - } - - bool cli_parser::switch_value(unsigned i) const throw(cli_mode_error,cli_index_error) - { - return m_data->switch_value(i); - } - - std::string cli_parser::string_value(unsigned i) const throw(cli_mode_error,cli_index_error) - { - return m_data->string_value(i); - } - - //////////////////////////////////////////////////////////////////////////////// - - void cli_parser::usage(void) const throw(std::runtime_error) - { - m_data->usage(); - } - - //////////////////////////////////////////////////////////////////////////////// - -} // end namespace stlplus