From 3e10322425fa0a3cf6e125bc6f9d833b015cc9b5 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 14 Sep 2010 10:52:55 +0200 Subject: Implement the --cli-namespace option --- NEWS | 3 ++ cli/context.cxx | 53 ++++++++++++++++++++++++++ cli/context.hxx | 11 ++++++ cli/header.cxx | 6 +-- cli/options.cli | 11 +++++- cli/options.cxx | 101 +++++++++++++++++++++---------------------------- cli/options.hxx | 4 ++ cli/options.ixx | 6 +++ cli/runtime-header.cxx | 5 +-- cli/runtime-inline.cxx | 5 +-- cli/runtime-source.cxx | 5 +-- cli/source.cxx | 34 ++++++++--------- 12 files changed, 157 insertions(+), 87 deletions(-) diff --git a/NEWS b/NEWS index dfeb3e2..dc3ce70 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,9 @@ Version 1.2.0 * New option, --generate-specifier, triggers the generation of functions for determining whether the option was specified on the command line. + * New option, --cli-namespace, allows changing of the namespace for the + generated CLI support types. + * The argv_file_scanner now supports double and single-quoting option values in option files. This is useful to preserve leading and trailing whitespaces as well as to specify empty values. diff --git a/cli/context.cxx b/cli/context.cxx index a740374..8d5cba3 100644 --- a/cli/context.cxx +++ b/cli/context.cxx @@ -105,12 +105,18 @@ context (ostream& os_, inl (data_->inl_), opt_prefix (options.option_prefix ()), opt_sep (options.option_separator ()), + cli (data_->cli_), reserved_name_map (options.reserved_name ()), keyword_set (data_->keyword_set_) { if (!options.suppress_inline ()) data_->inl_ = "inline "; + data_->cli_ = options.cli_namespace (); + + if (!cli.empty () && cli[0] != ':') + data_->cli_ = "::" + data_->cli_; + for (size_t i (0); i < sizeof (keywords) / sizeof (char*); ++i) data_->keyword_set_.insert (keywords[i]); } @@ -127,6 +133,7 @@ context (context& c) inl (c.inl), opt_prefix (c.opt_prefix), opt_sep (c.opt_sep), + cli (c.cli), reserved_name_map (c.reserved_name_map), keyword_set (c.keyword_set) { @@ -614,6 +621,52 @@ fq_name (semantics::nameable& n, bool cxx_name) return r; } +void context:: +cli_open () +{ + string::size_type b (0), e; + + do + { + e = cli.find ("::", b); + string n (cli, b, e == string::npos ? e : e - b); + + if (!n.empty ()) + os << "namespace " << n << "{"; + + b = e; + + if (b == string::npos) + break; + + b += 2; + + } while (true); +} + +void context:: +cli_close () +{ + string::size_type b (0), e; + + do + { + e = cli.find ("::", b); + string n (cli, b, e == string::npos ? e : e - b); + + if (!n.empty ()) + os << "}"; + + b = e; + + if (b == string::npos) + break; + + b += 2; + + } while (true); +} + // namespace // diff --git a/cli/context.hxx b/cli/context.hxx index 1f2625d..ed0e058 100644 --- a/cli/context.hxx +++ b/cli/context.hxx @@ -45,6 +45,7 @@ public: string const& inl; string const& opt_prefix; string const& opt_sep; + string const& cli; typedef std::map reserved_name_map_type; reserved_name_map_type const& reserved_name_map; @@ -56,6 +57,7 @@ private: struct data { string inl_; + string cli_; keyword_set_type keyword_set_; }; @@ -116,6 +118,15 @@ public: string fq_name (semantics::nameable& n, bool cxx_name = true); + // Open/close cli namespace. + // +public: + void + cli_open (); + + void + cli_close (); + public: context (std::ostream&, semantics::cli_unit&, options_type const&); diff --git a/cli/header.cxx b/cli/header.cxx index e43c0af..7905b22 100644 --- a/cli/header.cxx +++ b/cli/header.cxx @@ -88,7 +88,7 @@ namespace // c-tors // - string um ("::cli::unknown_mode"); + string um (cli + "::unknown_mode"); os << name << " (int& argc," << endl << "char** argv," << endl @@ -122,7 +122,7 @@ namespace << um << " argument = " << um << "::stop);" << endl; - os << name << " (::cli::scanner&," << endl + os << name << " (" << cli << "::scanner&," << endl << um << " option = " << um << "::fail," << endl << um << " argument = " << um << "::stop);" << endl; @@ -150,7 +150,7 @@ namespace // os << "private:" << endl << "void" << endl - << "_parse (::cli::scanner&," << endl + << "_parse (" << cli << "::scanner&," << endl << um << " option," << endl << um << " argument);" << endl; diff --git a/cli/options.cli b/cli/options.cli index 896a1a0..8955e08 100644 --- a/cli/options.cli +++ b/cli/options.cli @@ -67,6 +67,15 @@ class options files, and would like their usage to have the same indentation level." }; + std::string --cli-namespace = "::cli" + { + "" + "Generate the CLI support types in the namespace (\cb{cli} by + default). The namespace can be nested, for example \cb{details::cli}. + If the namespace is empty, then the support types are generated in + the global namespace." + }; + bool --generate-cxx { "Generate C++ code. If neither \cb{--generate-man} nor \cb{--generate-html} @@ -225,6 +234,6 @@ class options the same set of options in the same order on the command line at the point where the \cb{--options-file} option is specified except that the shell escaping and quoting is not required. Repeat this option - to specify more than one options files." + to specify more than one options file." }; }; diff --git a/cli/options.cxx b/cli/options.cxx index 1c46fd4..6a14702 100644 --- a/cli/options.cxx +++ b/cli/options.cxx @@ -425,7 +425,8 @@ namespace cli parse (std::vector& c, scanner& s) { X x; - parser::parse (x, s); + bool dummy; + parser::parse (x, dummy, s); c.push_back (x); } }; @@ -437,7 +438,8 @@ namespace cli parse (std::set& c, scanner& s) { X x; - parser::parse (x, s); + bool dummy; + parser::parse (x, dummy, s); c.insert (x); } }; @@ -530,6 +532,7 @@ options (int& argc, suppress_usage_ (), long_usage_ (), option_length_ (0), + cli_namespace_ ("::cli"), generate_cxx_ (), generate_man_ (), generate_html_ (), @@ -573,6 +576,7 @@ options (int start, suppress_usage_ (), long_usage_ (), option_length_ (0), + cli_namespace_ ("::cli"), generate_cxx_ (), generate_man_ (), generate_html_ (), @@ -616,6 +620,7 @@ options (int& argc, suppress_usage_ (), long_usage_ (), option_length_ (0), + cli_namespace_ ("::cli"), generate_cxx_ (), generate_man_ (), generate_html_ (), @@ -661,6 +666,7 @@ options (int start, suppress_usage_ (), long_usage_ (), option_length_ (0), + cli_namespace_ ("::cli"), generate_cxx_ (), generate_man_ (), generate_html_ (), @@ -702,6 +708,7 @@ options (::cli::scanner& s, suppress_usage_ (), long_usage_ (), option_length_ (0), + cli_namespace_ ("::cli"), generate_cxx_ (), generate_man_ (), generate_html_ (), @@ -730,91 +737,69 @@ options (::cli::scanner& s, void options:: print_usage (::std::ostream& os) { - os << "--help Print usage information and exit." << ::std::endl; + os << "--help Print usage information and exit." << ::std::endl; - os << "--version Print version and exit." << ::std::endl; + os << "--version Print version and exit." << ::std::endl; - os << "--output-dir|-o Write the generated files to instead of the" << ::std::endl - << " current directory." << ::std::endl; + os << "--output-dir|-o Write the generated files to instead of the current directory." << ::std::endl; - os << "--generate-modifier Generate option value modifiers in addition to" << ::std::endl - << " accessors." << ::std::endl; + os << "--generate-modifier Generate option value modifiers in addition to accessors." << ::std::endl; - os << "--generate-specifier Generate functions for determining whether the" << ::std::endl - << " option was specified on the command line." << ::std::endl; + os << "--generate-specifier Generate functions for determining whether the option was specified on the command line." << ::std::endl; - os << "--generate-file-scanner Generate the 'argv_file_scanner' implementation." << ::std::endl; + os << "--generate-file-scanner Generate the 'argv_file_scanner' implementation." << ::std::endl; - os << "--suppress-inline Generate all functions non-inline." << ::std::endl; + os << "--suppress-inline Generate all functions non-inline." << ::std::endl; - os << "--suppress-usage Suppress the generation of the usage printing code." << ::std::endl; + os << "--suppress-usage Suppress the generation of the usage printing code." << ::std::endl; - os << "--long-usage If no short documentation string is provided, use" << ::std::endl - << " the complete long documentation string in usage." << ::std::endl; + os << "--long-usage If no short documentation string is provided, use the complete long documentation string in usage." << ::std::endl; - os << "--option-length Indent option descriptions characters when" << ::std::endl - << " printing usage." << ::std::endl; + os << "--option-length Indent option descriptions characters when printing usage." << ::std::endl; - os << "--generate-cxx Generate C++ code." << ::std::endl; + os << "--cli-namespace Generate the CLI support types in the namespace ('cli' by default). The namespace can be nested, for example 'details::cli'. If the namespace is empty, then the support types are generated in the global namespace." << std::endl; - os << "--generate-man Generate documentation in the man page format." << ::std::endl; + os << "--generate-cxx Generate C++ code." << ::std::endl; - os << "--generate-html Generate documentation in the HTML format." << ::std::endl; + os << "--generate-man Generate documentation in the man page format." << ::std::endl; - os << "--man-prologue Insert the content of at the beginning of" << ::std::endl - << " the man page file." << ::std::endl; + os << "--generate-html Generate documentation in the HTML format." << ::std::endl; - os << "--man-epilogue Insert the content of at the end of the man" << ::std::endl - << " page file." << ::std::endl; + os << "--man-prologue Insert the content of at the beginning of the man page file." << ::std::endl; - os << "--html-prologue Insert the content of at the beginning of" << ::std::endl - << " the HTML file." << ::std::endl; + os << "--man-epilogue Insert the content of at the end of the man page file." << ::std::endl; - os << "--html-epilogue Insert the content of at the end of the HTML" << ::std::endl - << " file." << ::std::endl; + os << "--html-prologue Insert the content of at the beginning of the HTML file." << ::std::endl; - os << "--class Generate the man page or HTML documentation only" << ::std::endl - << " for the options class." << ::std::endl; + os << "--html-epilogue Insert the content of at the end of the HTML file." << ::std::endl; - os << "--stdout Write output to STDOUT instead of a file." << ::std::endl; + os << "--class Generate the man page or HTML documentation only for the options class." << ::std::endl; - os << "--hxx-suffix Use instead of the default '.hxx' to" << ::std::endl - << " construct the name of the generated header file." << ::std::endl; + os << "--stdout Write output to STDOUT instead of a file." << ::std::endl; - os << "--ixx-suffix Use instead of the default '.ixx' to" << ::std::endl - << " construct the name of the generated inline file." << ::std::endl; + os << "--hxx-suffix Use instead of the default '.hxx' to construct the name of the generated header file." << ::std::endl; - os << "--cxx-suffix Use instead of the default '.cxx' to" << ::std::endl - << " construct the name of the generated source file." << ::std::endl; + os << "--ixx-suffix Use instead of the default '.ixx' to construct the name of the generated inline file." << ::std::endl; - os << "--man-suffix Use instead of the default '.1' to" << ::std::endl - << " construct the name of the generated man page file." << ::std::endl; + os << "--cxx-suffix Use instead of the default '.cxx' to construct the name of the generated source file." << ::std::endl; - os << "--html-suffix Use instead of the default '.html' to" << ::std::endl - << " construct the name of the generated HTML file." << ::std::endl; + os << "--man-suffix Use instead of the default '.1' to construct the name of the generated man page file." << ::std::endl; - os << "--option-prefix Use instead of the default '-' as an" << ::std::endl - << " option prefix." << ::std::endl; + os << "--html-suffix Use instead of the default '.html' to construct the name of the generated HTML file." << ::std::endl; - os << "--option-separator Use instead of the default '--' as an" << ::std::endl - << " optional separator between options and arguments." << ::std::endl; + os << "--option-prefix Use instead of the default '-' as an option prefix." << ::std::endl; - os << "--include-with-brackets Use angle brackets (<>) instead of quotes (\"\") in" << ::std::endl - << " the generated '#include' directives." << ::std::endl; + os << "--option-separator Use instead of the default '--' as an optional separator between options and arguments." << ::std::endl; - os << "--include-prefix Add to the generated '#include' directive" << ::std::endl - << " paths." << ::std::endl; + os << "--include-with-brackets Use angle brackets (<>) instead of quotes (\"\") in the generated '#include' directives." << ::std::endl; - os << "--guard-prefix Add to the generated header inclusion" << ::std::endl - << " guards." << ::std::endl; + os << "--include-prefix Add to the generated '#include' directive paths." << ::std::endl; - os << "--reserved-name = Add with an optional replacement to" << ::std::endl - << " the list of names that should not be used as" << ::std::endl - << " identifiers." << ::std::endl; + os << "--guard-prefix Add to the generated header inclusion guards." << ::std::endl; - os << "--options-file Read additional options from with each" << ::std::endl - << " option appearing on a separate line optionally" << ::std::endl - << " followed by space and an option value." << ::std::endl; + os << "--reserved-name = Add with an optional replacement to the list of names that should not be used as identifiers." << ::std::endl; + + os << "--options-file Read additional options from with each option appearing on a separate line optionally followed by space and an option value." << ::std::endl; } typedef @@ -849,6 +834,8 @@ struct _cli_options_map_init &::cli::thunk< options, bool, &options::long_usage_ >; _cli_options_map_["--option-length"] = &::cli::thunk< options, std::size_t, &options::option_length_ >; + _cli_options_map_["--cli-namespace"] = + &::cli::thunk< options, std::string, &options::cli_namespace_ >; _cli_options_map_["--generate-cxx"] = &::cli::thunk< options, bool, &options::generate_cxx_ >; _cli_options_map_["--generate-man"] = diff --git a/cli/options.hxx b/cli/options.hxx index 2c60c83..5c5e1bb 100644 --- a/cli/options.hxx +++ b/cli/options.hxx @@ -350,6 +350,9 @@ class options const std::size_t& option_length () const; + const std::string& + cli_namespace () const; + const bool& generate_cxx () const; @@ -435,6 +438,7 @@ class options bool suppress_usage_; bool long_usage_; std::size_t option_length_; + std::string cli_namespace_; bool generate_cxx_; bool generate_man_; bool generate_html_; diff --git a/cli/options.ixx b/cli/options.ixx index 4a5b17e..f79d75e 100644 --- a/cli/options.ixx +++ b/cli/options.ixx @@ -221,6 +221,12 @@ option_length () const return this->option_length_; } +inline const std::string& options:: +cli_namespace () const +{ + return this->cli_namespace_; +} + inline const bool& options:: generate_cxx () const { diff --git a/cli/runtime-header.cxx b/cli/runtime-header.cxx index 5a2905c..99da036 100644 --- a/cli/runtime-header.cxx +++ b/cli/runtime-header.cxx @@ -20,8 +20,7 @@ generate_runtime_header (context& ctx) << "#include " << endl << endl; - os << "namespace cli" - << "{"; + ctx.cli_open (); // unknown_mode // @@ -300,5 +299,5 @@ generate_runtime_header (context& ctx) os << "};"; } - os << "}"; // namespace cli + ctx.cli_close (); } diff --git a/cli/runtime-inline.cxx b/cli/runtime-inline.cxx index da2decf..753e86b 100644 --- a/cli/runtime-inline.cxx +++ b/cli/runtime-inline.cxx @@ -13,8 +13,7 @@ generate_runtime_inline (context& ctx) ostream& os (ctx.os); string const& inl (ctx.inl); - os << "namespace cli" - << "{"; + ctx.cli_open (); // unknown_mode // @@ -212,5 +211,5 @@ generate_runtime_inline (context& ctx) << "}"; } - os << "}"; // namespace cli + ctx.cli_close (); } diff --git a/cli/runtime-source.cxx b/cli/runtime-source.cxx index 35ee265..c76b745 100644 --- a/cli/runtime-source.cxx +++ b/cli/runtime-source.cxx @@ -25,8 +25,7 @@ generate_runtime_source (context& ctx) os << endl; - os << "namespace cli" - << "{"; + ctx.cli_open (); // unknown_option // @@ -596,5 +595,5 @@ generate_runtime_source (context& ctx) << "parser::parse (x.*M, x.*S, s);" << "}"; - os << "}"; // namespace cli + ctx.cli_close (); } diff --git a/cli/source.cxx b/cli/source.cxx index c9273f4..f68f2d3 100644 --- a/cli/source.cxx +++ b/cli/source.cxx @@ -89,7 +89,7 @@ namespace for (names::name_iterator i (n.name_begin ()); i != n.name_end (); ++i) { os << "_cli_" << scope << "_map_[\"" << *i << "\"] = " << endl - << "&::cli::thunk< " << scope << ", " << type << ", " << + << "&" << cli << "::thunk< " << scope << ", " << type << ", " << "&" << scope << "::" << member; if (specifier && type != "bool") @@ -368,7 +368,7 @@ namespace // c-tors // - string um ("::cli::unknown_mode"); + string um (cli + "::unknown_mode"); os << name << "::" << endl << name << " (int& argc," << endl @@ -382,7 +382,7 @@ namespace names (c, names_init); } os << "{" - << "::cli::argv_scanner s (argc, argv, erase);" + << cli << "::argv_scanner s (argc, argv, erase);" << "_parse (s, opt, arg);" << "}"; @@ -399,7 +399,7 @@ namespace names (c, names_init); } os << "{" - << "::cli::argv_scanner s (start, argc, argv, erase);" + << cli << "::argv_scanner s (start, argc, argv, erase);" << "_parse (s, opt, arg);" << "}"; @@ -416,7 +416,7 @@ namespace names (c, names_init); } os << "{" - << "::cli::argv_scanner s (argc, argv, erase);" + << cli << "::argv_scanner s (argc, argv, erase);" << "_parse (s, opt, arg);" << "end = s.end ();" << "}"; @@ -435,13 +435,13 @@ namespace names (c, names_init); } os << "{" - << "::cli::argv_scanner s (start, argc, argv, erase);" + << cli << "::argv_scanner s (start, argc, argv, erase);" << "_parse (s, opt, arg);" << "end = s.end ();" << "}"; os << name << "::" << endl - << name << " (::cli::scanner& s," << endl + << name << " (" << cli << "::scanner& s," << endl << um << " opt," << endl << um << " arg)"; { @@ -503,7 +503,7 @@ namespace os << "typedef" << endl << "std::map" << endl + name << "&, " << cli << "::scanner&)>" << endl << map << ";" << endl << "static " << map << " " << map << "_;" @@ -524,7 +524,7 @@ namespace bool sep (!opt_sep.empty ()); os << "void " << name << "::" << endl - << "_parse (::cli::scanner& s," << endl + << "_parse (" << cli << "::scanner& s," << endl << um << " opt_mode," << endl << um << " arg_mode)" << "{"; @@ -572,18 +572,18 @@ namespace << "{" << "switch (opt_mode)" << "{" - << "case ::cli::unknown_mode::skip:" << endl + << "case " << cli << "::unknown_mode::skip:" << endl << "{" << "s.skip ();" << "continue;" << "}" - << "case ::cli::unknown_mode::stop:" << endl + << "case " << cli << "::unknown_mode::stop:" << endl << "{" << "break;" << "}" - << "case ::cli::unknown_mode::fail:" << endl + << "case " << cli << "::unknown_mode::fail:" << endl << "{" - << "throw ::cli::unknown_option (o);" + << "throw " << cli << "::unknown_option (o);" << "}" << "}" // switch << "break;" // The stop case. @@ -596,18 +596,18 @@ namespace << "{" << "switch (arg_mode)" << "{" - << "case ::cli::unknown_mode::skip:" << endl + << "case " << cli << "::unknown_mode::skip:" << endl << "{" << "s.skip ();" << "continue;" << "}" - << "case ::cli::unknown_mode::stop:" << endl + << "case " << cli << "::unknown_mode::stop:" << endl << "{" << "break;" << "}" - << "case ::cli::unknown_mode::fail:" << endl + << "case " << cli << "::unknown_mode::fail:" << endl << "{" - << "throw ::cli::unknown_argument (o);" + << "throw " << cli << "::unknown_argument (o);" << "}" << "}" // switch << "break;" // The stop case. -- cgit v1.1