diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2010-11-19 10:12:22 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2010-11-19 10:12:22 +0200 |
commit | 0b4fcbeae101f2a5171217f65bab9c6545e853ba (patch) | |
tree | d4a80d33799ba874c8ab4ff26185a9bccce9b6ce | |
parent | 89ce153311d9163bbc356927346c0b30e158a75f (diff) |
Add option description that can be examined at runtime.
New option: --generate-description.
-rw-r--r-- | cli/header.cxx | 13 | ||||
-rw-r--r-- | cli/options.cli | 5 | ||||
-rw-r--r-- | cli/options.cxx | 10 | ||||
-rw-r--r-- | cli/options.hxx | 4 | ||||
-rw-r--r-- | cli/options.ixx | 6 | ||||
-rw-r--r-- | cli/runtime-header.cxx | 57 | ||||
-rw-r--r-- | cli/runtime-inline.cxx | 54 | ||||
-rw-r--r-- | cli/runtime-source.cxx | 19 | ||||
-rw-r--r-- | cli/source.cxx | 109 |
9 files changed, 273 insertions, 4 deletions
diff --git a/cli/header.cxx b/cli/header.cxx index 7905b22..d1b078f 100644 --- a/cli/header.cxx +++ b/cli/header.cxx @@ -135,7 +135,7 @@ namespace names (c, names_option_); - // usage + // Usage. // if (usage) { @@ -146,6 +146,17 @@ namespace << endl; } + // Description. + // + if (options.generate_description ()) + { + os << "// Option description." << endl + << "//" << endl + << "static const " << cli << "::options&" << endl + << "description ();" + << endl; + } + // _parse() // os << "private:" << endl diff --git a/cli/options.cli b/cli/options.cli index ccafa68..a1cc3b4 100644 --- a/cli/options.cli +++ b/cli/options.cli @@ -34,6 +34,11 @@ class options on the command line." }; + bool --generate-description + { + "Generate the option description list that can be examined at runtime." + }; + bool --generate-file-scanner { "Generate the \c{argv_file_scanner} implementation. This scanner is diff --git a/cli/options.cxx b/cli/options.cxx index 093fd55..c8a83df 100644 --- a/cli/options.cxx +++ b/cli/options.cxx @@ -527,6 +527,7 @@ options (int& argc, output_dir_ (), generate_modifier_ (), generate_specifier_ (), + generate_description_ (), generate_file_scanner_ (), suppress_inline_ (), suppress_undocumented_ (), @@ -572,6 +573,7 @@ options (int start, output_dir_ (), generate_modifier_ (), generate_specifier_ (), + generate_description_ (), generate_file_scanner_ (), suppress_inline_ (), suppress_undocumented_ (), @@ -617,6 +619,7 @@ options (int& argc, output_dir_ (), generate_modifier_ (), generate_specifier_ (), + generate_description_ (), generate_file_scanner_ (), suppress_inline_ (), suppress_undocumented_ (), @@ -664,6 +667,7 @@ options (int start, output_dir_ (), generate_modifier_ (), generate_specifier_ (), + generate_description_ (), generate_file_scanner_ (), suppress_inline_ (), suppress_undocumented_ (), @@ -707,6 +711,7 @@ options (::cli::scanner& s, output_dir_ (), generate_modifier_ (), generate_specifier_ (), + generate_description_ (), generate_file_scanner_ (), suppress_inline_ (), suppress_undocumented_ (), @@ -755,6 +760,9 @@ print_usage (::std::ostream& os) os << "--generate-specifier Generate functions for determining whether the" << ::std::endl << " option was specified on the command line." << ::std::endl; + os << "--generate-description Generate the option description list that can be" << ::std::endl + << " examined at runtime." << ::std::endl; + os << "--generate-file-scanner Generate the 'argv_file_scanner' implementation." << ::std::endl; os << "--suppress-inline Generate all functions non-inline." << ::std::endl; @@ -857,6 +865,8 @@ struct _cli_options_map_init &::cli::thunk< options, bool, &options::generate_modifier_ >; _cli_options_map_["--generate-specifier"] = &::cli::thunk< options, bool, &options::generate_specifier_ >; + _cli_options_map_["--generate-description"] = + &::cli::thunk< options, bool, &options::generate_description_ >; _cli_options_map_["--generate-file-scanner"] = &::cli::thunk< options, bool, &options::generate_file_scanner_ >; _cli_options_map_["--suppress-inline"] = diff --git a/cli/options.hxx b/cli/options.hxx index d8a880d..a7a7094 100644 --- a/cli/options.hxx +++ b/cli/options.hxx @@ -336,6 +336,9 @@ class options generate_specifier () const; const bool& + generate_description () const; + + const bool& generate_file_scanner () const; const bool& @@ -436,6 +439,7 @@ class options std::string output_dir_; bool generate_modifier_; bool generate_specifier_; + bool generate_description_; bool generate_file_scanner_; bool suppress_inline_; bool suppress_undocumented_; diff --git a/cli/options.ixx b/cli/options.ixx index 9c9afda..f2072fe 100644 --- a/cli/options.ixx +++ b/cli/options.ixx @@ -192,6 +192,12 @@ generate_specifier () const } inline const bool& options:: +generate_description () const +{ + return this->generate_description_; +} + +inline const bool& options:: generate_file_scanner () const { return this->generate_file_scanner_; diff --git a/cli/runtime-header.cxx b/cli/runtime-header.cxx index 99da036..de24073 100644 --- a/cli/runtime-header.cxx +++ b/cli/runtime-header.cxx @@ -15,6 +15,10 @@ generate_runtime_header (context& ctx) if (ctx.options.generate_file_scanner ()) os << "#include <deque>" << endl; + if (ctx.options.generate_description ()) + os << "#include <map>" << endl + << "#include <vector>" << endl; + os << "#include <iosfwd>" << endl << "#include <string>" << endl << "#include <exception>" << endl @@ -299,5 +303,58 @@ generate_runtime_header (context& ctx) os << "};"; } + // Option description. + // + if (ctx.options.generate_description ()) + { + os << "typedef std::vector<std::string> option_names;" + << endl; + + os << "class option" + << "{" + << "public:" << endl + << endl + << "const std::string&" << endl + << "name () const;" + << endl + << "const option_names&" << endl + << "aliases () const;" + << endl + << "bool" << endl + << "flag () const;" + << endl + << "const std::string&" << endl + << "default_value () const;" + << endl + << "public:" + << "option ();" + << "option (const std::string& name," << endl + << "const option_names& aliases," << endl + << "bool flag," << endl + << "const std::string& default_value);" + << endl + << "private:" + << "std::string name_;" + << "option_names aliases_;" + << "bool flag_;" + << "std::string default_value_;" + << "};"; + + os << "class options: public std::vector<option>" + << "{" + << "public:" << endl + << "typedef std::vector<option> container_type;" + << endl + << "container_type::const_iterator" << endl + << "find (const std::string& name) const;" + << endl + << "void" << endl + << "push_back (const option&);" + << "private:" + << "typedef std::map<std::string, container_type::size_type> map_type;" + << "map_type map_;" + << "};"; + } + ctx.cli_close (); } diff --git a/cli/runtime-inline.cxx b/cli/runtime-inline.cxx index 753e86b..fecbd02 100644 --- a/cli/runtime-inline.cxx +++ b/cli/runtime-inline.cxx @@ -211,5 +211,59 @@ generate_runtime_inline (context& ctx) << "}"; } + // Option description. + // + if (ctx.options.generate_description ()) + { + // option + // + os << inl << "const std::string& option::" << endl + << "name () const" + << "{" + << "return name_;" + << "}"; + + os << inl << "const option_names& option::" << endl + << "aliases () const" + << "{" + << "return aliases_;" + << "}"; + + os << inl << "bool option::" << endl + << "flag () const" + << "{" + << "return flag_;" + << "}"; + + os << inl << "const std::string& option::" << endl + << "default_value () const" + << "{" + << "return default_value_;" + << "}"; + + os << inl << "option::" << endl + << "option ()" + << "{" + << "}"; + + os << inl << "option::" << endl + << "option (const std::string& n," << endl + << "const option_names& a," << endl + << "bool f," << endl + << "const std::string& dv)" << endl + << ": name_ (n), aliases_ (a), flag_ (f), default_value_ (dv)" + << "{" + << "}"; + + // options + // + os << inl << "options::container_type::const_iterator options::" << endl + << "find (const std::string& name) const" + << "{" + << "map_type::const_iterator i (map_.find (name));" + << "return i != map_.end () ? begin () + i->second : end ();" + << "}"; + } + ctx.cli_close (); } diff --git a/cli/runtime-source.cxx b/cli/runtime-source.cxx index c76b745..7ccf404 100644 --- a/cli/runtime-source.cxx +++ b/cli/runtime-source.cxx @@ -412,6 +412,25 @@ generate_runtime_source (context& ctx) << "}"; } + // Option description. + // + if (ctx.options.generate_description ()) + { + // options + // + os << "void options::" << endl + << "push_back (const option& o)" + << "{" + << "container_type::size_type n (size ());" + << "container_type::push_back (o);" + << "map_[o.name ()] = n;" + << endl + << "for (option_names::const_iterator i (o.aliases ().begin ());" << endl + << "i != o.aliases ().end (); ++i)" << endl + << "map_[*i] = n;" + << "}"; + } + bool sp (ctx.specifier); // parser class template & its specializations diff --git a/cli/source.cxx b/cli/source.cxx index 7d85859..b6f4234 100644 --- a/cli/source.cxx +++ b/cli/source.cxx @@ -103,6 +103,75 @@ namespace // // + struct option_desc: traversal::option, context + { + option_desc (context& c) : context (c) {} + + virtual void + traverse (type& o) + { + using semantics::names; + + names& n (o.named ()); + + os << "// " << o.name () << endl + << "//" << endl + << "{" + << cli << "::option_names a;"; + + for (names::name_iterator b (n.name_begin ()), i (b); + i != n.name_end (); ++i) + { + if (i == b) // Skip the primary name. + continue; + + os << "a.push_back (\"" << *i << "\");"; + } + + if (o.initialized_p ()) + { + using semantics::expression; + expression const& i (o.initializer ()); + + switch (i.type ()) + { + case expression::string_lit: + { + os << "std::string dv (" << i.value () << ");"; + break; + } + case expression::char_lit: + { + os << "std::string dv (1, " << i.value () << ");"; + break; + } + case expression::bool_lit: + case expression::int_lit: + case expression::float_lit: + { + os << "std::string dv (\"" << i.value () << "\");"; + } + case expression::identifier: + case expression::call_expr: + { + os << "std::string dv;"; + break; + } + } + } + else + os << "std::string dv;"; + + + os << cli << "::option o (\"" << o.name () << "\", a, " << + (o.type ().name () == "bool" ? "true" : "false") << ", dv);" + << "os.push_back (o);" + << "}"; + } + }; + + // + // struct option_length: traversal::option, context { option_length (context& c, size_t& l, type*& o) @@ -358,9 +427,10 @@ namespace struct class_: traversal::class_, context { class_ (context& c) - : context (c), option_map_ (c) + : context (c), option_map_ (c), option_desc_ (c) { names_option_map_ >> option_map_; + names_option_desc_ >> option_desc_; } virtual void @@ -460,7 +530,7 @@ namespace << "_parse (s, opt, arg);" << "}"; - // usage + // Usage. // if (usage) { @@ -504,6 +574,35 @@ namespace os << "}"; } + // Description. + // + if (options.generate_description ()) + { + string desc ("_cli_" + name + "_desc"); + + os << "static " << cli << "::options " << desc << "_;" + << endl; + + os << "struct " << desc << "_init" + << "{" + << desc << "_init (" << cli << "::options& os)" + << "{"; + + names (c, names_option_desc_); + + os << "}" + << "};" + << "static " << desc << "_init " << desc << "_init_ (" << + desc << "_);" + << endl; + + os << "const " << cli << "::options& " << name << "::" << endl + << "description ()" + << "{" + << "return " << desc << "_;" + << "};"; + } + // _parse() // string map ("_cli_" + name + "_map"); @@ -524,7 +623,8 @@ namespace names (c, names_option_map_); os << "}" - << "} " << map << "_init_;" + << "};" + << "static " << map << "_init " << map << "_init_;" << endl; bool pfx (!opt_prefix.empty ()); @@ -627,6 +727,9 @@ namespace private: option_map option_map_; traversal::names names_option_map_; + + option_desc option_desc_; + traversal::names names_option_desc_; }; } |