diff --git a/Makefile.am b/Makefile.am index 57382779..814c1e6e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -248,11 +248,6 @@ UTIL_FILES = \ view.cpp \ view.hpp -# zlib.cpp -# zlib.hpp -# options.cpp -# options.hpp - if PLATFORM_LINUX UTIL_FILES += \ backtrace_execinfo.cpp \ diff --git a/options.cpp b/options.cpp deleted file mode 100644 index 51d68869..00000000 --- a/options.cpp +++ /dev/null @@ -1,605 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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. - * - * Copyright 2013 Danny Robson - */ - - -#include "options.hpp" - -#include "debug.hpp" -#include "string.hpp" -#include "types.hpp" -#include "types/casts.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -using util::option; -using util::nulloption; -using util::presentoption; -using util::valueoption; -using util::bytesoption; -using util::processor; - - -/////////////////////////////////////////////////////////////////////////////// -/// Generic option operations, failure or default modes -option::option (char _letter, - const char *_name, - const char *_desc, - bool _required): - m_shortopt (_letter), - m_longopt (_name), - m_description(_desc), - m_required (_required), - m_found (false) -{ reset(); } - - -//----------------------------------------------------------------------------- -void -option::execute (void) -{ - throw std::runtime_error( - "Cannot provide no value for the option '" + m_longopt + "'" - ); -} - - -//----------------------------------------------------------------------------- -void -option::execute (const std::string& data) -{ - assert(data.size() > 0); - throw std::runtime_error( - "Cannot provide a value for the option '" + m_longopt + "'" - ); -} - - -//----------------------------------------------------------------------------- -std::ostream& -operator<< (std::ostream & os, const option& opt) -{ - os << (opt.is_required () ? " -" : "[-" ) << opt.shortopt () - << (opt.is_required () ? " \t" : "]\t") << opt.longopt () - << "\t" << opt.description (); - return os; -} - - -//----------------------------------------------------------------------------- -void -option::finish (void) -{ - if (m_required && !m_found) - throw std::runtime_error ("Required argument not found: " + m_longopt); -} - - -/////////////////////////////////////////////////////////////////////////////// -nulloption::nulloption (char _letter, - const char *_name, - const char *_desc, - bool _required): - option (_letter, _name, _desc, _required) -{ ; } - - -/////////////////////////////////////////////////////////////////////////////// -presentoption::presentoption (char _letter, - const char *_name, - const char *_desc, - bool *_data, - bool _required): - option (_letter, _name, _desc, _required), - m_data (_data) -{ ; } - - -//----------------------------------------------------------------------------- -void -presentoption::execute (void) -{ - *m_data = true; - m_found = true; -} - - -/////////////////////////////////////////////////////////////////////////////// -namespace util { - template<> - bool& - valueoption::get_arg(const std::string& arg, bool *val) - { - if (arg == "true" || arg == "yes" || arg == "1") - return *val = true; - else if (arg == "false" || arg == "no" || arg == "0") - return *val = false; - else - throw std::domain_error("Invalid form for boolean argument"); - } - - - template - T& - valueoption::get_arg(const std::string &arg, - T *val) - { - std::istringstream stream (arg, std::istringstream::in); - stream.exceptions ( - std::istringstream::failbit - | std::istringstream::badbit - ); - - stream >> *val; - return *val; - } -} - - -//----------------------------------------------------------------------------- -template std::string& util::valueoption::get_arg (const std::string&, std::string*); - -template int16_t& util::valueoption< int16_t>::get_arg (const std::string&, int16_t*); -template int32_t& util::valueoption< int32_t>::get_arg (const std::string&, int32_t*); -template int64_t& util::valueoption< int64_t>::get_arg (const std::string&, int64_t*); - -template uint16_t& util::valueoption::get_arg (const std::string&, uint16_t*); -template uint32_t& util::valueoption::get_arg (const std::string&, uint32_t*); -template uint64_t& util::valueoption::get_arg (const std::string&, uint64_t*); - - -/////////////////////////////////////////////////////////////////////////////// -bytesoption::bytesoption (char _letter, - const char *_name, - const char *_desc, - size_t *_data, - bytestype _type, - bytesmodifier _modifier, - bool _required): - valueoption (_letter, _name, _desc, _data, _required), - m_type (_type), - m_modifier (_modifier) -{ ; } - - -//----------------------------------------------------------------------------- -bytesoption::bytestype -bytesoption::type_from_character (char c) -{ - switch (c) { - case 'e': - case 'E': - return BYTES_EXA; - - case 'p': - case 'P': - return BYTES_PETA; - - case 't': - case 'T': - return BYTES_TERA; - - case 'g': - case 'G': - return BYTES_GIGA; - - case 'm': - case 'M': - return BYTES_MEGA; - - case 'k': - case 'K': - return BYTES_KILO; - - default: - throw std::domain_error("Invalid magnitude specifier"); - } -} - - -//----------------------------------------------------------------------------- -void -bytesoption::execute (const std::string& data) -{ - // We shouldn't get this far into processing with a zero sized argument, - // that's what the null data execute function is for. - assert (data.size () > 0); - - size_t defaultvalue = *m_data; - - try { - bytesmodifier modifier = m_modifier; - size_t cursor = data.size () - 1; - - // Consume an optional trailing `byte' type - if (data[cursor] == 'B' || data[cursor] == 'b') { - if (cursor == 0) - throw std::invalid_argument ("Size is too short"); - --cursor; - } - - // Check if we explicitly request base2 - if (data[cursor] == 'i') { - modifier = BYTES_BASE2; - if (cursor == 0) - throw std::invalid_argument("Size is too short"); - --cursor; - } - - // Determine what constant factor is needed for the raw size - uint64_t multiplier = 1; - uint64_t modifier_factor; - switch (modifier) { - case BYTES_BASE2: - modifier_factor = 1024; - break; - - case BYTES_BASE10: - modifier_factor = 1000; - break; - - default: - unreachable (); - } - - // Find the difference in magnitude between what is desired, and what - // is specified by the user. Raise the multiplier by that magnitude. - bytestype specified = m_type; - try { - specified = type_from_character (data[cursor]); - // If the character is a digit, it just means the user skipped the - // size specifier, which is ok. - } catch (std::domain_error &x) { - if (!isdigit (data[cursor])) - throw std::invalid_argument ("Not a size"); - - // Falsely increment the cursor if there's no size specifier... - ++cursor; - } - - // ... so that we can easily decrement the cursor without special logic - // after reading the specifiers. - --cursor; - - multiplier = static_cast (std::pow (modifier_factor, (int)specified)); - get_arg (data.substr(0, cursor + 1), m_data); - *m_data *= multiplier; - } catch (...) { - // Ensure that we haven't nuked a default value due to a half - // completed calculation followed by an exception. - - *m_data = defaultvalue; - throw; - } - - m_found = true; -} - - -/////////////////////////////////////////////////////////////////////////////// -/// -/// Internal helper options. Print help and usage. -/// A callback to the processor which triggers output of the help message. -/// -/// This should never be instanced by a user of the system. The processor will -/// automatically adds this to its available options where needed. - -class helpoption : public option -{ -protected: - static const char HELP_CHARACTER; - static const char *HELP_NAME; - static const char *HELP_DESCRIPTION; - - processor * m_processor; - -public: - helpoption (processor * _processor): - option (HELP_CHARACTER, HELP_NAME, HELP_DESCRIPTION, false), - m_processor (_processor) - { ; } - - - virtual void execute (void); - virtual void execute (const std::string& data) - { option::execute (data); } -}; - - -//----------------------------------------------------------------------------- -const char helpoption::HELP_CHARACTER = 'h'; -const char *helpoption::HELP_NAME = "help"; -const char *helpoption::HELP_DESCRIPTION = - "display help and usage information"; - - -//----------------------------------------------------------------------------- -void -helpoption::execute (void) -{ - m_processor->print_usage (); - exit (EXIT_SUCCESS); -} - - -/////////////////////////////////////////////////////////////////////////////// -processor::processor () -{ - add_option (std::make_unique (this)); -} - - -//----------------------------------------------------------------------------- -processor::~processor () -{ ; } - - -//----------------------------------------------------------------------------- -void -processor::print_usage (void) -{ - std::cout << "Usage: " << m_command << " [options]\n"; - - for (const auto &i: m_options) - std::cout << '\t' << *i << '\n'; -} - - -///---------------------------------------------------------------------------- -/// Parse a single argument in short form. We are given an offset into the -/// argument array, and arguments. Establishes whether a value is present and -/// passes control over to the option. -/// -/// The format of the options are "-f [b]" || "-abcde" -/// -/// @param pos the current offset into the argument array -/// @param argc the size of the argument array -/// @param argv the argument array given to the application -/// -/// @return the number of tokens consumed for this option; must be at least 1. - -unsigned int -processor::parse_short (int pos, int argc, const char **argv) -{ - assert (pos > 0); - assert (pos < argc); - - assert (argv[pos] != NULL); - const char *arg = argv[pos]; - - // Must begin with a dash, then have at least one non-dash character - assert (arg[0] == '-'); - assert (arg[1] != '-'); - assert (strlen(arg) >= 2); - - // Check if we have a value option, Ie `-a [val]` - // First: must be of form '-[a-zA-Z]'. - if (strlen (arg) == 2) { - // Second: the next segment (which contains the value) shouldn't begin - // with a dash. - if (pos + 1 < argc && argv[pos+1][0] != '-') { - option * o = m_shortopt[arg[1]]; - if (!o) - throw std::runtime_error ("Cannot match option"); - - o->execute (argv[pos+1]); - return 2; - } - } - - // We must have a string of no-value flags, `-abcdef...`, execute each - // option in the list after the dash. - for(unsigned int i = 1; i < strlen (arg); ++i) { - option * o = m_shortopt[arg[i]]; - - if (!o) - throw std::runtime_error ("Cannot match option"); - o->execute (); - } - - return 1; -} - - -///---------------------------------------------------------------------------- -/// -/// Parse a single argument in long form. We are given an offset into the -/// argument array, and arguments. Establishes whether a value is present and -/// passes control over to the option. -/// -/// The format of the options are "--foo[=bar]" -/// -/// @param pos the current offset into the argument array -/// @param argc the size of the argument array -/// @param argv the argument array given to the application`--foo[=bar]` -/// -/// @return the number of tokens consumed for this option; must be 1. - -unsigned int -processor::parse_long (int pos, int argc, const char ** argv) -{ - assert (pos > 0); - assert (pos < argc); - - assert (argv[pos] != NULL); - const char *arg = argv[pos]; - - // We must have at least two hyphens, and two letters (else a short opt) - assert (arg[0] == '-'); - assert (arg[1] == '-'); - assert (strlen (arg) >= 4); - - // Skip past the dashes to the argument name - arg += 2; - - // If there's an equals it has a value to extract - const char *data = strchr (arg, '='); - option *o = data ? m_longopt[std::string (arg, data++)] - : m_longopt[arg]; - - if (!o) - throw std::runtime_error ("Cannot match option"); - - if (data) - o->execute (data); - else - o->execute (); - - return 1; -} - - -///---------------------------------------------------------------------------- -/// -/// Pass long and short options to specific parsing handlers. -/// -/// Establishes enough context to determine if the argument is long, short, or -/// none. The functions parse_long and parse_short are given the task of -/// dispatching control to the relevant option handlers. -/// -/// @param argc the raw parameter from the application main -/// @param argv the raw parameter from the application main - -void -processor::parse_args (int argc, const char ** argv) -{ - // While technically we can have zero arguments, for practical purposes - // this is a reasonable method at catching odd errors in the library. - assert (argc > 0); - assert (argv[0]); - - m_command.assign (argv[0]); - - // Must make sure each option has a chance to reset state (clear flags, - // etc) between parses - for (auto &i: m_options) - i->reset (); - - const int FIRST_ARGUMENT = 1; - try { - for (int i = FIRST_ARGUMENT; i < argc; ++i) { - // An argument must begin with a dash, if not we've reached the - // end of the argument lists or we have a parsing error. - if (argv[i][0] != '-') - return; - - // An argument must consist of at least one non-dash character - if (strlen (argv[i]) <= 1) - throw std::runtime_error ("Invalid argument"); - - // Actually hand off args to be parsed. Subtract one from the - // tokens consumed, as the for loop increments tokens too. - unsigned int consumed; - if (argv[i][1] != '-') - consumed = parse_short (i, argc, argv); - else - consumed = parse_long (i, argc, argv); - - assert (consumed >= 1); - i += sign_cast (consumed - 1); - } - } catch (std::runtime_error &x) { - print_usage (); - exit (EXIT_FAILURE); - } - - for (auto &i: m_options) - i->finish (); -} - - -//----------------------------------------------------------------------------- -void -processor::add_option (std::unique_ptr