From 161efedd3ddca75c1cd3ad7f8592653c5070614e Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 26 Mar 2010 12:16:49 +0200 Subject: Add option file and the build infrastructure --- odb/options.cxx | 658 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 658 insertions(+) create mode 100644 odb/options.cxx (limited to 'odb/options.cxx') diff --git a/odb/options.cxx b/odb/options.cxx new file mode 100644 index 0000000..d0e80b4 --- /dev/null +++ b/odb/options.cxx @@ -0,0 +1,658 @@ +// This code was generated by CLI, a command line interface +// compiler for C++. +// + +#include "options.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace cli +{ + // unknown_option + // + unknown_option:: + ~unknown_option () throw () + { + } + + void unknown_option:: + print (std::ostream& os) const + { + os << "unknown option '" << option () << "'"; + } + + const char* unknown_option:: + what () const throw () + { + return "unknown option"; + } + + // unknown_argument + // + unknown_argument:: + ~unknown_argument () throw () + { + } + + void unknown_argument:: + print (std::ostream& os) const + { + os << "unknown argument '" << argument () << "'"; + } + + const char* unknown_argument:: + what () const throw () + { + return "unknown argument"; + } + + // missing_value + // + missing_value:: + ~missing_value () throw () + { + } + + void missing_value:: + print (std::ostream& os) const + { + os << "missing value for option '" << option () << "'"; + } + + const char* missing_value:: + what () const throw () + { + return "missing option value"; + } + + // invalid_value + // + invalid_value:: + ~invalid_value () throw () + { + } + + void invalid_value:: + print (std::ostream& os) const + { + os << "invalid value '" << value () << "' for option '" + << option () << "'"; + } + + const char* invalid_value:: + what () const throw () + { + return "invalid option value"; + } + + // eos_reached + // + void eos_reached:: + print (std::ostream& os) const + { + os << what (); + } + + const char* eos_reached:: + what () const throw () + { + return "end of argument stream reached"; + } + + // file_io_failure + // + file_io_failure:: + ~file_io_failure () throw () + { + } + + void file_io_failure:: + print (std::ostream& os) const + { + os << "unable to open file '" << file () << "' or read failure"; + } + + const char* file_io_failure:: + what () const throw () + { + return "unable to open file or read failure"; + } + + // scanner + // + scanner:: + ~scanner () + { + } + + // argv_scanner + // + bool argv_scanner:: + more () + { + return i_ < argc_; + } + + const char* argv_scanner:: + peek () + { + if (i_ < argc_) + return argv_[i_]; + else + throw eos_reached (); + } + + const char* argv_scanner:: + next () + { + if (i_ < argc_) + { + const char* r (argv_[i_]); + + if (erase_) + { + for (int i (i_ + 1); i < argc_; ++i) + argv_[i - 1] = argv_[i]; + + --argc_; + argv_[argc_] = 0; + } + else + ++i_; + + return r; + } + else + throw eos_reached (); + } + + void argv_scanner:: + skip () + { + if (i_ < argc_) + ++i_; + else + throw eos_reached (); + } + + // argv_file_scanner + // + bool argv_file_scanner:: + more () + { + if (!args_.empty ()) + return true; + + while (base::more ()) + { + // See if the next argument is the file option. + // + const char* a (base::peek ()); + + if (!skip_ && a == option_) + { + base::next (); + + if (!base::more ()) + throw missing_value (option_); + + load (base::next ()); + + if (!args_.empty ()) + return true; + } + else + { + if (!skip_) + skip_ = (std::strcmp (a, "--") == 0); + + return true; + } + } + + return false; + } + + const char* argv_file_scanner:: + peek () + { + if (!more ()) + throw eos_reached (); + + return args_.empty () ? base::peek () : args_.front ().c_str (); + } + + const char* argv_file_scanner:: + next () + { + if (!more ()) + throw eos_reached (); + + if (args_.empty ()) + return base::next (); + else + { + hold_.swap (args_.front ()); + args_.pop_front (); + return hold_.c_str (); + } + } + + void argv_file_scanner:: + skip () + { + if (!more ()) + throw eos_reached (); + + if (args_.empty ()) + return base::skip (); + else + args_.pop_front (); + } + + void argv_file_scanner:: + load (const char* file) + { + using namespace std; + + ifstream is (file); + + if (!is.is_open ()) + throw file_io_failure (file); + + while (!is.eof ()) + { + string line; + getline (is, line); + + if (is.fail () && !is.eof ()) + throw file_io_failure (file); + + string::size_type n (line.size ()); + + // Trim the line from leading and trailing whitespaces. + // + if (n != 0) + { + const char* f (line.c_str ()); + const char* l (f + n); + + const char* of (f); + while (f < l && (*f == ' ' || *f == '\t' || *f == '\r')) + ++f; + + --l; + + const char* ol (l); + while (l > f && (*l == ' ' || *l == '\t' || *l == '\r')) + --l; + + if (f != of || l != ol) + line = f <= l ? string (f, l - f + 1) : string (); + } + + // Ignore empty lines, those that start with #. + // + if (line.empty () || line[0] == '#') + continue; + + string::size_type p (line.find (' ')); + + if (p == string::npos) + { + if (!skip_) + skip_ = (line == "--"); + + args_.push_back (line); + } + else + { + string s1 (line, 0, p); + + // Skip leading whitespaces in the argument. + // + n = line.size (); + for (++p; p < n; ++p) + { + char c (line[p]); + + if (c != ' ' && c != '\t' && c != '\r') + break; + } + + string s2 (line, p); + + if (!skip_ && s1 == option_) + load (s2.c_str ()); + else + { + args_.push_back (s1); + args_.push_back (s2); + } + } + } + } + + template + struct parser + { + static void + parse (X& x, scanner& s) + { + const char* o (s.next ()); + + if (s.more ()) + { + const char* v (s.next ()); + std::istringstream is (v); + if (!(is >> x && is.eof ())) + throw invalid_value (o, v); + } + else + throw missing_value (o); + } + }; + + template <> + struct parser + { + static void + parse (bool& x, scanner& s) + { + s.next (); + x = true; + } + }; + + template <> + struct parser + { + static void + parse (std::string& x, scanner& s) + { + const char* o (s.next ()); + + if (s.more ()) + x = s.next (); + else + throw missing_value (o); + } + }; + + template + struct parser > + { + static void + parse (std::vector& c, scanner& s) + { + X x; + parser::parse (x, s); + c.push_back (x); + } + }; + + template + struct parser > + { + static void + parse (std::set& c, scanner& s) + { + X x; + parser::parse (x, s); + c.insert (x); + } + }; + + template + struct parser > + { + static void + parse (std::map& m, scanner& s) + { + const char* o (s.next ()); + + if (s.more ()) + { + std::string ov (s.next ()); + std::string::size_type p = ov.find ('='); + + if (p == std::string::npos) + { + K k = K (); + + if (!ov.empty ()) + { + std::istringstream ks (ov); + + if (!(ks >> k && ks.eof ())) + throw invalid_value (o, ov); + } + + m[k] = V (); + } + else + { + K k = K (); + V v = V (); + std::string kstr (ov, 0, p); + std::string vstr (ov, p + 1); + + if (!kstr.empty ()) + { + std::istringstream ks (kstr); + + if (!(ks >> k && ks.eof ())) + throw invalid_value (o, ov); + } + + if (!vstr.empty ()) + { + std::istringstream vs (vstr); + + if (!(vs >> v && vs.eof ())) + throw invalid_value (o, ov); + } + + m[k] = v; + } + } + else + throw missing_value (o); + } + }; + + template + void + thunk (X& x, scanner& s) + { + parser::parse (x.*P, s); + } +} + +#include +#include + +// options +// + +options:: +options (int& argc, + char** argv, + bool erase, + ::cli::unknown_mode opt, + ::cli::unknown_mode arg) +: help_ (), + version_ (), + options_file_ () +{ + ::cli::argv_scanner s (argc, argv, erase); + _parse (s, opt, arg); +} + +options:: +options (int start, + int& argc, + char** argv, + bool erase, + ::cli::unknown_mode opt, + ::cli::unknown_mode arg) +: help_ (), + version_ (), + options_file_ () +{ + ::cli::argv_scanner s (start, argc, argv, erase); + _parse (s, opt, arg); +} + +options:: +options (int& argc, + char** argv, + int& end, + bool erase, + ::cli::unknown_mode opt, + ::cli::unknown_mode arg) +: help_ (), + version_ (), + options_file_ () +{ + ::cli::argv_scanner s (argc, argv, erase); + _parse (s, opt, arg); + end = s.end (); +} + +options:: +options (int start, + int& argc, + char** argv, + int& end, + bool erase, + ::cli::unknown_mode opt, + ::cli::unknown_mode arg) +: help_ (), + version_ (), + options_file_ () +{ + ::cli::argv_scanner s (start, argc, argv, erase); + _parse (s, opt, arg); + end = s.end (); +} + +options:: +options (::cli::scanner& s, + ::cli::unknown_mode opt, + ::cli::unknown_mode arg) +: help_ (), + version_ (), + options_file_ () +{ + _parse (s, opt, arg); +} + +void options:: +print_usage (::std::ostream& os) +{ + os << "--help Print usage information and exit." << ::std::endl; + + os << "--version Print version and exit." << ::std::endl; + + os << "--options-file Read additional options from with each option" << ::std::endl + << " appearing on a separate line optionally followed by space" << ::std::endl + << " and an option value." << ::std::endl; +} + +typedef +std::map +_cli_options_map; + +static _cli_options_map _cli_options_map_; + +struct _cli_options_map_init +{ + _cli_options_map_init () + { + _cli_options_map_["--help"] = + &::cli::thunk< options, bool, &options::help_ >; + _cli_options_map_["--version"] = + &::cli::thunk< options, bool, &options::version_ >; + _cli_options_map_["--options-file"] = + &::cli::thunk< options, std::string, &options::options_file_ >; + } +} _cli_options_map_init_; + +void options:: +_parse (::cli::scanner& s, + ::cli::unknown_mode opt_mode, + ::cli::unknown_mode arg_mode) +{ + bool opt = true; + + while (s.more ()) + { + const char* o = s.peek (); + + if (std::strcmp (o, "--") == 0) + { + s.skip (); + opt = false; + continue; + } + + _cli_options_map::const_iterator i ( + opt ? _cli_options_map_.find (o) : _cli_options_map_.end ()); + + if (i != _cli_options_map_.end ()) + { + (*(i->second)) (*this, s); + } + else if (opt && std::strncmp (o, "-", 1) == 0 && o[1] != '\0') + { + switch (opt_mode) + { + case ::cli::unknown_mode::skip: + { + s.skip (); + continue; + } + case ::cli::unknown_mode::stop: + { + break; + } + case ::cli::unknown_mode::fail: + { + throw ::cli::unknown_option (o); + } + } + + break; + } + else + { + switch (arg_mode) + { + case ::cli::unknown_mode::skip: + { + s.skip (); + continue; + } + case ::cli::unknown_mode::stop: + { + break; + } + case ::cli::unknown_mode::fail: + { + throw ::cli::unknown_argument (o); + } + } + + break; + } + } +} + -- cgit v1.1