summaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
Diffstat (limited to 'cli')
-rw-r--r--cli/NEWS17
-rw-r--r--cli/build/root.build11
-rw-r--r--cli/cli/.gitignore2
-rw-r--r--cli/cli/buildfile145
-rw-r--r--cli/cli/cli.cxx8
-rw-r--r--cli/cli/context.cxx75
-rw-r--r--cli/cli/context.hxx4
-rw-r--r--cli/cli/generator.cxx144
-rw-r--r--cli/cli/generator.hxx7
-rw-r--r--cli/cli/header.cxx6
-rw-r--r--cli/cli/options.cli33
-rw-r--r--cli/cli/parser.cxx33
-rw-r--r--cli/cli/parser.hxx21
-rw-r--r--cli/cli/parser.test.cxx2
-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.cxx81
-rw-r--r--cli/cli/runtime-source.cxx146
-rw-r--r--cli/cli/source.cxx9
-rw-r--r--cli/doc/.gitignore6
-rw-r--r--cli/doc/buildfile236
-rw-r--r--cli/doc/cli-guide.xhtml6
-rw-r--r--cli/doc/pregenerated/cli.1 (renamed from cli/doc/bootstrap/cli.1)22
-rw-r--r--cli/doc/pregenerated/cli.xhtml (renamed from cli/doc/bootstrap/cli.xhtml)32
-rw-r--r--cli/manifest6
26 files changed, 1122 insertions, 313 deletions
diff --git a/cli/NEWS b/cli/NEWS
index a1fe25e..07da75f 100644
--- a/cli/NEWS
+++ b/cli/NEWS
@@ -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 &lt;string>;
class options
{
- std::map&lt;std::string, std::string> --map | -m;
+ std::map&lt;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 8231848..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 2022" "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
@@ -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-2022 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 56273ef..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="&#169; 2009-2022 Code Synthesis Tools CC"/>
+ <meta name="copyright" content="&#169; 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
@@ -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 &#169; 2009-2022 Code Synthesis Tools CC.
+ Copyright &#169; 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 == $