diff options
Diffstat (limited to 'cli')
-rw-r--r-- | cli/NEWS | 17 | ||||
-rw-r--r-- | cli/build/root.build | 11 | ||||
-rw-r--r-- | cli/cli/.gitignore | 2 | ||||
-rw-r--r-- | cli/cli/buildfile | 145 | ||||
-rw-r--r-- | cli/cli/cli.cxx | 8 | ||||
-rw-r--r-- | cli/cli/context.cxx | 75 | ||||
-rw-r--r-- | cli/cli/context.hxx | 4 | ||||
-rw-r--r-- | cli/cli/generator.cxx | 144 | ||||
-rw-r--r-- | cli/cli/generator.hxx | 7 | ||||
-rw-r--r-- | cli/cli/header.cxx | 6 | ||||
-rw-r--r-- | cli/cli/options.cli | 33 | ||||
-rw-r--r-- | cli/cli/parser.cxx | 33 | ||||
-rw-r--r-- | cli/cli/parser.hxx | 21 | ||||
-rw-r--r-- | cli/cli/parser.test.cxx | 2 | ||||
-rw-r--r-- | cli/cli/pregenerated/cli/options.cxx (renamed from cli/cli/bootstrap/cli/options.cxx) | 214 | ||||
-rw-r--r-- | cli/cli/pregenerated/cli/options.hxx (renamed from cli/cli/bootstrap/cli/options.hxx) | 61 | ||||
-rw-r--r-- | cli/cli/pregenerated/cli/options.ixx (renamed from cli/cli/bootstrap/cli/options.ixx) | 108 | ||||
-rw-r--r-- | cli/cli/runtime-header.cxx | 81 | ||||
-rw-r--r-- | cli/cli/runtime-source.cxx | 146 | ||||
-rw-r--r-- | cli/cli/source.cxx | 9 | ||||
-rw-r--r-- | cli/doc/.gitignore | 6 | ||||
-rw-r--r-- | cli/doc/buildfile | 236 | ||||
-rw-r--r-- | cli/doc/cli-guide.xhtml | 6 | ||||
-rw-r--r-- | cli/doc/pregenerated/cli.1 (renamed from cli/doc/bootstrap/cli.1) | 24 | ||||
-rw-r--r-- | cli/doc/pregenerated/cli.xhtml (renamed from cli/doc/bootstrap/cli.xhtml) | 34 | ||||
-rw-r--r-- | cli/manifest | 6 |
26 files changed, 1124 insertions, 315 deletions
@@ -4,8 +4,8 @@ Version 1.2.0 function which can be used to merge several already parsed options class instances, for example, to implement option appending/overriding. - * New option, --generate-specifier, triggers the generation of functions - for determining whether the option was specified on the command line. + * New option, --generate-specifier, triggers the generation of functions for + determining whether the option was specified on the command line. * New option, --suppress-undocumented, suppresses the generation of documentation entries for undocumented options. @@ -13,12 +13,17 @@ Version 1.2.0 * 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 + * 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. - * The argv_file_scanner now supports multiple file options as well as - file search callbacks. + * The argv_file_scanner now supports multiple file options as well as file + search callbacks. + + * New option, --generate-dep, triggers the generation of the make dependency + information. Other related new options: --dep-suffix, --dep-file. + + * Support for std::multimap as an option type in addition to std::map. Version 1.1.0 diff --git a/cli/build/root.build b/cli/build/root.build index 6132356..ceeaf6c 100644 --- a/cli/build/root.build +++ b/cli/build/root.build @@ -4,10 +4,12 @@ # Note that we cannot install the development build. This is due to both the # bootstrap cli (which we need to run) and the final cli (which we need to # install) depending on libcutl (so we need it to be both "for-install" and -# "for-run"). Nor can we run the final cli to generate the man pages. +# "for-run"). Nor can we run such final cli to generate the man pages. # config [bool] config.cli.develop ?= false +develop = $config.cli.develop + define cli: file cli{*}: extension = cli @@ -34,6 +36,7 @@ test.target = $cxx.target # # Note that cat is a builtin which means this is both portable and fast. # -copyright = $process.run_regex(cat $src_root/LICENSE, \ - 'Copyright \(c\) (.+)\.', \ - '\1') +if ($build.mode != 'skeleton') + copyright = $process.run_regex(cat $src_root/LICENSE, \ + 'Copyright \(c\) (.+)\.', \ + '\1') diff --git a/cli/cli/.gitignore b/cli/cli/.gitignore index 79562f1..614e56f 100644 --- a/cli/cli/.gitignore +++ b/cli/cli/.gitignore @@ -1,5 +1,5 @@ /cli -/bootstrap/cli/cli +/pregenerated/cli/cli /version.hxx /options.?xx diff --git a/cli/cli/buildfile b/cli/cli/buildfile index dc5d75b..92c3e6e 100644 --- a/cli/cli/buildfile +++ b/cli/cli/buildfile @@ -25,91 +25,118 @@ libue{cli}: $hdr $src $all_s $all_t {hxx}{version} $libs hxx{version}: in{version} $src_root/manifest -# Build options (both bootstrap and final version). +# Build options (apply to both bootstrap and final version). # cxx.poptions =+ "-I$out_root" "-I$src_root" +# CLI uses its own generated code to handle the command line. To solve the +# chicken and egg problem that this poses we keep pregenerated source code in +# pregenerated/. +# +# In the consumption build ($config.cli.develop == false), we just use this +# pregenerated source code to build the final version of the compiler. In the +# development build ($config.cli.develop == true) we use this pregenerated +# source code to build a bootstrap version of the compiler which we then use +# to regenerate the source code and build that final version from that. + +## Consumption build ($develop == false). +# + +# Use pregenerated versions to build the final version of cli. +# +libue{cli}: pregenerated/{hxx ixx cxx}{**}: include = (!$develop) + +if! $develop + cxx.poptions =+ "-I($src_base/pregenerated)" # Note: must come first. + +# Distribute pregenerated versions only in the consumption build. +# +pregenerated/{hxx ixx cxx}{*}: dist = (!$develop) + +# +## + +## Development build ($develop == true). +# +libue{cli}: {hxx ixx cxx}{options}: include = $develop + # Bootstrap. # # The plan is as follows: # # 1. Build the bootstrap version of cli using a copy of options.?xx saved in -# bootstrap/cli/. +# pregenerated/cli/. # -# 2. Use that to re-generate options.?xx. If the result differs from the -# saved version, copy it over and fail the build, asking for a restart. +# 2. Use that to regenerate options.?xx. If the result differs from the saved +# version, copy it over and fail the build, asking for a restart. # -# 3. Otherwise, proceed to build the final version of cli. +# 3. Otherwise, proceed to build the final version of cli using regenerated +# options.?xx. # -if $config.cli.develop +pregenerated/ { - libue{cli}: {hxx ixx cxx}{options} + # This should only apply to the bootstrap build. + # + cxx.poptions =+ "-I$src_base" # Note: must come first. - bootstrap/ + cli/ { - # This should only apply to the bootstrap build. + # Note: semantics/ and traversal/ do not include options.hxx so we can + # share their object files. # - cxx.poptions =+ "-I$src_base" # Note: must come first. + exe{cli}: obj{cli $name($src) options} ../../{$all_s $all_t} $libs - cli/ - { - # Note: semantics/ and traversal/ do not include options.hxx so we can - # share their object files. - # - exe{cli}: obj{cli $name($src) options} ../../{$all_s $all_t} $libs + for s: cli $name($src) + obj{$s}: ../../cxx{$s} $libs - for s: cli $name($src) - obj{$s}: ../../cxx{$s} $libs + obj{options}: {hxx ixx cxx}{options} - obj{options}: {hxx ixx cxx}{options} - - obj{cli}: cxx.poptions += -DCLI_BOOTSTRAP - } + obj{cli}: cxx.poptions += -DCLI_BOOTSTRAP } +} - <{hxx ixx cxx}{options}>: cli{options} bootstrap/cli/exe{cli} - { - options = --include-with-brackets --include-prefix cli \ - --guard-prefix CLI --generate-file-scanner \ - --generate-specifier --generate-modifier \ - --suppress-undocumented --reserved-name stdout - - # Symlink the generated code in src for convenience of development. - # - backlink = true - } - {{ - diag cli ($<[0]) - ($<[1]) $options -o $out_base $path($<[0]) +# In the development build distribute regenerated {hxx ixx cxx}{options}, +# remapping their locations to the paths of the pregenerated versions (which +# are only distributed in the consumption build; see above). This way we make +# sure that the distributed files are always up-to-date. +# +<{hxx ixx cxx}{options}>: cli{options} pregenerated/cli/exe{cli} +{ + dist = ($develop ? pregenerated/cli/ : false) - # If the result differs from the bootstrap version, copy it over and - # request the build restart. - # - if diff $src_base/bootstrap/cli/options.hxx $path($>[0]) >- && \ - diff $src_base/bootstrap/cli/options.ixx $path($>[1]) >- && \ - diff $src_base/bootstrap/cli/options.cxx $path($>[2]) >- - exit - end - - cp $path($>[0]) $src_base/bootstrap/cli/options.hxx - cp $path($>[1]) $src_base/bootstrap/cli/options.ixx - cp $path($>[2]) $src_base/bootstrap/cli/options.cxx - - exit "bootstrap options.?xx have changed, restart the build" - }} + # Symlink the generated code in src for convenience of development. + # + backlink = true } -else -{ - # Use bootstrap options.?xx to build the final version of cli. +% +if $develop +{{ + options = --include-with-brackets --include-prefix cli \ + --guard-prefix CLI --generate-file-scanner \ + --generate-specifier --generate-modifier \ + --suppress-undocumented --reserved-name stdout + + diag cli ($<[0]) -> $> + ($<[1]) $options -o $out_base $path($<[0]) + + # If the result differs from the bootstrap version, copy it over and + # request the build restart. # - libue{cli}: bootstrap/cli/{hxx ixx cxx}{options} - cxx.poptions =+ "-I($src_base/bootstrap)" # Note: must come first. + if diff $src_base/pregenerated/cli/options.hxx $path($>[0]) >- && \ + diff $src_base/pregenerated/cli/options.ixx $path($>[1]) >- && \ + diff $src_base/pregenerated/cli/options.cxx $path($>[2]) >- + exit + end - ./: cli{options} # Keep in distribution. -} + cp $path($>[0]) $src_base/pregenerated/cli/options.hxx + cp $path($>[1]) $src_base/pregenerated/cli/options.ixx + cp $path($>[2]) $src_base/pregenerated/cli/options.cxx + + exit "bootstrap options.?xx have changed, restart the build" +}} -# Build options (final version only). # +## # Pass the copyright notice extracted from the LICENSE file. # diff --git a/cli/cli/cli.cxx b/cli/cli/cli.cxx index f1196de..d56f9e2 100644 --- a/cli/cli/cli.cxx +++ b/cli/cli/cli.cxx @@ -6,6 +6,7 @@ #include <string> #include <memory> // unique_ptr #include <fstream> +#include <utility> // move() #include <iostream> #include <libcutl/compiler/code-stream.hxx> @@ -121,8 +122,9 @@ main (int argc, char* argv[]) // Parse and generate. // - parser p (include_paths); - unique_ptr<semantics::cli_unit> unit (p.parse (ifs, path)); + parser p (include_paths, ops.generate_dep ()); + parser::parse_result r (p.parse (ifs, path)); + unique_ptr<semantics::cli_unit>& unit (r.unit); // Merge documentation variables from the command line. // @@ -143,7 +145,7 @@ main (int argc, char* argv[]) } generator g; - g.generate (ops, *unit, path); + g.generate (ops, move (*unit), move (r.dependencies), path); } catch (cli::exception const& ex) { diff --git a/cli/cli/context.cxx b/cli/cli/context.cxx index 2833861..2c6a733 100644 --- a/cli/cli/context.cxx +++ b/cli/cli/context.cxx @@ -7,6 +7,7 @@ #include <cstring> // strncmp() #include <fstream> #include <sstream> +#include <utility> // move() #include <iostream> #include <cli/context.hxx> @@ -114,6 +115,8 @@ context (ostream& os_, opt_prefix (options.option_prefix ()), opt_sep (options.option_separator ()), cli (data_->cli_), + exp (data_->exp_), + exp_inl (data_->exp_inl_), reserved_name_map (options.reserved_name ()), keyword_set (data_->keyword_set_), link_regex (data_->link_regex_), @@ -141,6 +144,16 @@ context (ostream& os_, if (!cli.empty () && cli[0] != ':') data_->cli_ = "::" + data_->cli_; + data_->exp_ = options.export_symbol (); + + if (!exp.empty ()) + { + data_->exp_ += ' '; + + if (options.suppress_inline ()) + data_->exp_inl_ = data_->exp_; + } + for (size_t i (0); i < sizeof (keywords) / sizeof (char*); ++i) data_->keyword_set_.insert (keywords[i]); @@ -179,6 +192,8 @@ context (context& c) opt_prefix (c.opt_prefix), opt_sep (c.opt_sep), cli (c.cli), + exp (c.exp), + exp_inl (c.exp_inl), reserved_name_map (c.reserved_name_map), keyword_set (c.keyword_set), link_regex (c.link_regex), @@ -1323,15 +1338,32 @@ format (semantics::scope& scope, string const& s, bool para) stack<block> blocks; blocks.push (block (block::text, para, "")); // Top-level. - // Number of li in ol. Since we don't support nested lists, we don't - // need to push it into the stack. + // Number of li in ol. Since we don't support nested lists (except in HTML + // where this is unused), we don't need to push it into the stack. // size_t ol_count (0); // Mapping of \h to HTML tag. By default it is <h1> until we encounter - // \h0 or \h1 at which point we change it to <h2>. + // \h0 or \h1 at which point we change it to <h2>. It can also be mapped + // with --html-heading-map. // - char html_h ('1'); + char html_h ('\0'); + + typedef map<char, string> html_hmap; + if (ot == ot_html) + { + const html_hmap& hm (options.html_heading_map ()); + html_hmap::const_iterator mi (hm.find ('h')); + + if (mi != hm.end ()) + { + // Note: this mapping back is necessary for TOC to function correctly + // with multiple string fragments. + // + if (mi->second == "h1") html_h = '1'; + else if (mi->second == "h2") html_h = '2'; + } + } bool last (false); for (size_t b (0), e; !last; b = e + 1) @@ -1585,7 +1617,10 @@ format (semantics::scope& scope, string const& s, bool para) case block::dl: good = (k == block::li); break; case block::li: good = (k == block::note || k == block::text || - k == block::pre ); break; + k == block::pre || + (ot == ot_html && (k == block::ul || + k == block::ol || + k == block::dl))); break; case block::note: good = (k == block::text || k == block::pre || (ot == ot_html && (k == block::ul || @@ -1697,7 +1732,7 @@ format (semantics::scope& scope, string const& s, bool para) { case block::h: blocks.push (block (k, false, id, header)); break; case block::ul: - case block::ol: ol_count = 0; // Fall through. + case block::ol: if (ot != ot_html) ol_count = 0; // Fall through. case block::dl: blocks.push (block (k, true, id)); break; case block::li: { @@ -1705,9 +1740,12 @@ format (semantics::scope& scope, string const& s, bool para) { case block::ol: { - ostringstream os; - os << ++ol_count; - header = os.str (); + if (ot != ot_html) + { + ostringstream os; + os << ++ol_count; + header = os.str (); + } break; } case block::dl: @@ -1972,7 +2010,7 @@ format (semantics::scope& scope, string const& s, bool para) case '1': break; // Always unwind. case 'h': { - pop = html_h == '1' || e.type == 'h' || e.type == '2'; + pop = html_h != '2' || e.type == 'h' || e.type == '2'; break; } case '2': pop = e.type == '2'; break; @@ -2069,9 +2107,10 @@ format (semantics::scope& scope, string const& s, bool para) // Same as in non-TOC mode below. // - // @@ This only works for a single string fragment. + // This only works automatically for a single string fragment. + // For multiple string fragments use --html-heading-map. // - if (t == '0' || t == '1') + if (html_h == '\0' && (t == '0' || t == '1')) html_h = '2'; break; @@ -2189,9 +2228,8 @@ format (semantics::scope& scope, string const& s, bool para) string h; string c; - typedef map<char, string> map; - const map& hm (options.html_heading_map ()); - map::const_iterator mi (hm.find (t)); + const html_hmap& hm (options.html_heading_map ()); + html_hmap::const_iterator mi (hm.find (t)); if (mi == hm.end ()) { @@ -2200,7 +2238,7 @@ format (semantics::scope& scope, string const& s, bool para) case '0': h = "h1"; c = "preface"; break; case 'H': h = "h1"; c = "part"; break; case '1': h = "h1"; break; - case 'h': h = html_h == '1' ? "h1" : "h2"; break; + case 'h': h = html_h != '2' ? "h1" : "h2"; break; case '2': h = "h3"; break; } } @@ -2226,9 +2264,10 @@ format (semantics::scope& scope, string const& s, bool para) v += "</" + h + '>'; - // @@ This only works for a single string fragment. + // This only works automatically for a single string fragment. + // For multiple string fragments use --html-heading-map. // - if (t == '0' || t == '1') + if (html_h == '\0' && (t == '0' || t == '1')) html_h = '2'; break; diff --git a/cli/cli/context.hxx b/cli/cli/context.hxx index 19bfa51..c5802ed 100644 --- a/cli/cli/context.hxx +++ b/cli/cli/context.hxx @@ -92,6 +92,8 @@ public: string const& opt_prefix; string const& opt_sep; string const& cli; + string const& exp; + string const& exp_inl; // Export symbol if inline is suppressed. typedef std::map<string, string> reserved_name_map_type; reserved_name_map_type const& reserved_name_map; @@ -135,6 +137,8 @@ private: { string inl_; string cli_; + string exp_; + string exp_inl_; keyword_set_type keyword_set_; regex_mapping link_regex_; id_set_type id_set_; diff --git a/cli/cli/generator.cxx b/cli/cli/generator.cxx index b4e6640..623ac67 100644 --- a/cli/cli/generator.cxx +++ b/cli/cli/generator.cxx @@ -2,9 +2,10 @@ // author : Boris Kolpackov <boris@codesynthesis.com> // license : MIT; see accompanying LICENSE file -#include <cctype> // std::toupper, std::is{alpha,upper,lower} +#include <cctype> // toupper, is{alpha,upper,lower} #include <string> #include <fstream> +#include <utility> // move() #include <iostream> #include <libcutl/fs/auto-remove.hxx> @@ -98,7 +99,10 @@ namespace } void - append (context& ctx, vector<string> const& text, string const& file) + append (context& ctx, + vector<string> const& text, + string const& file, + vector<path>* pdeps) { for (vector<string>::const_iterator i (text.begin ()); i != text.end (); ++i) @@ -111,7 +115,8 @@ namespace ifstream ifs; open (ifs, file); - path d (path (file).directory ()); + path p (file); + path d (p.directory ()); // getline() will set the failbit if it failed to extract anything, // not even the delimiter and eofbit if it reached eof before seeing @@ -119,6 +124,9 @@ namespace // for (string s; getline (ifs, s); ) append (ctx, s, &d); + + if (pdeps != nullptr) + pdeps->push_back (move (p.normalize ())); } } } @@ -129,7 +137,10 @@ generator () } void generator:: -generate (options& ops, semantics::cli_unit& unit, path const& p) +generate (options& ops, + semantics::cli_unit&& unit, + vector<path>&& deps, + path const& p) { if (ops.generate_group_scanner ()) ops.generate_vector_scanner (true); @@ -168,8 +179,48 @@ generate (options& ops, semantics::cli_unit& unit, path const& p) } } + bool gen_dep (ops.generate_dep ()); + vector<path>* pdeps (gen_dep ? &deps : nullptr); + vector<path> depts; // Dependents. + fs::auto_removes auto_rm; + // gen_dep + // + // Make sure that we remove the potentially outdated dependency file if we + // fail to generate any source/documentation file. + // + // Note that we will write the dependency file content later, when all the + // dependents and dependencies are determined. + // + ofstream dep; + + if (gen_dep) + { + path dep_path; + + if (ops.dep_file ().empty ()) + { + dep_path = path (pfx + base + sfx + ops.dep_suffix ()); + + if (!ops.output_dir ().empty ()) + dep_path = path (ops.output_dir ()) / dep_path; + } + else + dep_path = path (ops.dep_file ()); + + dep.open (dep_path.string ().c_str (), ios_base::out); + + if (!dep.is_open ()) + { + cerr << "error: unable to open '" << dep_path << "' in write mode" + << endl; + throw failed (); + } + + auto_rm.add (dep_path); + } + // C++ output. // if (gen_cxx) @@ -235,6 +286,9 @@ generate (options& ops, semantics::cli_unit& unit, path const& p) auto_rm.add (hxx_path); + if (gen_dep) + depts.push_back (move (hxx_path.normalize ())); + // // ofstream ixx; @@ -251,6 +305,9 @@ generate (options& ops, semantics::cli_unit& unit, path const& p) } auto_rm.add (ixx_path); + + if (gen_dep) + depts.push_back (move (ixx_path.normalize ())); } // @@ -266,6 +323,9 @@ generate (options& ops, semantics::cli_unit& unit, path const& p) auto_rm.add (cxx_path); + if (gen_dep) + depts.push_back (move (cxx_path.normalize ())); + // Print headers. // hxx << cxx_header; @@ -304,7 +364,7 @@ generate (options& ops, semantics::cli_unit& unit, path const& p) // hxx << "// Begin prologue." << endl << "//" << endl; - append (ctx, ops.hxx_prologue (), ops.hxx_prologue_file ()); + append (ctx, ops.hxx_prologue (), ops.hxx_prologue_file (), pdeps); hxx << "//" << endl << "// End prologue." << endl << endl; @@ -331,7 +391,7 @@ generate (options& ops, semantics::cli_unit& unit, path const& p) // hxx << "// Begin epilogue." << endl << "//" << endl; - append (ctx, ops.hxx_epilogue (), ops.hxx_epilogue_file ()); + append (ctx, ops.hxx_epilogue (), ops.hxx_epilogue_file (), pdeps); hxx << "//" << endl << "// End epilogue." << endl << endl; @@ -349,7 +409,7 @@ generate (options& ops, semantics::cli_unit& unit, path const& p) // ixx << "// Begin prologue." << endl << "//" << endl; - append (ctx, ops.ixx_prologue (), ops.ixx_prologue_file ()); + append (ctx, ops.ixx_prologue (), ops.ixx_prologue_file (), pdeps); ixx << "//" << endl << "// End prologue." << endl << endl; @@ -369,7 +429,7 @@ generate (options& ops, semantics::cli_unit& unit, path const& p) // ixx << "// Begin epilogue." << endl << "//" << endl; - append (ctx, ops.ixx_epilogue (), ops.ixx_epilogue_file ()); + append (ctx, ops.ixx_epilogue (), ops.ixx_epilogue_file (), pdeps); ixx << "//" << endl << "// End epilogue." << endl; } @@ -383,7 +443,7 @@ generate (options& ops, semantics::cli_unit& unit, path const& p) // cxx << "// Begin prologue." << endl << "//" << endl; - append (ctx, ops.cxx_prologue (), ops.cxx_prologue_file ()); + append (ctx, ops.cxx_prologue (), ops.cxx_prologue_file (), pdeps); cxx << "//" << endl << "// End prologue." << endl << endl; @@ -413,7 +473,7 @@ generate (options& ops, semantics::cli_unit& unit, path const& p) // cxx << "// Begin epilogue." << endl << "//" << endl; - append (ctx, ops.cxx_epilogue (), ops.cxx_epilogue_file ()); + append (ctx, ops.cxx_epilogue (), ops.cxx_epilogue_file (), pdeps); cxx << "//" << endl << "// End epilogue." << endl << endl; @@ -443,6 +503,9 @@ generate (options& ops, semantics::cli_unit& unit, path const& p) } auto_rm.add (man_path); + + if (gen_dep) + depts.push_back (move (man_path.normalize ())); } // The explicit cast helps VC++ 8.0 overcome its issues. @@ -452,9 +515,9 @@ generate (options& ops, semantics::cli_unit& unit, path const& p) for (bool first (true); first || ctx.toc; first = false) { - append (ctx, ops.man_prologue (), ops.man_prologue_file ()); + append (ctx, ops.man_prologue (), ops.man_prologue_file (), pdeps); generate_man (ctx); - append (ctx, ops.man_epilogue (), ops.man_epilogue_file ()); + append (ctx, ops.man_epilogue (), ops.man_epilogue_file (), pdeps); if (ctx.toc) { @@ -492,6 +555,9 @@ generate (options& ops, semantics::cli_unit& unit, path const& p) } auto_rm.add (html_path); + + if (gen_dep) + depts.push_back (move (html_path.normalize ())); } // The explicit cast helps VC++ 8.0 overcome its issues. @@ -501,9 +567,9 @@ generate (options& ops, semantics::cli_unit& unit, path const& p) for (bool first (true); first || ctx.toc; first = false) { - append (ctx, ops.html_prologue (), ops.html_prologue_file ()); + append (ctx, ops.html_prologue (), ops.html_prologue_file (), pdeps); generate_html (ctx); - append (ctx, ops.html_epilogue (), ops.html_epilogue_file ()); + append (ctx, ops.html_epilogue (), ops.html_epilogue_file (), pdeps); if (ctx.toc) { @@ -538,6 +604,9 @@ generate (options& ops, semantics::cli_unit& unit, path const& p) } auto_rm.add (txt_path); + + if (gen_dep) + depts.push_back (move (txt_path.normalize ())); } // The explicit cast helps VC++ 8.0 overcome its issues. @@ -547,9 +616,9 @@ generate (options& ops, semantics::cli_unit& unit, path const& p) for (bool first (true); first || ctx.toc; first = false) { - append (ctx, ops.txt_prologue (), ops.txt_prologue_file ()); + append (ctx, ops.txt_prologue (), ops.txt_prologue_file (), pdeps); generate_txt (ctx); - append (ctx, ops.txt_epilogue (), ops.txt_epilogue_file ()); + append (ctx, ops.txt_epilogue (), ops.txt_epilogue_file (), pdeps); if (ctx.toc) { @@ -561,6 +630,49 @@ generate (options& ops, semantics::cli_unit& unit, path const& p) ctx.verify_id_ref (); } + // gen_dep + // + if (gen_dep) + { + // Write the specified path to the dependencies file stream, escaping + // colons and backslashes. + // + auto write = [&dep] (path const& p) + { + for (char c: p.string ()) + { + if (c == ':' || c == '\\') + dep << '\\'; + + dep << c; + } + }; + + // Note that we don't add the dependency file as a dependent, but in the + // future may invent some option which triggers that. + // + bool first (true); + for (const auto& p: depts) + { + if (!first) + dep << " \\" << endl; + else + first = false; + + write (p); + } + + dep << ':'; + + for (const auto& p: deps) + { + dep << " \\" << endl + << " "; write (p); + } + + dep << endl; + } + auto_rm.cancel (); } catch (const generation_failed&) diff --git a/cli/cli/generator.hxx b/cli/cli/generator.hxx index f567528..3deb3f3 100644 --- a/cli/cli/generator.hxx +++ b/cli/cli/generator.hxx @@ -5,6 +5,8 @@ #ifndef CLI_GENERATOR_HXX #define CLI_GENERATOR_HXX +#include <vector> + #include <cli/options.hxx> #include <cli/semantics/unit.hxx> @@ -16,7 +18,10 @@ public: class failed {}; void - generate (options&, semantics::cli_unit&, semantics::path const&); + generate (options&, + semantics::cli_unit&&, + std::vector<semantics::path>&& dependencies, + semantics::path const&); private: generator (generator const&); diff --git a/cli/cli/header.cxx b/cli/cli/header.cxx index a2a3ccd..87ff259 100644 --- a/cli/cli/header.cxx +++ b/cli/cli/header.cxx @@ -115,7 +115,7 @@ namespace string name (escape (c.name ())); string um (cli + "::unknown_mode"); - os << "class " << name; + os << "class " << exp << name; { base b (*this); @@ -367,13 +367,13 @@ generate_header (context& ctx) string up (ctx.cli + "::usage_para"); string const& ost (ctx.options.ostream_type ()); - os << up << endl + os << ctx.exp << up << endl << n << "usage (" << ost << "&," << endl << up << " = " << up << "::none);" << endl; if (ctx.gen_usage == ut_both) - os << up << endl + os << ctx.exp << up << endl << n << "long_usage (" << ost << "&," << endl << up << " = " << up << "::none);" << endl; diff --git a/cli/cli/options.cli b/cli/cli/options.cli index 3a3089b..211e01f 100644 --- a/cli/cli/options.cli +++ b/cli/cli/options.cli @@ -171,6 +171,13 @@ class options should be used to print usage and exception information." }; + std::string --export-symbol + { + "<symbol>", + "Insert <symbol> in places where DLL export/import control statements + (\cb{__declspec(dllexport/dllimport)}) are necessary." + }; + bool --generate-cxx { "Generate C++ code. If neither \cb{--generate-man}, \cb{--generate-html}, @@ -192,6 +199,18 @@ class options "Generate documentation in the plain text format, similar to usage." }; + bool --generate-dep + { + "Generate \cb{make} dependency information. This option triggers the + creation of the \cb{.d} file containing the dependencies of the generated + files on the main \cb{.cli} file as well as all the \cb{.cli} files that + it includes or sources, transitively. Paths specified with the + \cb{--*-prologue-file} and \cb{--*-epilogue-file} options are also + added as dependencies. Note, however, that paths specified with the + \cb{--options-file} option are not added (since they may or may not + contain options that affect the output)." + }; + bool --stdout { "Write output to STDOUT instead of a file. This option is not valid @@ -579,6 +598,20 @@ class options the generated text file." }; + std::string --dep-suffix = ".d" + { + "<suffix>", + "Use <suffix> instead of the default \cb{.d} to construct the name of the + generated dependency file. See also \cb{--dep-file}." + }; + + std::string --dep-file + { + "<path>", + "Use <path> as the generated dependency file path instead of deriving it + from the input file name." + }; + std::string --option-prefix = "-" { "<prefix>", diff --git a/cli/cli/parser.cxx b/cli/cli/parser.cxx index 4685edc..e2efca5 100644 --- a/cli/cli/parser.cxx +++ b/cli/cli/parser.cxx @@ -17,6 +17,7 @@ #include <fstream> #include <sstream> +#include <utility> // move() #include <iostream> #include <cli/token.hxx> @@ -66,7 +67,7 @@ const char* punctuation[] = { // Output the token type and value in a format suitable for diagnostics. // -std::ostream& +static std::ostream& operator<< (std::ostream& os, token const& t) { switch (t.type ()) @@ -184,16 +185,19 @@ recover (token& t) } } -unique_ptr<cli_unit> parser:: +parser::parse_result parser:: parse (std::istream& is, path const& p) { unique_ptr<cli_unit> unit (new cli_unit (p, 1, 1)); { path ap (p); - ap.absolute (); + ap.complete (); ap.normalize (); - include_map_[ap] = unit.get (); + include_map_[move (ap)] = unit.get (); + + if (collect_dependencies_) + dependencies_.push_back (path (p).normalize ()); } root_ = cur_ = unit.get (); @@ -211,7 +215,7 @@ parse (std::istream& is, path const& p) if (!valid_ || !l.valid ()) throw invalid_input (); - return unit; + return parse_result {move (unit), move (dependencies_)}; } void parser:: @@ -350,6 +354,16 @@ source_decl () if (valid_) { + if (collect_dependencies_) + { + path ap (p); + ap.complete (); + ap.normalize (); + + if (include_map_.emplace (move (ap), nullptr).second) + dependencies_.push_back (p); + } + auto_restore<path const> new_path (path_, &p); ifstream ifs (p.string ().c_str ()); @@ -468,15 +482,18 @@ include_decl () // Detect and ignore multiple inclusions. // path ap (p); - ap.absolute (); + ap.complete (); ap.normalize (); include_map::iterator it (include_map_.find (ap)); - if (it == include_map_.end ()) + if (it == include_map_.end () || it->second == nullptr) { + if (collect_dependencies_ && it == include_map_.end ()) + dependencies_.push_back (p); + cli_unit& n (root_->new_node<cli_unit> (p, 1, 1)); root_->new_edge<cli_includes> (*cur_, n, ik, f); - include_map_[ap] = &n; + include_map_[move (ap)] = &n; auto_restore<cli_unit> new_cur (cur_, &n); auto_restore<path const> new_path (path_, &p); diff --git a/cli/cli/parser.hxx b/cli/cli/parser.hxx index 326768e..960e74b 100644 --- a/cli/cli/parser.hxx +++ b/cli/cli/parser.hxx @@ -23,11 +23,23 @@ class parser public: typedef std::vector<semantics::path> paths; - parser (paths const& include_paths): include_paths_ (include_paths) {} + parser (paths const& include_paths, bool collect_dependencies) + : include_paths_ (include_paths), + collect_dependencies_ (collect_dependencies) {} struct invalid_input {}; - std::unique_ptr<semantics::cli_unit> + struct parse_result + { + std::unique_ptr<semantics::cli_unit> unit; + + // Normalized paths of the main CLI file and files it includes and sources + // recursively, with the duplicates suppressed. + // + paths dependencies; + }; + + parse_result parse (std::istream& is, semantics::path const& path); private: @@ -72,6 +84,7 @@ private: private: paths const include_paths_; + bool collect_dependencies_; bool valid_; semantics::path const* path_; @@ -84,8 +97,12 @@ private: std::size_t doc_count_; // Scope doc counter, see scope_doc() for details. + // If the entry's value is NULL, then the key refers to a sourced file. + // typedef std::map<semantics::path, semantics::cli_unit*> include_map; include_map include_map_; + + paths dependencies_; }; #endif // CLI_PARSER_HXX diff --git a/cli/cli/parser.test.cxx b/cli/cli/parser.test.cxx index 5a87bb7..44109b3 100644 --- a/cli/cli/parser.test.cxx +++ b/cli/cli/parser.test.cxx @@ -32,7 +32,7 @@ main (int argc, char* argv[]) ifs.open (path.string ().c_str ()); parser::paths include_paths; - parser p (include_paths); + parser p (include_paths, true /* collect_dependencies */); p.parse (ifs, path); } catch (semantics::invalid_path const& e) diff --git a/cli/cli/bootstrap/cli/options.cxx b/cli/cli/pregenerated/cli/options.cxx index e66ae63..9f0be5f 100644 --- a/cli/cli/bootstrap/cli/options.cxx +++ b/cli/cli/pregenerated/cli/options.cxx @@ -542,10 +542,31 @@ namespace cli struct parser<bool> { static void - parse (bool& x, scanner& s) + parse (bool& x, bool& xs, scanner& s) { - s.next (); - x = true; + const char* o (s.next ()); + + if (s.more ()) + { + const char* v (s.next ()); + + if (std::strcmp (v, "1") == 0 || + std::strcmp (v, "true") == 0 || + std::strcmp (v, "TRUE") == 0 || + std::strcmp (v, "True") == 0) + x = true; + else if (std::strcmp (v, "0") == 0 || + std::strcmp (v, "false") == 0 || + std::strcmp (v, "FALSE") == 0 || + std::strcmp (v, "False") == 0) + x = false; + else + throw invalid_value (o, v); + } + else + throw missing_value (o); + + xs = true; } }; @@ -655,6 +676,56 @@ namespace cli } }; + template <typename K, typename V, typename C> + struct parser<std::multimap<K, V, C> > + { + static void + parse (std::multimap<K, V, C>& m, bool& xs, scanner& s) + { + const char* o (s.next ()); + + if (s.more ()) + { + std::size_t pos (s.position ()); + std::string ov (s.next ()); + std::string::size_type p = ov.find ('='); + + K k = K (); + V v = V (); + std::string kstr (ov, 0, p); + std::string vstr (ov, (p != std::string::npos ? p + 1 : ov.size ())); + + int ac (2); + char* av[] = + { + const_cast<char*> (o), + 0 + }; + + bool dummy; + if (!kstr.empty ()) + { + av[1] = const_cast<char*> (kstr.c_str ()); + argv_scanner s (0, ac, av, false, pos); + parser<K>::parse (k, dummy, s); + } + + if (!vstr.empty ()) + { + av[1] = const_cast<char*> (vstr.c_str ()); + argv_scanner s (0, ac, av, false, pos); + parser<V>::parse (v, dummy, s); + } + + m.insert (typename std::multimap<K, V, C>::value_type (k, v)); + } + else + throw missing_value (o); + + xs = true; + } + }; + template <typename X, typename T, T X::*M> void thunk (X& x, scanner& s) @@ -662,6 +733,14 @@ namespace cli parser<T>::parse (x.*M, s); } + template <typename X, bool X::*M> + void + thunk (X& x, scanner& s) + { + s.next (); + x.*M = true; + } + template <typename X, typename T, T X::*M, bool X::*S> void thunk (X& x, scanner& s) @@ -671,7 +750,6 @@ namespace cli } #include <map> -#include <cstring> // options // @@ -702,10 +780,13 @@ options () cli_namespace_specified_ (false), ostream_type_ ("::std::ostream"), ostream_type_specified_ (false), + export_symbol_ (), + export_symbol_specified_ (false), generate_cxx_ (), generate_man_ (), generate_html_ (), generate_txt_ (), + generate_dep_ (), stdout__ (), suppress_undocumented_ (), suppress_usage_ (), @@ -795,6 +876,10 @@ options () html_suffix_specified_ (false), txt_suffix_ (".txt"), txt_suffix_specified_ (false), + dep_suffix_ (".d"), + dep_suffix_specified_ (false), + dep_file_ (), + dep_file_specified_ (false), option_prefix_ ("-"), option_prefix_specified_ (false), option_separator_ ("--"), @@ -844,10 +929,13 @@ options (int& argc, cli_namespace_specified_ (false), ostream_type_ ("::std::ostream"), ostream_type_specified_ (false), + export_symbol_ (), + export_symbol_specified_ (false), generate_cxx_ (), generate_man_ (), generate_html_ (), generate_txt_ (), + generate_dep_ (), stdout__ (), suppress_undocumented_ (), suppress_usage_ (), @@ -937,6 +1025,10 @@ options (int& argc, html_suffix_specified_ (false), txt_suffix_ (".txt"), txt_suffix_specified_ (false), + dep_suffix_ (".d"), + dep_suffix_specified_ (false), + dep_file_ (), + dep_file_specified_ (false), option_prefix_ ("-"), option_prefix_specified_ (false), option_separator_ ("--"), @@ -989,10 +1081,13 @@ options (int start, cli_namespace_specified_ (false), ostream_type_ ("::std::ostream"), ostream_type_specified_ (false), + export_symbol_ (), + export_symbol_specified_ (false), generate_cxx_ (), generate_man_ (), generate_html_ (), generate_txt_ (), + generate_dep_ (), stdout__ (), suppress_undocumented_ (), suppress_usage_ (), @@ -1082,6 +1177,10 @@ options (int start, html_suffix_specified_ (false), txt_suffix_ (".txt"), txt_suffix_specified_ (false), + dep_suffix_ (".d"), + dep_suffix_specified_ (false), + dep_file_ (), + dep_file_specified_ (false), option_prefix_ ("-"), option_prefix_specified_ (false), option_separator_ ("--"), @@ -1134,10 +1233,13 @@ options (int& argc, cli_namespace_specified_ (false), ostream_type_ ("::std::ostream"), ostream_type_specified_ (false), + export_symbol_ (), + export_symbol_specified_ (false), generate_cxx_ (), generate_man_ (), generate_html_ (), generate_txt_ (), + generate_dep_ (), stdout__ (), suppress_undocumented_ (), suppress_usage_ (), @@ -1227,6 +1329,10 @@ options (int& argc, html_suffix_specified_ (false), txt_suffix_ (".txt"), txt_suffix_specified_ (false), + dep_suffix_ (".d"), + dep_suffix_specified_ (false), + dep_file_ (), + dep_file_specified_ (false), option_prefix_ ("-"), option_prefix_specified_ (false), option_separator_ ("--"), @@ -1281,10 +1387,13 @@ options (int start, cli_namespace_specified_ (false), ostream_type_ ("::std::ostream"), ostream_type_specified_ (false), + export_symbol_ (), + export_symbol_specified_ (false), generate_cxx_ (), generate_man_ (), generate_html_ (), generate_txt_ (), + generate_dep_ (), stdout__ (), suppress_undocumented_ (), suppress_usage_ (), @@ -1374,6 +1483,10 @@ options (int start, html_suffix_specified_ (false), txt_suffix_ (".txt"), txt_suffix_specified_ (false), + dep_suffix_ (".d"), + dep_suffix_specified_ (false), + dep_file_ (), + dep_file_specified_ (false), option_prefix_ ("-"), option_prefix_specified_ (false), option_separator_ ("--"), @@ -1424,10 +1537,13 @@ options (::cli::scanner& s, cli_namespace_specified_ (false), ostream_type_ ("::std::ostream"), ostream_type_specified_ (false), + export_symbol_ (), + export_symbol_specified_ (false), generate_cxx_ (), generate_man_ (), generate_html_ (), generate_txt_ (), + generate_dep_ (), stdout__ (), suppress_undocumented_ (), suppress_usage_ (), @@ -1517,6 +1633,10 @@ options (::cli::scanner& s, html_suffix_specified_ (false), txt_suffix_ (".txt"), txt_suffix_specified_ (false), + dep_suffix_ (".d"), + dep_suffix_specified_ (false), + dep_file_ (), + dep_file_specified_ (false), option_prefix_ ("-"), option_prefix_specified_ (false), option_separator_ ("--"), @@ -1590,6 +1710,10 @@ print_usage (::std::ostream& os, ::cli::usage_para p) << " std::ostream that should be used to print usage" << ::std::endl << " and exception information." << ::std::endl; + os << "--export-symbol <symbol> Insert <symbol> in places where DLL export/import" << ::std::endl + << " control statements" << ::std::endl + << " (__declspec(dllexport/dllimport)) are necessary." << ::std::endl; + os << "--generate-cxx Generate C++ code." << ::std::endl; os << "--generate-man Generate documentation in the man page format." << ::std::endl; @@ -1599,6 +1723,8 @@ print_usage (::std::ostream& os, ::cli::usage_para p) os << "--generate-txt Generate documentation in the plain text format," << ::std::endl << " similar to usage." << ::std::endl; + os << "--generate-dep Generate make dependency information." << ::std::endl; + os << "--stdout Write output to STDOUT instead of a file." << ::std::endl; os << "--suppress-undocumented Suppress the generation of documentation entries" << ::std::endl @@ -1749,6 +1875,13 @@ print_usage (::std::ostream& os, ::cli::usage_para p) os << "--txt-suffix <suffix> Use <suffix> instead of the default .txt to" << ::std::endl << " construct the name of the generated text file." << ::std::endl; + os << "--dep-suffix <suffix> Use <suffix> instead of the default .d to" << ::std::endl + << " construct the name of the generated dependency" << ::std::endl + << " file." << ::std::endl; + + os << "--dep-file <path> Use <path> as the generated dependency file path" << ::std::endl + << " instead of deriving it from the input file name." << ::std::endl; + os << "--option-prefix <prefix> Use <prefix> instead of the default '-' as an" << ::std::endl << " option prefix." << ::std::endl; @@ -1799,9 +1932,9 @@ struct _cli_options_map_init &::cli::thunk< options, std::uint64_t, &options::build2_metadata_, &options::build2_metadata_specified_ >; _cli_options_map_["--help"] = - &::cli::thunk< options, bool, &options::help_ >; + &::cli::thunk< options, &options::help_ >; _cli_options_map_["--version"] = - &::cli::thunk< options, bool, &options::version_ >; + &::cli::thunk< options, &options::version_ >; _cli_options_map_["--include-path"] = &::cli::thunk< options, std::vector<std::string>, &options::include_path_, &options::include_path_specified_ >; @@ -1818,49 +1951,54 @@ struct _cli_options_map_init &::cli::thunk< options, cxx_version, &options::std_, &options::std_specified_ >; _cli_options_map_["--generate-modifier"] = - &::cli::thunk< options, bool, &options::generate_modifier_ >; + &::cli::thunk< options, &options::generate_modifier_ >; _cli_options_map_["--generate-specifier"] = - &::cli::thunk< options, bool, &options::generate_specifier_ >; + &::cli::thunk< options, &options::generate_specifier_ >; _cli_options_map_["--generate-parse"] = - &::cli::thunk< options, bool, &options::generate_parse_ >; + &::cli::thunk< options, &options::generate_parse_ >; _cli_options_map_["--generate-merge"] = - &::cli::thunk< options, bool, &options::generate_merge_ >; + &::cli::thunk< options, &options::generate_merge_ >; _cli_options_map_["--generate-description"] = - &::cli::thunk< options, bool, &options::generate_description_ >; + &::cli::thunk< options, &options::generate_description_ >; _cli_options_map_["--generate-file-scanner"] = - &::cli::thunk< options, bool, &options::generate_file_scanner_ >; + &::cli::thunk< options, &options::generate_file_scanner_ >; _cli_options_map_["--generate-vector-scanner"] = - &::cli::thunk< options, bool, &options::generate_vector_scanner_ >; + &::cli::thunk< options, &options::generate_vector_scanner_ >; _cli_options_map_["--generate-group-scanner"] = - &::cli::thunk< options, bool, &options::generate_group_scanner_ >; + &::cli::thunk< options, &options::generate_group_scanner_ >; _cli_options_map_["--suppress-inline"] = - &::cli::thunk< options, bool, &options::suppress_inline_ >; + &::cli::thunk< options, &options::suppress_inline_ >; _cli_options_map_["--suppress-cli"] = - &::cli::thunk< options, bool, &options::suppress_cli_ >; + &::cli::thunk< options, &options::suppress_cli_ >; _cli_options_map_["--cli-namespace"] = &::cli::thunk< options, std::string, &options::cli_namespace_, &options::cli_namespace_specified_ >; _cli_options_map_["--ostream-type"] = &::cli::thunk< options, std::string, &options::ostream_type_, &options::ostream_type_specified_ >; + _cli_options_map_["--export-symbol"] = + &::cli::thunk< options, std::string, &options::export_symbol_, + &options::export_symbol_specified_ >; _cli_options_map_["--generate-cxx"] = - &::cli::thunk< options, bool, &options::generate_cxx_ >; + &::cli::thunk< options, &options::generate_cxx_ >; _cli_options_map_["--generate-man"] = - &::cli::thunk< options, bool, &options::generate_man_ >; + &::cli::thunk< options, &options::generate_man_ >; _cli_options_map_["--generate-html"] = - &::cli::thunk< options, bool, &options::generate_html_ >; + &::cli::thunk< options, &options::generate_html_ >; _cli_options_map_["--generate-txt"] = - &::cli::thunk< options, bool, &options::generate_txt_ >; + &::cli::thunk< options, &options::generate_txt_ >; + _cli_options_map_["--generate-dep"] = + &::cli::thunk< options, &options::generate_dep_ >; _cli_options_map_["--stdout"] = - &::cli::thunk< options, bool, &options::stdout__ >; + &::cli::thunk< options, &options::stdout__ >; _cli_options_map_["--suppress-undocumented"] = - &::cli::thunk< options, bool, &options::suppress_undocumented_ >; + &::cli::thunk< options, &options::suppress_undocumented_ >; _cli_options_map_["--suppress-usage"] = - &::cli::thunk< options, bool, &options::suppress_usage_ >; + &::cli::thunk< options, &options::suppress_usage_ >; _cli_options_map_["--long-usage"] = - &::cli::thunk< options, bool, &options::long_usage_ >; + &::cli::thunk< options, &options::long_usage_ >; _cli_options_map_["--short-usage"] = - &::cli::thunk< options, bool, &options::short_usage_ >; + &::cli::thunk< options, &options::short_usage_ >; _cli_options_map_["--page-usage"] = &::cli::thunk< options, std::string, &options::page_usage_, &options::page_usage_specified_ >; @@ -1868,13 +2006,13 @@ struct _cli_options_map_init &::cli::thunk< options, std::size_t, &options::option_length_, &options::option_length_specified_ >; _cli_options_map_["--ascii-tree"] = - &::cli::thunk< options, bool, &options::ascii_tree_ >; + &::cli::thunk< options, &options::ascii_tree_ >; _cli_options_map_["--ansi-color"] = - &::cli::thunk< options, bool, &options::ansi_color_ >; + &::cli::thunk< options, &options::ansi_color_ >; _cli_options_map_["--exclude-base"] = - &::cli::thunk< options, bool, &options::exclude_base_ >; + &::cli::thunk< options, &options::exclude_base_ >; _cli_options_map_["--include-base-last"] = - &::cli::thunk< options, bool, &options::include_base_last_ >; + &::cli::thunk< options, &options::include_base_last_ >; _cli_options_map_["--class-doc"] = &::cli::thunk< options, std::map<std::string, std::string>, &options::class_doc_, &options::class_doc_specified_ >; @@ -1891,12 +2029,12 @@ struct _cli_options_map_init &::cli::thunk< options, std::vector<std::string>, &options::link_regex_, &options::link_regex_specified_ >; _cli_options_map_["--link-regex-trace"] = - &::cli::thunk< options, bool, &options::link_regex_trace_ >; + &::cli::thunk< options, &options::link_regex_trace_ >; _cli_options_map_["--html-heading-map"] = &::cli::thunk< options, std::map<char, std::string>, &options::html_heading_map_, &options::html_heading_map_specified_ >; _cli_options_map_["--omit-link-check"] = - &::cli::thunk< options, bool, &options::omit_link_check_ >; + &::cli::thunk< options, &options::omit_link_check_ >; _cli_options_map_["--hxx-prologue"] = &::cli::thunk< options, std::vector<std::string>, &options::hxx_prologue_, &options::hxx_prologue_specified_ >; @@ -1993,6 +2131,12 @@ struct _cli_options_map_init _cli_options_map_["--txt-suffix"] = &::cli::thunk< options, std::string, &options::txt_suffix_, &options::txt_suffix_specified_ >; + _cli_options_map_["--dep-suffix"] = + &::cli::thunk< options, std::string, &options::dep_suffix_, + &options::dep_suffix_specified_ >; + _cli_options_map_["--dep-file"] = + &::cli::thunk< options, std::string, &options::dep_file_, + &options::dep_file_specified_ >; _cli_options_map_["--option-prefix"] = &::cli::thunk< options, std::string, &options::option_prefix_, &options::option_prefix_specified_ >; @@ -2000,13 +2144,13 @@ struct _cli_options_map_init &::cli::thunk< options, std::string, &options::option_separator_, &options::option_separator_specified_ >; _cli_options_map_["--keep-separator"] = - &::cli::thunk< options, bool, &options::keep_separator_ >; + &::cli::thunk< options, &options::keep_separator_ >; _cli_options_map_["--no-combined-flags"] = - &::cli::thunk< options, bool, &options::no_combined_flags_ >; + &::cli::thunk< options, &options::no_combined_flags_ >; _cli_options_map_["--no-combined-values"] = - &::cli::thunk< options, bool, &options::no_combined_values_ >; + &::cli::thunk< options, &options::no_combined_values_ >; _cli_options_map_["--include-with-brackets"] = - &::cli::thunk< options, bool, &options::include_with_brackets_ >; + &::cli::thunk< options, &options::include_with_brackets_ >; _cli_options_map_["--include-prefix"] = &::cli::thunk< options, std::string, &options::include_prefix_, &options::include_prefix_specified_ >; diff --git a/cli/cli/bootstrap/cli/options.hxx b/cli/cli/pregenerated/cli/options.hxx index 3ae86c6..f44258f 100644 --- a/cli/cli/bootstrap/cli/options.hxx +++ b/cli/cli/pregenerated/cli/options.hxx @@ -673,6 +673,21 @@ class options void ostream_type_specified (bool); + const std::string& + export_symbol () const; + + std::string& + export_symbol (); + + void + export_symbol (const std::string&); + + bool + export_symbol_specified () const; + + void + export_symbol_specified (bool); + const bool& generate_cxx () const; @@ -710,6 +725,15 @@ class options generate_txt (const bool&); const bool& + generate_dep () const; + + bool& + generate_dep (); + + void + generate_dep (const bool&); + + const bool& stdout_ () const; bool& @@ -1394,6 +1418,36 @@ class options txt_suffix_specified (bool); const std::string& + dep_suffix () const; + + std::string& + dep_suffix (); + + void + dep_suffix (const std::string&); + + bool + dep_suffix_specified () const; + + void + dep_suffix_specified (bool); + + const std::string& + dep_file () const; + + std::string& + dep_file (); + + void + dep_file (const std::string&); + + bool + dep_file_specified () const; + + void + dep_file_specified (bool); + + const std::string& option_prefix () const; std::string& @@ -1562,10 +1616,13 @@ class options bool cli_namespace_specified_; std::string ostream_type_; bool ostream_type_specified_; + std::string export_symbol_; + bool export_symbol_specified_; bool generate_cxx_; bool generate_man_; bool generate_html_; bool generate_txt_; + bool generate_dep_; bool stdout__; bool suppress_undocumented_; bool suppress_usage_; @@ -1655,6 +1712,10 @@ class options bool html_suffix_specified_; std::string txt_suffix_; bool txt_suffix_specified_; + std::string dep_suffix_; + bool dep_suffix_specified_; + std::string dep_file_; + bool dep_file_specified_; std::string option_prefix_; bool option_prefix_specified_; std::string option_separator_; diff --git a/cli/cli/bootstrap/cli/options.ixx b/cli/cli/pregenerated/cli/options.ixx index 8c22d51..54fa54a 100644 --- a/cli/cli/bootstrap/cli/options.ixx +++ b/cli/cli/pregenerated/cli/options.ixx @@ -672,6 +672,36 @@ ostream_type_specified (bool x) this->ostream_type_specified_ = x; } +inline const std::string& options:: +export_symbol () const +{ + return this->export_symbol_; +} + +inline std::string& options:: +export_symbol () +{ + return this->export_symbol_; +} + +inline void options:: +export_symbol (const std::string& x) +{ + this->export_symbol_ = x; +} + +inline bool options:: +export_symbol_specified () const +{ + return this->export_symbol_specified_; +} + +inline void options:: +export_symbol_specified (bool x) +{ + this->export_symbol_specified_ = x; +} + inline const bool& options:: generate_cxx () const { @@ -745,6 +775,24 @@ generate_txt (const bool& x) } inline const bool& options:: +generate_dep () const +{ + return this->generate_dep_; +} + +inline bool& options:: +generate_dep () +{ + return this->generate_dep_; +} + +inline void options:: +generate_dep (const bool& x) +{ + this->generate_dep_ = x; +} + +inline const bool& options:: stdout_ () const { return this->stdout__; @@ -2113,6 +2161,66 @@ txt_suffix_specified (bool x) } inline const std::string& options:: +dep_suffix () const +{ + return this->dep_suffix_; +} + +inline std::string& options:: +dep_suffix () +{ + return this->dep_suffix_; +} + +inline void options:: +dep_suffix (const std::string& x) +{ + this->dep_suffix_ = x; +} + +inline bool options:: +dep_suffix_specified () const +{ + return this->dep_suffix_specified_; +} + +inline void options:: +dep_suffix_specified (bool x) +{ + this->dep_suffix_specified_ = x; +} + +inline const std::string& options:: +dep_file () const +{ + return this->dep_file_; +} + +inline std::string& options:: +dep_file () +{ + return this->dep_file_; +} + +inline void options:: +dep_file (const std::string& x) +{ + this->dep_file_ = x; +} + +inline bool options:: +dep_file_specified () const +{ + return this->dep_file_specified_; +} + +inline void options:: +dep_file_specified (bool x) +{ + this->dep_file_specified_ = x; +} + +inline const std::string& options:: option_prefix () const { return this->option_prefix_; diff --git a/cli/cli/runtime-header.cxx b/cli/cli/runtime-header.cxx index 2148941..1003e91 100644 --- a/cli/cli/runtime-header.cxx +++ b/cli/cli/runtime-header.cxx @@ -43,10 +43,13 @@ generate_runtime_header (context& ctx) ctx.ns_open (ctx.cli); + string const& exp (ctx.exp); + string const& exp_inl (ctx.exp_inl); + // usage_para // if (!ctx.options.suppress_usage ()) - os << "class usage_para" + os << "class " << exp_inl << "usage_para" << "{" << "public:" << endl << "enum value" @@ -64,7 +67,7 @@ generate_runtime_header (context& ctx) // unknown_mode // - os << "class unknown_mode" + os << "class " << exp_inl << "unknown_mode" << "{" << "public:" << endl << "enum value" @@ -85,26 +88,30 @@ generate_runtime_header (context& ctx) string const& os_type (ctx.options.ostream_type ()); + const char* nothrow (ctx.options.std () < cxx_version::cxx11 + ? "throw ()" + : "noexcept"); + os << "// Exceptions." << endl << "//" << endl << endl; - os << "class exception: public std::exception" + os << "class " << exp << "exception: public std::exception" << "{" << "public:" << endl << "virtual void" << endl << "print (" << os_type << "&) const = 0;" << "};"; - os << os_type << "&" << endl + os << exp_inl << os_type << "&" << endl << "operator<< (" << os_type << "&, const exception&);" << endl; - os << "class unknown_option: public exception" + os << "class " << exp << "unknown_option: public exception" << "{" << "public:" << endl << "virtual" << endl - << "~unknown_option () throw ();" + << "~unknown_option () " << nothrow << ';' << endl << "unknown_option (const std::string& option);" << endl @@ -115,17 +122,17 @@ generate_runtime_header (context& ctx) << "print (" << os_type << "&) const;" << endl << "virtual const char*" << endl - << "what () const throw ();" + << "what () const " << nothrow << ';' << endl << "private:" << endl << "std::string option_;" << "};"; - os << "class unknown_argument: public exception" + os << "class " << exp << "unknown_argument: public exception" << "{" << "public:" << endl << "virtual" << endl - << "~unknown_argument () throw ();" + << "~unknown_argument () " << nothrow << ';' << endl << "unknown_argument (const std::string& argument);" << endl @@ -136,17 +143,17 @@ generate_runtime_header (context& ctx) << "print (" << os_type << "&) const;" << endl << "virtual const char*" << endl - << "what () const throw ();" + << "what () const " << nothrow << ';' << endl << "private:" << endl << "std::string argument_;" << "};"; - os << "class missing_value: public exception" + os << "class " << exp << "missing_value: public exception" << "{" << "public:" << endl << "virtual" << endl - << "~missing_value () throw ();" + << "~missing_value () " << nothrow << ';' << endl << "missing_value (const std::string& option);" << endl @@ -157,17 +164,17 @@ generate_runtime_header (context& ctx) << "print (" << os_type << "&) const;" << endl << "virtual const char*" << endl - << "what () const throw ();" + << "what () const " << nothrow << ';' << endl << "private:" << endl << "std::string option_;" << "};"; - os << "class invalid_value: public exception" + os << "class " << exp << "invalid_value: public exception" << "{" << "public:" << endl << "virtual" << endl - << "~invalid_value () throw ();" + << "~invalid_value () " << nothrow << ';' << endl << "invalid_value (const std::string& option," << endl << "const std::string& value," << endl @@ -186,7 +193,7 @@ generate_runtime_header (context& ctx) << "print (" << os_type << "&) const;" << endl << "virtual const char*" << endl - << "what () const throw ();" + << "what () const " << nothrow << ';' << endl << "private:" << endl << "std::string option_;" @@ -194,23 +201,23 @@ generate_runtime_header (context& ctx) << "std::string message_;" << "};"; - os << "class eos_reached: public exception" + os << "class " << exp << "eos_reached: public exception" << "{" << "public:" << endl << "virtual void" << endl << "print (" << os_type << "&) const;" << endl << "virtual const char*" << endl - << "what () const throw ();" + << "what () const " << nothrow << ';' << "};"; if (ctx.options.generate_file_scanner ()) { - os << "class file_io_failure: public exception" + os << "class " << exp << "file_io_failure: public exception" << "{" << "public:" << endl << "virtual" << endl - << "~file_io_failure () throw ();" + << "~file_io_failure () " << nothrow << ';' << endl << "file_io_failure (const std::string& file);" << endl @@ -221,17 +228,17 @@ generate_runtime_header (context& ctx) << "print (" << os_type << "&) const;" << endl << "virtual const char*" << endl - << "what () const throw ();" + << "what () const " << nothrow << ';' << endl << "private:" << endl << "std::string file_;" << "};"; - os << "class unmatched_quote: public exception" + os << "class " << exp << "unmatched_quote: public exception" << "{" << "public:" << endl << "virtual" << endl - << "~unmatched_quote () throw ();" + << "~unmatched_quote () " << nothrow << ';' << endl << "unmatched_quote (const std::string& argument);" << endl @@ -242,7 +249,7 @@ generate_runtime_header (context& ctx) << "print (" << os_type << "&) const;" << endl << "virtual const char*" << endl - << "what () const throw ();" + << "what () const " << nothrow << ';' << endl << "private:" << endl << "std::string argument_;" @@ -251,11 +258,11 @@ generate_runtime_header (context& ctx) if (ctx.options.generate_group_scanner ()) { - os << "class unexpected_group: public exception" + os << "class " << exp << "unexpected_group: public exception" << "{" << "public:" << endl << "virtual" << endl - << "~unexpected_group () throw ();" + << "~unexpected_group () " << nothrow << ';' << endl << "unexpected_group (const std::string& argument," << endl << "const std::string& group);" @@ -270,18 +277,18 @@ generate_runtime_header (context& ctx) << "print (std::ostream&) const;" << endl << "virtual const char*" << endl - << "what () const throw ();" + << "what () const " << nothrow << ';' << endl << "private:" << endl << "std::string argument_;" << "std::string group_;" << "};"; - os << "class group_separator: public exception" << endl + os << "class " << exp << "group_separator: public exception" << endl << "{" << "public:" << endl << "virtual" << endl - << "~group_separator () throw ();" + << "~group_separator () " << nothrow << ';' << endl << "// Note: either (but not both) can be empty." << endl << "//" << endl @@ -298,7 +305,7 @@ generate_runtime_header (context& ctx) << "print (std::ostream&) const;" << endl << "virtual const char*" << endl - << "what () const throw ();" + << "what () const " << nothrow << ';' << endl << "private:" << endl << "std::string encountered_;" @@ -322,7 +329,7 @@ generate_runtime_header (context& ctx) << "// position of the previous scanner should be used as the" << endl << "// start position of the next." << endl << "//" << endl - << "class scanner" + << "class " << exp << "scanner" << "{" << "public:" << endl << "virtual" << endl @@ -346,7 +353,7 @@ generate_runtime_header (context& ctx) // argv_scanner // - os << "class argv_scanner: public scanner" + os << "class " << exp << "argv_scanner: public scanner" << "{" << "public:" << endl << "argv_scanner (int& argc," << endl @@ -390,7 +397,7 @@ generate_runtime_header (context& ctx) // if (ctx.options.generate_vector_scanner ()) { - os << "class vector_scanner: public scanner" + os << "class " << exp << "vector_scanner: public scanner" << "{" << "public:" << endl << "vector_scanner (const std::vector<std::string>&," << endl @@ -429,7 +436,7 @@ generate_runtime_header (context& ctx) // if (ctx.options.generate_file_scanner ()) { - os << "class argv_file_scanner: public argv_scanner" + os << "class " << exp << "argv_file_scanner: public argv_scanner" << "{" << "public:" << endl << "argv_file_scanner (int& argc," << endl @@ -549,7 +556,7 @@ generate_runtime_header (context& ctx) // if (ctx.options.generate_group_scanner ()) { - os << "class group_scanner: public scanner" + os << "class " << exp << "group_scanner: public scanner" << "{" << "public:" << endl << "group_scanner (scanner&);" @@ -632,7 +639,7 @@ generate_runtime_header (context& ctx) os << "typedef std::vector<std::string> option_names;" << endl; - os << "class option" + os << "class " << exp_inl << "option" << "{" << "public:" << endl << endl @@ -662,7 +669,7 @@ generate_runtime_header (context& ctx) << "std::string default_value_;" << "};"; - os << "class options: public std::vector<option>" + os << "class " << exp << "options: public std::vector<option>" << "{" << "public:" << endl << "typedef std::vector<option> container_type;" diff --git a/cli/cli/runtime-source.cxx b/cli/cli/runtime-source.cxx index d5334a0..11cd746 100644 --- a/cli/cli/runtime-source.cxx +++ b/cli/cli/runtime-source.cxx @@ -17,11 +17,11 @@ generate_runtime_source (context& ctx, bool complete) << "#include <vector>" << endl << "#include <utility>" << endl // pair << "#include <ostream>" << endl - << "#include <sstream>" << endl; + << "#include <sstream>" << endl + << "#include <cstring>" << endl; if (complete && ctx.options.generate_file_scanner ()) - os << "#include <cstring>" << endl - << "#include <fstream>" << endl; + os << "#include <fstream>" << endl; os << endl; @@ -31,12 +31,16 @@ generate_runtime_source (context& ctx, bool complete) { string const& os_type (ctx.options.ostream_type ()); + const char* nothrow (ctx.options.std () < cxx_version::cxx11 + ? "throw ()" + : "noexcept"); + // unknown_option // os << "// unknown_option" << endl << "//" << endl << "unknown_option::" << endl - << "~unknown_option () throw ()" + << "~unknown_option () " << nothrow << "{" << "}" @@ -47,7 +51,7 @@ generate_runtime_source (context& ctx, bool complete) << "}" << "const char* unknown_option::" << endl - << "what () const throw ()" + << "what () const " << nothrow << "{" << "return \"unknown option\";" << "}"; @@ -57,7 +61,7 @@ generate_runtime_source (context& ctx, bool complete) os << "// unknown_argument" << endl << "//" << endl << "unknown_argument::" << endl - << "~unknown_argument () throw ()" + << "~unknown_argument () " << nothrow << "{" << "}" @@ -68,7 +72,7 @@ generate_runtime_source (context& ctx, bool complete) << "}" << "const char* unknown_argument::" << endl - << "what () const throw ()" + << "what () const " << nothrow << "{" << "return \"unknown argument\";" << "}"; @@ -78,7 +82,7 @@ generate_runtime_source (context& ctx, bool complete) os << "// missing_value" << endl << "//" << endl << "missing_value::" << endl - << "~missing_value () throw ()" + << "~missing_value () " << nothrow << "{" << "}" @@ -89,7 +93,7 @@ generate_runtime_source (context& ctx, bool complete) << "}" << "const char* missing_value::" << endl - << "what () const throw ()" + << "what () const " << nothrow << "{" << "return \"missing option value\";" << "}"; @@ -99,7 +103,7 @@ generate_runtime_source (context& ctx, bool complete) os << "// invalid_value" << endl << "//" << endl << "invalid_value::" << endl - << "~invalid_value () throw ()" + << "~invalid_value () " << nothrow << "{" << "}" @@ -115,7 +119,7 @@ generate_runtime_source (context& ctx, bool complete) << "}" << "const char* invalid_value::" << endl - << "what () const throw ()" + << "what () const " << nothrow << "{" << "return \"invalid option value\";" << "}"; @@ -131,7 +135,7 @@ generate_runtime_source (context& ctx, bool complete) << "}" << "const char* eos_reached::" << endl - << "what () const throw ()" + << "what () const " << nothrow << "{" << "return \"end of argument stream reached\";" << "}"; @@ -143,7 +147,7 @@ generate_runtime_source (context& ctx, bool complete) os << "// file_io_failure" << endl << "//" << endl << "file_io_failure::" << endl - << "~file_io_failure () throw ()" + << "~file_io_failure () " << nothrow << "{" << "}" @@ -155,7 +159,7 @@ generate_runtime_source (context& ctx, bool complete) << "}" << "const char* file_io_failure::" << endl - << "what () const throw ()" + << "what () const " << nothrow << "{" << "return \"unable to open file or read failure\";" << "}"; @@ -165,7 +169,7 @@ generate_runtime_source (context& ctx, bool complete) os << "// unmatched_quote" << endl << "//" << endl << "unmatched_quote::" << endl - << "~unmatched_quote () throw ()" + << "~unmatched_quote () " << nothrow << "{" << "}" @@ -177,7 +181,7 @@ generate_runtime_source (context& ctx, bool complete) << "}" << "const char* unmatched_quote::" << endl - << "what () const throw ()" + << "what () const " << nothrow << "{" << "return \"unmatched quote\";" << "}"; @@ -191,7 +195,7 @@ generate_runtime_source (context& ctx, bool complete) << "//" << endl << "unexpected_group::" << endl - << "~unexpected_group () throw ()" + << "~unexpected_group () " << nothrow << "{" << "}" @@ -203,7 +207,7 @@ generate_runtime_source (context& ctx, bool complete) << "}" << "const char* unexpected_group::" << endl - << "what () const throw ()" + << "what () const " << nothrow << "{" << "return \"unexpected grouped argument\";" << "}"; @@ -214,7 +218,7 @@ generate_runtime_source (context& ctx, bool complete) << "//" << endl << "group_separator::" << endl - << "~group_separator () throw ()" + << "~group_separator () " << nothrow << "{" << "}" @@ -238,7 +242,7 @@ generate_runtime_source (context& ctx, bool complete) << "}" << "const char* group_separator::" << endl - << "what () const throw ()" + << "what () const " << nothrow << "{" << "bool ex (!expected_.empty ());" << "bool en (!encountered_.empty ());" @@ -1011,11 +1015,33 @@ generate_runtime_source (context& ctx, bool complete) << "{"; os << "static void" << endl - << "parse (bool& x, scanner& s)" + << "parse (bool& x, " << (sp ? "bool& xs, " : "") << "scanner& s)" << "{" - << "s.next ();" - << "x = true;" - << "}"; + << "const char* o (s.next ());" + << endl + << "if (s.more ())" + << "{" + << "const char* v (s.next ());" + << endl + << "if (std::strcmp (v, \"1\") == 0 ||" << endl + << "std::strcmp (v, \"true\") == 0 ||" << endl + << "std::strcmp (v, \"TRUE\") == 0 ||" << endl + << "std::strcmp (v, \"True\") == 0)" << endl + << "x = true;" + << "else if (std::strcmp (v, \"0\") == 0 ||" << endl + << "std::strcmp (v, \"false\") == 0 ||" << endl + << "std::strcmp (v, \"FALSE\") == 0 ||" << endl + << "std::strcmp (v, \"False\") == 0)" << endl + << "x = false;" + << "else" << endl + << "throw invalid_value (o, v);" + << "}" + << "else" << endl + << "throw missing_value (o);"; + if (sp) + os << endl + << "xs = true;"; + os << "}"; if (gen_merge) os << "static void" << endl @@ -1194,6 +1220,70 @@ generate_runtime_source (context& ctx, bool complete) os << "};"; + // parser<std::multimap<K,V,C>> + // + os << "template <typename K, typename V, typename C>" << endl + << "struct parser<std::multimap<K, V, C> >" + << "{"; + + os << "static void" << endl + << "parse (std::multimap<K, V, C>& m, " << (sp ? "bool& xs, " : "") << "scanner& s)" + << "{" + << "const char* o (s.next ());" + << endl + << "if (s.more ())" + << "{" + << "std::size_t pos (s.position ());" + << "std::string ov (s.next ());" + << "std::string::size_type p = ov.find ('=');" + << endl + << "K k = K ();" + << "V v = V ();" + << "std::string kstr (ov, 0, p);" + << "std::string vstr (ov, (p != std::string::npos ? p + 1 : ov.size ()));" + << endl + << "int ac (2);" + << "char* av[] =" + << "{" + << "const_cast<char*> (o)," << endl + << "0" + << "};"; + if (sp) + os << "bool dummy;"; + os << "if (!kstr.empty ())" + << "{" + << "av[1] = const_cast<char*> (kstr.c_str ());" + << "argv_scanner s (0, ac, av, false, pos);" + << "parser<K>::parse (k, " << (sp ? "dummy, " : "") << "s);" + << "}" + << "if (!vstr.empty ())" + << "{" + << "av[1] = const_cast<char*> (vstr.c_str ());" + << "argv_scanner s (0, ac, av, false, pos);" + << "parser<V>::parse (v, " << (sp ? "dummy, " : "") << "s);" + << "}" + << "m.insert (typename std::multimap<K, V, C>::value_type (k, v));" + << "}" + << "else" << endl + << "throw missing_value (o);"; + if (sp) + os << endl + << "xs = true;"; + os << "}"; + + if (gen_merge) + os << "static void" << endl + << "merge (std::multimap<K, V, C>& b, const std::multimap<K, V, C>& a)" + << "{" + << "for (typename std::multimap<K, V, C>::const_iterator i (a.begin ()); " << endl + << "i != a.end (); " << endl + << "++i)" << endl + << "b.insert (typename std::multimap<K, V, C>::value_type (i->first," << endl + << "i->second));" << endl + << "}"; + + os << "};"; + // Parser thunk. // os << "template <typename X, typename T, T X::*M>" << endl @@ -1203,6 +1293,14 @@ generate_runtime_source (context& ctx, bool complete) << "parser<T>::parse (x.*M, s);" << "}"; + os << "template <typename X, bool X::*M>" << endl + << "void" << endl + << "thunk (X& x, scanner& s)" + << "{" + << "s.next ();" + << "x.*M = true;" + << "}"; + if (ctx.gen_specifier) os << "template <typename X, typename T, T X::*M, bool X::*S>" << endl << "void" << endl diff --git a/cli/cli/source.cxx b/cli/cli/source.cxx index 1b9e832..3c04d1a 100644 --- a/cli/cli/source.cxx +++ b/cli/cli/source.cxx @@ -110,8 +110,12 @@ namespace for (names::name_iterator i (n.name_begin ()); i != n.name_end (); ++i) { os << "_cli_" << scope << "_map_[\"" << *i << "\"] =" << endl - << "&" << cli << "::thunk< " << scope << ", " << type << ", " << - "&" << scope << "::" << member; + << "&" << cli << "::thunk< " << scope; + + if (type != "bool") + os << ", " << type; + + os << ", " << "&" << scope << "::" << member; if (gen_specifier && type != "bool") os << "," << endl @@ -1272,7 +1276,6 @@ generate_source (context& ctx) ostream& os (ctx.os); os << "#include <map>" << endl - << "#include <cstring>" << endl << endl; traversal::cli_unit unit; diff --git a/cli/doc/.gitignore b/cli/doc/.gitignore index 93bbd2d..84c93ab 100644 --- a/cli/doc/.gitignore +++ b/cli/doc/.gitignore @@ -1,5 +1,5 @@ +/cli.1 +/cli.xhtml + *.ps *.pdf - -/cli.xhtml -/cli.1 diff --git a/cli/doc/buildfile b/cli/doc/buildfile index 09202ad..753b620 100644 --- a/cli/doc/buildfile +++ b/cli/doc/buildfile @@ -16,15 +16,37 @@ pdf{*}: extension = pdf define html2ps: file html2ps{*}: extension = html2ps -./: css{default} xhtml{cli-guide} bootstrap/{man1 xhtml}{cli} +./: css{default} xhtml{cli-guide} -if $config.cli.develop +# Man pages. +# + +## Consumption build ($develop == false). +# + +# Use pregenerated versions in the consumption build. +# +./: pregenerated/{man1 xhtml}{*}: include = (!$develop) + +# Distribute pregenerated versions only in the consumption build. +# +pregenerated/{man1 xhtml}{*}: dist = (!$develop) + +# +## + +## Development build ($develop == true). +# + +./: {man1 xhtml}{cli}: include = $develop + +if $develop { - doc_version = [string] "$version.major\.$version.minor\.$version.patch" + doc_version = [string] "$version.major.$version.minor.$version.patch" if $version.pre_release doc_version += "-$version.pre_release_string" - # Let's take the last for-digit number to cover 2000-2021,2022. + # Let's take the last four-digit number to cover 2000-2021,2022. # doc_year = $regex.replace($copyright, '.+[-, ]([0-9][0-9][0-9][0-9]) .+', '\1') @@ -33,87 +55,145 @@ if $config.cli.develop # We use the cli version we've built to generate the documentation. # - # Note: avoid cleaning it through this dependency. - # include ../cli/ +} + +# Note: avoid cleaning exe{cli} through this dependency. +# +{man1 xhtml}{cli}: ../cli/exe{cli}: clean = false - {xhtml man1}{cli}: ../cli/exe{cli}: clean = false - - ./: man1{cli}: ../cli/cli{options} file{cli-prologue.1 cli-epilogue.1} - {{ - diag cli --man ($<[1]) - - # Use the copyright year to approximate the last authoring date. - # - ($<[0]) --generate-man $man_options \ - -v date="January $doc_year" \ - --man-prologue-file $path($<[2]) \ - --man-epilogue-file $path($<[3]) \ - --stdout $path($<[1]) >$path($>) - - # If the result differs from the bootstrap version, copy it over. Unlike - # the bootstrap cli case, here we don't need to cause a build restart. - # - if! diff $src_base/bootstrap/cli.1 $path($>) >- - cp $path($>) $src_base/bootstrap/cli.1 - end - }} - - ./: xhtml{cli}: $src_root/cli/cli{options} \ - file{cli-prologue.xhtml cli-epilogue.xhtml} - {{ - diag cli --html ($<[1]) - - ($<[0]) --generate-html $man_options \ - --html-prologue-file $path($<[2]) \ - --html-epilogue-file $path($<[3]) \ - --stdout $path($<[1]) >$path($>) - - if! diff $src_base/bootstrap/cli.xhtml $path($>) >- - cp $path($>) $src_base/bootstrap/cli.xhtml - end - }} +# In the development build distribute regenerated versions, remapping their +# locations to the paths of the pregenerated versions (which are only +# distributed in the consumption build; see above). This way we make sure that +# the distributed files are always up-to-date. +# +{man1 xhtml}{cli}: dist = ($develop ? pregenerated/ : false) +man1{cli}: ../cli/cli{options} file{cli-prologue.1 cli-epilogue.1} +% +if $develop +{{ + diag 'cli --man' ($<[1]) -> $> + + # Use the copyright year to approximate the last authoring date. + # + ($<[0]) --generate-man $man_options \ + -v date="January $doc_year" \ + --man-prologue-file $path($<[2]) \ + --man-epilogue-file $path($<[3]) \ + --stdout $path($<[1]) >$path($>) + + # If the result differs from the pregenerated version, copy it over. Unlike + # the bootstrap compiler case, here we don't need to cause a build restart + # (since nothing depends on it). + # + if! diff $src_base/pregenerated/cli.1 $path($>) >- + cp $path($>) $src_base/pregenerated/cli.1 + end +}} + +xhtml{cli}: ../cli/cli{options} file{cli-prologue.xhtml cli-epilogue.xhtml} +% +if $develop +{{ + diag 'cli --html' ($<[1]) -> $> + + ($<[0]) --generate-html $man_options \ + --html-prologue-file $path($<[2]) \ + --html-epilogue-file $path($<[3]) \ + --stdout $path($<[1]) >$path($>) + + if! diff $src_base/pregenerated/cli.xhtml $path($>) >- + cp $path($>) $src_base/pregenerated/cli.xhtml + end +}} + +# +## + +# Manual. +# +# This case is slightly more involved because we make the generation of the +# manual's ps/pdf optional and also don't keep the result in the repository. +# Specifically: +# +# 1. In the consumption build we will install/redistribute ps/pdf if present. +# +# 2. In the development build we will generate ps/pdf if we are able to import +# the needed tools, issuing a warning otherwise. + +## Consumption build ($develop == false). +# + +# Use pregenerated versions, if exist, in the consumption build. +# +./: pregenerated/{ps pdf}{*}: include = (!$develop) + +# Distribute pregenerated versions only in the consumption build. +# +pregenerated/{ps pdf}{*}: dist = (!$develop) + +# +## + +## Development build ($develop == true). +# + +html2pdf = false + +if $develop +{ # Import the html2ps and ps2pdf programs from the system, if available. # import? html2ps = html2ps%exe{html2ps} import? ps2pdf = ps2pdf14%exe{ps2pdf14} - if ($html2ps != [null] && $ps2pdf != [null]) - { - # Note that we include these generated files into the distribution and - # don't remove them when cleaning in src (so that clean results in a state - # identical to distributed). - # - ./: ps{cli-guide}: xhtml{cli-guide} html2ps{guide} $html2ps - { - options = - - dist = true - clean = ($src_root != $out_root) - } - {{ - diag html2ps ($<[0]) - $html2ps $options -f $path($<[1]) -o $path($>) $path($<[0]) - }} - - ./: pdf{cli-guide}: ps{cli-guide} $ps2pdf - { - options = -dOptimize=true -dEmbedAllFonts=true - - dist = true - clean = ($src_root != $out_root) - } - {{ - diag ps2pdf ($<[0]) - $ps2pdf $options $path($<[0]) $path($>) - }} - } - else - { + html2pdf = ($html2ps != [null] && $ps2pdf != [null]) + + if! $html2pdf warn "html2ps and/or ps2pdf14 are not available, not generating .ps and .pdf documentation" - ./: html2ps{guide} # Note: not keeping ps/pdf (could be outdated). - } } -else - ./: file{cli-prologue* cli-epilogue*} html2ps{guide} {ps pdf}{+cli-guide} + +./: {ps pdf}{cli-guide}: include = $html2pdf + +# In the development build distribute regenerated versions, remapping their +# locations to the paths of the pregenerated versions (which are only +# distributed in the consumption build; see above). This way we make sure that +# the distributed files are always up-to-date. +# +{ps pdf}{cli-guide}: dist = ($html2pdf ? pregenerated/ : false) + +# Note: the pregenerated files may not exist, thus --no-cleanup option is +# required for the cp builtin call. Strictly speaking we don't really need +# to copy them since they are not stored in the repository, but let's do +# that for consistency with the distributed source tree. +# +# @@ TMP Note that cli-guide.xhtml and guide.html2ps still have copyright +# years hard-coded. +# +ps{cli-guide}: xhtml{cli-guide} html2ps{guide} $html2ps +% +if $html2pdf +{{ + options = + + diag html2ps ($<[0]) -> $> + $html2ps $options -f $path($<[1]) -o $path($>) $path($<[0]) + + cp --no-cleanup $path($>) $src_base/pregenerated/cli-guide.ps +}} + +pdf{cli-guide}: ps{cli-guide} $ps2pdf +% +if $html2pdf +{{ + options = -dOptimize=true -dEmbedAllFonts=true + + diag ps2pdf ($<[0]) -> $> + $ps2pdf $options $path($<[0]) $path($>) + + cp --no-cleanup $path($>) $src_base/pregenerated/cli-guide.pdf +}} + +# +## diff --git a/cli/doc/cli-guide.xhtml b/cli/doc/cli-guide.xhtml index 675db03..94c006c 100644 --- a/cli/doc/cli-guide.xhtml +++ b/cli/doc/cli-guide.xhtml @@ -1084,12 +1084,12 @@ include <string>; class options { - std::map<std::string, std::string> --map | -m; + std::map<std::string, bool> --map | -m; }; </pre> - <p>The possible option values for this interface are: <code>-m a=A</code>, - <code>-m =B</code> (key is an empty string), <code>-m c=</code> (value + <p>The possible option values for this interface are: <code>-m a=1</code>, + <code>-m =true</code> (key is an empty string), <code>-m c=</code> (value is an empty string), or <code>-m d</code> (same as <code>-m d=</code>).</p> <p>The last component in the option definition is optional documentation. diff --git a/cli/doc/bootstrap/cli.1 b/cli/doc/pregenerated/cli.1 index 1cced65..d452ca4 100644 --- a/cli/doc/bootstrap/cli.1 +++ b/cli/doc/pregenerated/cli.1 @@ -1,7 +1,7 @@ .\" Process this file with .\" groff -man -Tascii cli.1 .\" -.TH CLI 1 "January 2021" "CLI 1.2.0-b.8" +.TH CLI 1 "January 2023" "CLI 1.2.0" .SH NAME cli \- command line interface compiler for C++ .\" @@ -157,6 +157,9 @@ namespace\. .IP "\fB--ostream-type\fR \fItype\fR" Output stream type instead of the default \fBstd::ostream\fR that should be used to print usage and exception information\. +.IP "\fB--export-symbol\fR \fIsymbol\fR" +Insert \fIsymbol\fR in places where DLL export/import control statements +(\fB__declspec(dllexport/dllimport)\fR) are necessary\. .IP "\fB--generate-cxx\fR" Generate C++ code\. If neither \fB--generate-man\fR, \fB--generate-html\fR, nor \fB--generate-txt\fR is specified, this mode is assumed by default\. @@ -166,6 +169,15 @@ Generate documentation in the man page format\. Generate documentation in the HTML format\. .IP "\fB--generate-txt\fR" Generate documentation in the plain text format, similar to usage\. +.IP "\fB--generate-dep\fR" +Generate \fBmake\fR dependency information\. This option triggers the creation +of the \fB\.d\fR file containing the dependencies of the generated files on +the main \fB\.cli\fR file as well as all the \fB\.cli\fR files that it +includes or sources, transitively\. Paths specified with the +\fB--*-prologue-file\fR and \fB--*-epilogue-file\fR options are also added as +dependencies\. Note, however, that paths specified with the +\fB--options-file\fR option are not added (since they may or may not contain +options that affect the output)\. .IP "\fB--stdout\fR" Write output to STDOUT instead of a file\. This option is not valid when generating C++ code and is normally used to combine generated documentation @@ -209,7 +221,7 @@ and would like their usage to have the same indentation level\. .IP "\fB--ascii-tree\fR" Convert UTF-8 \fBtree(1)\fR output to ASCII\. Specifically, box-drawing characters used in the \fB--charset=UTF-8\fR output are replaced with ASCII -characters used in the --charset=ASCII\fR output\. +characters used in the \fB--charset=ASCII\fR output\. .IP "\fB--ansi-color\fR" Use ANSI color escape sequences when printing usage\. By "color" we really only mean the bold and underline modifiers\. Note that Windows console does @@ -345,6 +357,12 @@ the generated HTML file\. .IP "\fB--txt-suffix\fR \fIsuffix\fR" Use \fIsuffix\fR instead of the default \fB\.txt\fR to construct the name of the generated text file\. +.IP "\fB--dep-suffix\fR \fIsuffix\fR" +Use \fIsuffix\fR instead of the default \fB\.d\fR to construct the name of the +generated dependency file\. See also \fB--dep-file\fR\. +.IP "\fB--dep-file\fR \fIpath\fR" +Use \fIpath\fR as the generated dependency file path instead of deriving it +from the input file name\. .IP "\fB--option-prefix\fR \fIprefix\fR" Use \fIprefix\fR instead of the default '\fB-\fR' as an option prefix\. Unknown command line arguments that start with this prefix are treated as @@ -413,7 +431,7 @@ Send bug reports to the cli-users@codesynthesis.com mailing list. .\" COPYRIGHT .\" .SH COPYRIGHT -Copyright (c) 2009-2021 Code Synthesis Tools CC. +Copyright (c) 2009-2023 Code Synthesis Tools CC. Permission is granted to copy, distribute and/or modify this document under the terms of the MIT License. Copy of this license can be obtained from diff --git a/cli/doc/bootstrap/cli.xhtml b/cli/doc/pregenerated/cli.xhtml index 9ee5c16..2a4f751 100644 --- a/cli/doc/bootstrap/cli.xhtml +++ b/cli/doc/pregenerated/cli.xhtml @@ -2,9 +2,9 @@ <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> <head> - <title>CLI 1.2.0-b.8 Compiler Command Line Manual</title> + <title>CLI 1.2.0 Compiler Command Line Manual</title> - <meta name="copyright" content="© 2009-2021 Code Synthesis Tools CC"/> + <meta name="copyright" content="© 2009-2023 Code Synthesis Tools CC"/> <meta name="keywords" content="cli,command,line,interface,compiler,c++"/> <meta name="description" content="CLI Compiler Command Line Manual"/> @@ -192,6 +192,11 @@ arg+{ --foo } # 'arg+{' ...</pre> <code><b>std::ostream</b></code> that should be used to print usage and exception information.</dd> + <dt><code><b>--export-symbol</b></code> <code><i>symbol</i></code></dt> + <dd>Insert <code><i>symbol</i></code> in places where DLL export/import + control statements (<code><b>__declspec(dllexport/dllimport)</b></code>) + are necessary.</dd> + <dt><code><b>--generate-cxx</b></code></dt> <dd>Generate C++ code. If neither <code><b>--generate-man</b></code>, <code><b>--generate-html</b></code>, nor @@ -208,6 +213,18 @@ arg+{ --foo } # 'arg+{' ...</pre> <dd>Generate documentation in the plain text format, similar to usage.</dd> + <dt><code><b>--generate-dep</b></code></dt> + <dd>Generate <code><b>make</b></code> dependency information. This option + triggers the creation of the <code><b>.d</b></code> file containing the + dependencies of the generated files on the main <code><b>.cli</b></code> + file as well as all the <code><b>.cli</b></code> files that it includes or + sources, transitively. Paths specified with the + <code><b>--*-prologue-file</b></code> and + <code><b>--*-epilogue-file</b></code> options are also added as + dependencies. Note, however, that paths specified with the + <code><b>--options-file</b></code> option are not added (since they may or + may not contain options that affect the output).</dd> + <dt><code><b>--stdout</b></code></dt> <dd>Write output to STDOUT instead of a file. This option is not valid when generating C++ code and is normally used to combine generated @@ -262,7 +279,7 @@ arg+{ --foo } # 'arg+{' ...</pre> <dd>Convert UTF-8 <code><b>tree(1)</b></code> output to ASCII. Specifically, box-drawing characters used in the <code><b>--charset=UTF-8</b></code> output are replaced with ASCII - characters used in the <code>--charset=ASCII</code> output.</dd> + characters used in the <code><b>--charset=ASCII</b></code> output.</dd> <dt><code><b>--ansi-color</b></code></dt> <dd>Use ANSI color escape sequences when printing usage. By "color" we @@ -480,6 +497,15 @@ arg+{ --foo } # 'arg+{' ...</pre> <code><b>.txt</b></code> to construct the name of the generated text file.</dd> + <dt><code><b>--dep-suffix</b></code> <code><i>suffix</i></code></dt> + <dd>Use <code><i>suffix</i></code> instead of the default + <code><b>.d</b></code> to construct the name of the generated dependency + file. See also <code><b>--dep-file</b></code>.</dd> + + <dt><code><b>--dep-file</b></code> <code><i>path</i></code></dt> + <dd>Use <code><i>path</i></code> as the generated dependency file path + instead of deriving it from the input file name.</dd> + <dt><code><b>--option-prefix</b></code> <code><i>prefix</i></code></dt> <dd>Use <code><i>prefix</i></code> instead of the default '<code><b>-</b></code>' as an option prefix. Unknown command line @@ -566,7 +592,7 @@ arg+{ --foo } # 'arg+{' ...</pre> </div> <div id="footer"> - Copyright © 2009-2021 Code Synthesis Tools CC. + Copyright © 2009-2023 Code Synthesis Tools CC. <div id="terms"> Permission is granted to copy, distribute and/or modify this diff --git a/cli/manifest b/cli/manifest index 268c618..a90072b 100644 --- a/cli/manifest +++ b/cli/manifest @@ -1,6 +1,6 @@ : 1 name: cli -version: 1.2.0-b.8.z +version: 1.2.0 summary: Command line interface (CLI) compiler for C++ license: MIT topics: C++, command line interface, source code generation, \ @@ -14,8 +14,8 @@ email: cli-users@codesynthesis.com ; Mailing list build-warning-email: builds@codesynthesis.com requires: c++14 requires: host -depends: * build2 >= 0.14.0- -depends: * bpkg >= 0.14.0- +depends: * build2 >= 0.16.0 +depends: * bpkg >= 0.16.0 depends: libcutl ^1.11.0- tests: * cli-tests == $ examples: * cli-examples == $ |