diff options
-rw-r--r-- | cli/cli.cxx | 21 | ||||
-rw-r--r-- | cli/generator.cxx | 8 | ||||
-rw-r--r-- | cli/generator.hxx | 5 | ||||
-rw-r--r-- | cli/makefile | 15 | ||||
-rw-r--r-- | cli/options.cli | 18 | ||||
-rw-r--r-- | cli/options.cxx | 328 | ||||
-rw-r--r-- | cli/options.hxx | 230 |
7 files changed, 612 insertions, 13 deletions
diff --git a/cli/cli.cxx b/cli/cli.cxx index 9b2495d..eaf15f7 100644 --- a/cli/cli.cxx +++ b/cli/cli.cxx @@ -7,6 +7,7 @@ #include <fstream> #include <iostream> +#include "options.hxx" #include "parser.hxx" #include "generator.hxx" @@ -14,7 +15,7 @@ using namespace std; int main (int argc, char* argv[]) { - if (argc != 2) + if (argc < 2) { cerr << "usage: " << argv[0] << " file.cli" << endl; return 1; @@ -22,7 +23,16 @@ int main (int argc, char* argv[]) try { - semantics::path path (argv[1]); + int end; + options ops (argc, argv, end); + + if (end == argc) + { + cerr << "error: no input file specified" << endl; + return 1; + } + + semantics::path path (argv[end]); ifstream ifs (path.string ().c_str ()); if (!ifs.is_open ()) @@ -37,7 +47,12 @@ int main (int argc, char* argv[]) auto_ptr<semantics::cli_unit> unit (p.parse (ifs, path)); generator g; - g.generate (*unit, path); + g.generate (ops, *unit, path); + } + catch (cli::exception const& e) + { + cerr << e << endl; + return 1; } catch (semantics::invalid_path const& e) { diff --git a/cli/generator.cxx b/cli/generator.cxx index 79401e0..0142201 100644 --- a/cli/generator.cxx +++ b/cli/generator.cxx @@ -71,7 +71,7 @@ generator () } void generator:: -generate (semantics::cli_unit& unit, path const& p) +generate (options const& ops, semantics::cli_unit& unit, path const& p) { try { @@ -81,8 +81,6 @@ generate (semantics::cli_unit& unit, path const& p) string ixx_suffix (".ixx"); string cxx_suffix (".cxx"); - string out_dir; - path file (p.leaf ()); string base (file.base ().string ()); @@ -94,9 +92,9 @@ generate (semantics::cli_unit& unit, path const& p) path ixx_path (ixx_name); path cxx_path (cxx_name); - if (!out_dir.empty ()) + if (!ops.output_dir ().empty ()) { - path dir (out_dir); + path dir (ops.output_dir ()); hxx_path = dir / hxx_path; ixx_path = dir / ixx_path; diff --git a/cli/generator.hxx b/cli/generator.hxx index 40081af..c9b449d 100644 --- a/cli/generator.hxx +++ b/cli/generator.hxx @@ -6,7 +6,8 @@ #ifndef CLI_GENERATOR_HXX #define CLI_GENERATOR_HXX -#include <semantics/unit.hxx> +#include "options.hxx" +#include "semantics/unit.hxx" class generator { @@ -16,7 +17,7 @@ public: class failed {}; void - generate (semantics::cli_unit&, semantics::path const&); + generate (options const&, semantics::cli_unit&, semantics::path const&); private: generator (generator const&); diff --git a/cli/makefile b/cli/makefile index f281167..86df489 100644 --- a/cli/makefile +++ b/cli/makefile @@ -8,6 +8,7 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../build/bootstrap.make cxx_tun := cli.cxx lexer.cxx parser.cxx cxx_tun += \ +options.cxx \ context.cxx \ header.cxx \ inline.cxx \ @@ -32,9 +33,11 @@ traversal/namespace.cxx \ traversal/option.cxx \ traversal/unit.cxx +cli_tun := options.cli + # # -cxx_obj := $(addprefix $(out_base)/,$(cxx_tun:.cxx=.o)) +cxx_obj := $(addprefix $(out_base)/,$(cxx_tun:.cxx=.o) $(cli_tun:.cli=.o)) cxx_od := $(cxx_obj:.o=.o.d) cli := $(out_base)/cli @@ -52,9 +55,14 @@ $(call import,\ # $(cli): $(cxx_obj) $(cutl.l) -$(cxx_obj) $(cxx_od): cpp_options := -I$(src_base) +$(cxx_obj) $(cxx_od): cpp_options := -I$(src_base) -I$(out_base) $(cxx_obj) $(cxx_od): $(cutl.l.cpp-options) +genf := $(cli_tun:.cli=.hxx) $(cli_tun:.cli=.ixx) $(cli_tun:.cli=.cxx) +gen := $(addprefix $(out_base)/,$(genf)) + +$(gen): cli := $(out_root)/cli/cli + $(call include-dep,$(cxx_od)) # Alias for default target. @@ -80,7 +88,7 @@ $(install): $(cli) .PHONY: $(clean) $(clean): \ - $(cli).o.clean \ + $(cli).o.clean \ $(addsuffix .cxx.clean,$(cxx_obj)) \ $(addsuffix .cxx.clean,$(cxx_od)) @@ -102,4 +110,5 @@ endif $(call include,$(bld_root)/cxx/o-e.make) $(call include,$(bld_root)/cxx/cxx-o.make) $(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(scf_root)/cli/cli-cxx.make) $(call include,$(bld_root)/install.make) diff --git a/cli/options.cli b/cli/options.cli new file mode 100644 index 0000000..e7024fb --- /dev/null +++ b/cli/options.cli @@ -0,0 +1,18 @@ +// file : cli/options.cli +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2009 Code Synthesis Tools CC +// license : MIT; see accompanying LICENSE file + +// NOTE: Make sure you have a working CLI compiler around +// before modifying this file. +// + +include <string>; +include <vector>; + +class options +{ + bool --help; + bool --version; + std::string --output-dir; +}; diff --git a/cli/options.cxx b/cli/options.cxx new file mode 100644 index 0000000..6aba013 --- /dev/null +++ b/cli/options.cxx @@ -0,0 +1,328 @@ +// This code was generated by CLI, a command line interface +// compiler for C++. +// + +#include "options.hxx" + +// options +// + +bool const& options:: +help () const +{ + return help_; +} + +bool const& options:: +version () const +{ + return version_; +} + +std::string const& options:: +output_dir () const +{ + return output_dir_; +} + +#include <string> +#include <vector> +#include <ostream> +#include <sstream> + +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"; + } + + template <typename X> + struct parser + { + static int + parse (X& x, char** argv, int n) + { + if (n > 1) + { + std::istringstream is (argv[1]); + if (!(is >> x && is.eof ())) + throw invalid_value (argv[0], argv[1]); + return 2; + } + else + throw missing_value (argv[0]); + } + }; + + template <> + struct parser<bool> + { + static int + parse (bool& x, char**, int) + { + x = true; + return 1; + } + }; + + template <> + struct parser<std::string> + { + static int + parse (std::string& x, char** argv, int n) + { + if (n > 1) + { + x = argv[1]; + return 2; + } + else + throw missing_value (argv[0]); + } + }; + + template <typename X> + struct parser<std::vector<X> > + { + static int + parse (std::vector<X>& v, char** argv, int n) + { + X x; + int i (parser<X>::parse (x, argv, n)); + v.push_back (x); + return i; + } + }; + + template <typename X, typename T, T X::*P> + int + thunk (X& x, char** argv, int n) + { + return parser<T>::parse (x.*P, argv, n); + } +} + +#include <map> +#include <cstring> + +// options +// + +options:: +options (int argc, + char** argv, + ::cli::unknown_mode opt, + ::cli::unknown_mode arg) +: help_ (), + version_ (), + output_dir_ () +{ + _parse (1, argc, argv, opt, arg); +} + +options:: +options (int start, + int argc, + char** argv, + ::cli::unknown_mode opt, + ::cli::unknown_mode arg) +: help_ (), + version_ (), + output_dir_ () +{ + _parse (start, argc, argv, opt, arg); +} + +options:: +options (int argc, + char** argv, + int& end, + ::cli::unknown_mode opt, + ::cli::unknown_mode arg) +: help_ (), + version_ (), + output_dir_ () +{ + end = _parse (1, argc, argv, opt, arg); +} + +options:: +options (int start, + int argc, + char** argv, + int& end, + ::cli::unknown_mode opt, + ::cli::unknown_mode arg) +: help_ (), + version_ (), + output_dir_ () +{ + end = _parse (start, argc, argv, opt, arg); +} + +typedef +std::map<std::string, int (*) (options&, char**, int)> +_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_["--output-dir"] = + &::cli::thunk<options, std::string, &options::output_dir_>; + } +} _cli_options_map_init_; + +int options:: +_parse (int start, + int argc, + char** argv, + ::cli::unknown_mode opt_mode, + ::cli::unknown_mode arg_mode) +{ + bool opt (true); + + for (; start < argc;) + { + const char* s (argv[start]); + + if (std::strcmp (s, "--") == 0) + { + start++; + opt = false; + continue; + } + + _cli_options_map::const_iterator i ( + opt ? _cli_options_map_.find (s) : _cli_options_map_.end ()); + + if (i != _cli_options_map_.end ()) + { + start += (*(i->second)) (*this, argv + start, argc - start); + } + else if (opt && s[0] == '-' && s[1] != '\0') + { + switch (opt_mode) + { + case ::cli::unknown_mode::skip: + { + start++; + continue; + } + case ::cli::unknown_mode::stop: + { + break; + } + case ::cli::unknown_mode::fail: + { + throw ::cli::unknown_option (s); + } + } + + break; + } + else + { + switch (arg_mode) + { + case ::cli::unknown_mode::skip: + { + start++; + continue; + } + case ::cli::unknown_mode::stop: + { + break; + } + case ::cli::unknown_mode::fail: + { + throw ::cli::unknown_argument (s); + } + } + + break; + } + } + + return start; +} + diff --git a/cli/options.hxx b/cli/options.hxx new file mode 100644 index 0000000..37ec251 --- /dev/null +++ b/cli/options.hxx @@ -0,0 +1,230 @@ +// This code was generated by CLI, a command line interface +// compiler for C++. +// + +#ifndef OPTIONS_HXX +#define OPTIONS_HXX + +#include <iosfwd> +#include <string> +#include <exception> + +namespace cli +{ + class unknown_mode + { + public:enum value + { + skip, + stop, + fail + }; + + unknown_mode (value v) + : v_ (v) + { + } + + operator value () const + { + return v_; + } + + private: + value v_; + }; + + // Exceptions. + // + + class exception: public std::exception + { + public: + virtual void + print (std::ostream&) const = 0; + }; + + inline std::ostream& + operator<< (std::ostream& os, const exception& e) + { + e.print (os); + return os; + } + + class unknown_option: public exception + { + public: + virtual + ~unknown_option () throw (); + + unknown_option (const std::string& option) + : option_ (option) + { + } + + const std::string& + option () const + { + return option_; + } + + virtual void + print (std::ostream&) const; + + virtual const char* + what () const throw (); + + private: + std::string option_; + }; + + class unknown_argument: public exception + { + public: + virtual + ~unknown_argument () throw (); + + unknown_argument (const std::string& argument) + : argument_ (argument) + { + } + + const std::string& + argument () const + { + return argument_; + } + + virtual void + print (std::ostream&) const; + + virtual const char* + what () const throw (); + + private: + std::string argument_; + }; + + class missing_value: public exception + { + public: + virtual + ~missing_value () throw (); + + missing_value (const std::string& option) + : option_ (option) + { + } + + const std::string& + option () const + { + return option_; + } + + virtual void + print (std::ostream&) const; + + virtual const char* + what () const throw (); + + private: + std::string option_; + }; + + class invalid_value: public exception + { + public: + virtual + ~invalid_value () throw (); + + invalid_value (const std::string& option, + const std::string& value) + : option_ (option), value_ (value) + { + } + + const std::string& + option () const + { + return option_; + } + + const std::string& + value () const + { + return value_; + } + + virtual void + print (std::ostream&) const; + + virtual const char* + what () const throw (); + + private: + std::string option_; + std::string value_; + }; +} + +#include <string> + +#include <vector> + +class options +{ + public: + + options (int argc, + char** argv, + ::cli::unknown_mode option = ::cli::unknown_mode::fail, + ::cli::unknown_mode argument = ::cli::unknown_mode::stop); + + options (int start, + int argc, + char** argv, + ::cli::unknown_mode option = ::cli::unknown_mode::fail, + ::cli::unknown_mode argument = ::cli::unknown_mode::stop); + + options (int argc, + char** argv, + int& end, + ::cli::unknown_mode option = ::cli::unknown_mode::fail, + ::cli::unknown_mode argument = ::cli::unknown_mode::stop); + + options (int start, + int argc, + char** argv, + int& end, + ::cli::unknown_mode option = ::cli::unknown_mode::fail, + ::cli::unknown_mode argument = ::cli::unknown_mode::stop); + + // Option accessors. + // + public: + + bool const& + help () const; + + bool const& + version () const; + + std::string const& + output_dir () const; + + private: + int + _parse (int start, + int argc, + char** argv, + ::cli::unknown_mode option, + ::cli::unknown_mode argument); + + public: + bool help_; + bool version_; + std::string output_dir_; +}; + +#endif // OPTIONS_HXX |