summaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
Diffstat (limited to 'cli')
-rw-r--r--cli/NEWS17
-rw-r--r--cli/README2
-rw-r--r--cli/build/root.build54
-rw-r--r--cli/buildfile4
-rw-r--r--cli/cli/.gitignore6
-rw-r--r--cli/cli/buildfile161
-rw-r--r--cli/cli/cli.cxx18
-rw-r--r--cli/cli/context.cxx128
-rw-r--r--cli/cli/context.hxx19
-rw-r--r--cli/cli/generator.cxx150
-rw-r--r--cli/cli/generator.hxx7
-rw-r--r--cli/cli/header.cxx6
-rw-r--r--cli/cli/html.cxx10
-rw-r--r--cli/cli/inline.cxx4
-rw-r--r--cli/cli/lexer.test.cxx3
-rw-r--r--cli/cli/man.cxx10
-rw-r--r--cli/cli/options.cli50
-rw-r--r--cli/cli/parser.cxx33
-rw-r--r--cli/cli/parser.hxx21
-rw-r--r--cli/cli/parser.test.cxx5
-rw-r--r--cli/cli/pregenerated/cli/options.cxx (renamed from cli/cli/options.cxx)289
-rw-r--r--cli/cli/pregenerated/cli/options.hxx (renamed from cli/cli/options.hxx)121
-rw-r--r--cli/cli/pregenerated/cli/options.ixx (renamed from cli/cli/options.ixx)443
-rw-r--r--cli/cli/runtime-header.cxx173
-rw-r--r--cli/cli/runtime-inline.cxx65
-rw-r--r--cli/cli/runtime-source.cxx401
-rw-r--r--cli/cli/semantics/class.cxx2
-rw-r--r--cli/cli/semantics/doc.cxx2
-rw-r--r--cli/cli/semantics/elements.cxx2
-rw-r--r--cli/cli/semantics/elements.hxx8
-rw-r--r--cli/cli/semantics/expression.cxx2
-rw-r--r--cli/cli/semantics/namespace.cxx2
-rw-r--r--cli/cli/semantics/option.cxx2
-rw-r--r--cli/cli/semantics/unit.cxx2
-rw-r--r--cli/cli/source.cxx19
-rw-r--r--cli/cli/traversal/elements.hxx2
-rw-r--r--cli/cli/txt.cxx5
-rw-r--r--cli/cli/version.hxx.in2
-rw-r--r--cli/doc/.gitignore7
-rw-r--r--cli/doc/buildfile195
-rw-r--r--cli/doc/cli-guide.xhtml (renamed from cli/doc/guide/index.xhtml)6
-rw-r--r--cli/doc/cli-prologue.12
-rw-r--r--cli/doc/cli-prologue.xhtml2
-rwxr-xr-xcli/doc/doc.sh78
-rw-r--r--cli/doc/guide.html2ps (renamed from cli/doc/guide/guide.html2ps)0
-rw-r--r--cli/doc/guide/.gitignore2
-rw-r--r--cli/doc/pregenerated/cli.1438
-rw-r--r--cli/doc/pregenerated/cli.xhtml605
-rw-r--r--cli/manifest14
-rw-r--r--cli/tests/.gitignore2
-rw-r--r--cli/tests/ascii-tree/buildfile8
-rw-r--r--cli/tests/ascii-tree/testscript43
-rw-r--r--cli/tests/build/.gitignore3
-rw-r--r--cli/tests/build/bootstrap.build8
-rw-r--r--cli/tests/build/root.build8
-rw-r--r--cli/tests/buildfile4
-rw-r--r--cli/tests/headings/buildfile8
-rw-r--r--cli/tests/headings/testscript36
-rw-r--r--cli/tests/note/buildfile8
-rw-r--r--cli/tests/note/testscript197
-rw-r--r--cli/tests/toc/buildfile8
-rw-r--r--cli/tests/toc/testscript155
62 files changed, 3457 insertions, 630 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/README b/cli/README
index d2c6a02..05d6476 100644
--- a/cli/README
+++ b/cli/README
@@ -9,7 +9,7 @@ See the INSTALL file for prerequisites and installation instructions.
See the doc/ directory for documentation.
-The project page is at http://codesynthesis.com/projects/cli/.
+The project page is at https://www.codesynthesis.com/projects/cli/.
Send questions, bug reports, or any other feedback to
cli-users@codesynthesis.com.
diff --git a/cli/build/root.build b/cli/build/root.build
index c611c4f..ceeaf6c 100644
--- a/cli/build/root.build
+++ b/cli/build/root.build
@@ -1,24 +1,17 @@
# file : build/root.build
# license : MIT; see accompanying LICENSE file
-# Regenerate the options parsing code (included into the repository).
+# 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 such final cli to generate the man pages.
#
-# Note that this is the same variable as what's used by the import machinery
-# when we import cli%exe{cli}. Here, however, we require it to be explicitly
-# specified (i.e., no default search in PATH) in order for the regeneration
-# to be enabled.
-#
-# Normally, in the development build, this variable will be set only in the
-# cli package configuration to point to its own binary (or a binary in another
-# build configuration if you want to play it safe).
-#
-# Note, though, that currently referring to the cli target in the project
-# itself ends up with the 'dependency cycle detected' error. In the future we
-# will fix that by using an ad hoc recipe instead of the cli module. But for
-# now you can workaround this issue by pointing to a binary in another
-# configuration.
-#
-config [path] config.cli
+config [bool] config.cli.develop ?= false
+
+develop = $config.cli.develop
+
+define cli: file
+cli{*}: extension = cli
cxx.std = latest
@@ -35,26 +28,15 @@ if ($cxx.target.system == 'win32-msvc')
if ($cxx.class == 'msvc')
cxx.coptions += /wd4251 /wd4275 /wd4800
-cxx.poptions =+ "-I$out_root" "-I$src_root"
-
-# Load the cli module only if explicitly requested. This way a distribution
-# that includes pre-generated files can be built without installing cli. This
-# is also the reason why we need to explicitly spell out individual source
-# file prerequisites instead of using the cli.cxx{} group (it won't be there
-# unless the module is configured).
-#
-# @@ Replace with import when the parsing code regenerating is implemented
-# via an ad hoc recipe.
+# Specify the test target for cross-testing.
#
-if ($config.cli != [null] && $config.cli != false)
- using cli
+test.target = $cxx.target
-# All exe{} in unit-tests/ are, well, tests. Also don't link whole archives
-# by default there.
+# Extract the copyright notice from the LICENSE file.
#
-unit-tests/exe{*}: test = true
-unit-tests/{libue libul}{*}: bin.whole = false
-
-# Specify the test target for cross-testing.
+# Note that cat is a builtin which means this is both portable and fast.
#
-test.target = $cxx.target
+if ($build.mode != 'skeleton')
+ copyright = $process.run_regex(cat $src_root/LICENSE, \
+ 'Copyright \(c\) (.+)\.', \
+ '\1')
diff --git a/cli/buildfile b/cli/buildfile
index 3f0ccb0..c9e2e50 100644
--- a/cli/buildfile
+++ b/cli/buildfile
@@ -3,7 +3,7 @@
./: {*/ -build/} doc{INSTALL NEWS README} legal{LICENSE} manifest
-# Don't install unit tests or the INSTALL file.
+# Don't install tests or the INSTALL file.
#
-unit-tests/: install = false
+tests/: install = false
doc{INSTALL}@./: install = false
diff --git a/cli/cli/.gitignore b/cli/cli/.gitignore
index 903d015..614e56f 100644
--- a/cli/cli/.gitignore
+++ b/cli/cli/.gitignore
@@ -1,5 +1,7 @@
-cli
-version.hxx
+/cli
+/pregenerated/cli/cli
+/version.hxx
+/options.?xx
# Unit test executables and Testscript output directories (can be symlinks).
#
diff --git a/cli/cli/buildfile b/cli/cli/buildfile
index 2385a7d..92c3e6e 100644
--- a/cli/cli/buildfile
+++ b/cli/cli/buildfile
@@ -15,63 +15,146 @@ exe{cli}:
cli.checksum = $version
}
-libue{cli}: {hxx ixx txx cxx}{** -cli -version -options -**.test...} \
- {hxx}{version} {hxx ixx cxx}{options} \
- $libs
+hdr = {hxx ixx txx}{* -cli -version -options -*.test...}
+src = cxx{* -cli -version -options -*.test...}
+
+all_s = semantics/{hxx ixx txx cxx}{*}
+all_t = traversal/{hxx ixx txx cxx}{*}
+
+libue{cli}: $hdr $src $all_s $all_t {hxx}{version} $libs
hxx{version}: in{version} $src_root/manifest
-# Unit tests.
+# Build options (apply to both bootstrap and final version).
#
-exe{*.test}:
+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
+# pregenerated/cli/.
+#
+# 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 using regenerated
+# options.?xx.
+#
+pregenerated/
{
- test = true
- install = false
+ # This should only apply to the bootstrap build.
+ #
+ cxx.poptions =+ "-I$src_base" # Note: must come first.
+
+ 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
+
+ obj{options}: {hxx ixx cxx}{options}
+
+ obj{cli}: cxx.poptions += -DCLI_BOOTSTRAP
+ }
}
-for t: cxx{**.test...}
+# 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}
{
- d = $directory($t)
- n = $name($t)...
+ dist = ($develop ? pregenerated/cli/ : false)
- ./: $d/exe{$n}: $t $d/{hxx ixx txx}{+$n} $d/testscript{+$n}
- $d/exe{$n}: libue{cli}: bin.whole = false
+ # Symlink the generated code in src for convenience of development.
+ #
+ backlink = true
}
+%
+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.
+ #
+ 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
+
+ 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.
#
+##
+
# Pass the copyright notice extracted from the LICENSE file.
#
-copyright = $process.run_regex(cat $src_root/LICENSE, \
- 'Copyright \(c\) (.+)\.', \
- '\1')
-
obj{cli}: cxx.poptions += -DCLI_COPYRIGHT=\"$copyright\"
-# Generated options parsing code.
-#
-# @@ This will eventually be replaced with an ah hoc recipe.
+# Unit tests.
#
-if ($config.cli != [null] && $config.cli != false)
+exe{*.test}:
{
- cli.cxx{options}: cli{options}
-
- cli.options += --include-with-brackets --include-prefix cli \
---guard-prefix CLI --generate-file-scanner --generate-specifier \
---generate-modifier --suppress-undocumented --reserved-name stdout
+ test = true
+ install = false
+}
- cli.cxx{*}:
- {
- # Include the generated cli files into the distribution and don't remove
- # them when cleaning in src (so that clean results in a state identical to
- # distributed).
- #
- dist = true
- clean = ($src_root != $out_root)
+for t: cxx{**.test...}
+{
+ d = $directory($t)
+ n = $name($t)...
- # We keep the generated code in the repository so copy it back to src
- # in case of a forwarded configuration.
- #
- backlink = overwrite
- }
+ ./: $d/exe{$n}: $t $d/{hxx ixx txx}{+$n} $d/testscript{+$n}
+ $d/exe{$n}: libue{cli}: bin.whole = false
}
diff --git a/cli/cli/cli.cxx b/cli/cli/cli.cxx
index 754c5ff..d56f9e2 100644
--- a/cli/cli/cli.cxx
+++ b/cli/cli/cli.cxx
@@ -6,9 +6,10 @@
#include <string>
#include <memory> // unique_ptr
#include <fstream>
+#include <utility> // move()
#include <iostream>
-#include <cutl/compiler/code-stream.hxx>
+#include <libcutl/compiler/code-stream.hxx>
#include <cli/semantics/doc.hxx>
@@ -16,7 +17,13 @@
#include <cli/parser.hxx>
#include <cli/generator.hxx>
-#include <cli/version.hxx>
+#ifndef CLI_BOOTSTRAP
+# include <cli/version.hxx>
+#else
+# define CLI_VERSION_ID 0
+# define CLI_VERSION_FULL 0
+# define CLI_COPYRIGHT ""
+#endif
using namespace std;
using namespace cutl;
@@ -115,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.
//
@@ -137,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 54bb988..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),
@@ -296,6 +311,59 @@ process_link_target (const string& tg)
return found ? r : tg;
}
+void context::
+preprocess_ascii_tree (string& s)
+{
+ // tree --charset=UTF-8 uses the following box-drawing characters (see
+ // color.c):
+ //
+ // CHAR UTF-8 ASCII
+ //----------------------------
+ //
+ // | E29482 |
+ //
+ // -- E29480 -
+ //
+ // |- E2949C |
+ //
+ // |_ E29494 `
+ //
+ // <nbspace> C2A0 <space>
+ //
+ // Note that here we rely on the fact that neither E2 nor C2 can appear as
+ // continuation bytes.
+ //
+ for (size_t i (0); i != s.size (); ++i)
+ {
+ i = s.find_first_of ("\xE2\xC2", i);
+
+ if (i == string::npos)
+ break;
+
+ if (s[i] == '\xE2')
+ {
+ if (s[i + 1] == '\x94')
+ {
+ const char* r;
+ switch (s[i + 2])
+ {
+ case '\x80': r = "-"; break;
+ case '\x82':
+ case '\x9c': r = "|"; break;
+ case '\x94': r = "`"; break;
+ default: continue;
+ }
+
+ s.replace (i, 3, r);
+ }
+ }
+ else
+ {
+ if (s[i + 1] == '\xA0')
+ s.replace (i, 2, " ");
+ }
+ }
+}
string context::
translate_arg (string const& s, std::set<string>& set)
@@ -1270,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)
@@ -1532,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 ||
@@ -1644,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:
{
@@ -1652,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:
@@ -1919,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;
@@ -2016,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;
@@ -2136,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 ())
{
@@ -2147,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;
}
}
@@ -2173,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 633b8ad..c5802ed 100644
--- a/cli/cli/context.hxx
+++ b/cli/cli/context.hxx
@@ -12,9 +12,9 @@
#include <ostream>
#include <cstddef> // std::size_t
-#include <cutl/re.hxx>
-#include <cutl/shared-ptr.hxx>
-#include <cutl/fs/path.hxx>
+#include <libcutl/re.hxx>
+#include <libcutl/shared-ptr.hxx>
+#include <libcutl/fs/path.hxx>
#include <cli/options.hxx>
#include <cli/semantics.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_;
@@ -153,10 +157,13 @@ public:
string
process_link_target (const string&);
- // Translate and format the documentation string. Translate converts
- // the <arg>-style constructs to \i{arg}. Format converts the string
- // to the output format.
+ // Preprocess, translate, and format the documentation string. Translate
+ // converts the <arg>-style constructs to \i{arg}. Format converts the
+ // string to the output format.
//
+ static void
+ preprocess_ascii_tree (string&);
+
static string
translate_arg (string const&, std::set<string>&);
diff --git a/cli/cli/generator.cxx b/cli/cli/generator.cxx
index df1b99e..623ac67 100644
--- a/cli/cli/generator.cxx
+++ b/cli/cli/generator.cxx
@@ -2,15 +2,16 @@
// 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 <cutl/fs/auto-remove.hxx>
+#include <libcutl/fs/auto-remove.hxx>
-#include <cutl/compiler/code-stream.hxx>
-#include <cutl/compiler/cxx-indenter.hxx>
+#include <libcutl/compiler/code-stream.hxx>
+#include <libcutl/compiler/cxx-indenter.hxx>
#include <cli/header.hxx>
#include <cli/inline.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/html.cxx b/cli/cli/html.cxx
index b374b91..48eb5e3 100644
--- a/cli/cli/html.cxx
+++ b/cli/cli/html.cxx
@@ -127,13 +127,16 @@ namespace
// n > 2 - arg string, short string, long string
//
size_t n (ds.size ());
- const string& d (
+ string d (
n == 1
? (cd_ == cd_short ? first_sentence (ds[0]) : ds[0])
: (n == 2
? (cd_ == cd_short ? first_sentence (ds[1]) : ds[1])
: ds[cd_ == cd_short ? 1 : 2]));
+ if (options.ascii_tree ())
+ preprocess_ascii_tree (d);
+
std::set<string> arg_set;
if (n > 1)
translate_arg (ds[0], arg_set);
@@ -211,6 +214,8 @@ namespace
if (type != "bool" || doc.size () >= 3)
{
+ // Note: we naturally assume this doesn't need --ascii-tree treatment.
+ //
string s (
translate_arg (
doc.size () > 0 ? doc[0] : string ("<arg>"), arg_set));
@@ -236,6 +241,9 @@ namespace
d = (cd_ == cd_short ? first_sentence (doc[1]) : doc[1]);
}
+ if (options.ascii_tree ())
+ preprocess_ascii_tree (d);
+
// Format the documentation string.
//
d = format (o.scope (), escape_html (translate (d, arg_set)), false);
diff --git a/cli/cli/inline.cxx b/cli/cli/inline.cxx
index 05b83db..35b8caf 100644
--- a/cli/cli/inline.cxx
+++ b/cli/cli/inline.cxx
@@ -34,7 +34,7 @@ namespace
<< "}";
os << inl << "void " << scope << "::" << endl
- << name << "(const " << type << "& x)"
+ << name << " (const " << type << "& x)"
<< "{"
<< "this->" << emember (o) << " = x;"
<< "}";
@@ -52,7 +52,7 @@ namespace
if (gen_modifier)
os << inl << "void " << scope << "::" << endl
- << spec << "(bool x)"
+ << spec << " (bool x)"
<< "{"
<< "this->" << especifier_member (o) << " = x;"
<< "}";
diff --git a/cli/cli/lexer.test.cxx b/cli/cli/lexer.test.cxx
index 0eb4dcb..a5cc2f3 100644
--- a/cli/cli/lexer.test.cxx
+++ b/cli/cli/lexer.test.cxx
@@ -8,6 +8,9 @@
#include <cli/token.hxx>
#include <cli/lexer.hxx>
+#undef NDEBUG
+#include <cassert>
+
using namespace std;
const char* keywords[] =
diff --git a/cli/cli/man.cxx b/cli/cli/man.cxx
index df703e8..d446b2a 100644
--- a/cli/cli/man.cxx
+++ b/cli/cli/man.cxx
@@ -91,13 +91,16 @@ namespace
// n > 2 - arg string, short string, long string
//
size_t n (ds.size ());
- const string& d (
+ string d (
n == 1
? (cd_ == cd_short ? first_sentence (ds[0]) : ds[0])
: (n == 2
? (cd_ == cd_short ? first_sentence (ds[1]) : ds[1])
: ds[cd_ == cd_short ? 1 : 2]));
+ if (options.ascii_tree ())
+ preprocess_ascii_tree (d);
+
std::set<string> arg_set;
if (n > 1)
translate_arg (ds[0], arg_set);
@@ -149,6 +152,8 @@ namespace
if (type != "bool" || doc.size () >= 3)
{
+ // Note: we naturally assume this doesn't need --ascii-tree treatment.
+ //
string s (
translate_arg (
doc.size () > 0 ? doc[0] : string ("<arg>"), arg_set));
@@ -174,6 +179,9 @@ namespace
d = (cd_ == cd_short ? first_sentence (doc[1]) : doc[1]);
}
+ if (options.ascii_tree ())
+ preprocess_ascii_tree (d);
+
// Format the documentation string.
//
d = format (o.scope (), translate (d, arg_set), false);
diff --git a/cli/cli/options.cli b/cli/cli/options.cli
index ff462d3..211e01f 100644
--- a/cli/cli/options.cli
+++ b/cli/cli/options.cli
@@ -108,11 +108,15 @@ class options
{ -f }+ { -b }+ arg +{ f=1 } +{ b=2 } # 'arg' with '-f' 'b' 'f=1' 'b=2'
\
- Note that the group applies to a single argument only. For example:
+ The group applies to a single argument only unless multiple arguments
+ are themselves grouped with '\cb{{}' and '\cb{\}}'. For example:
\
- { --foo }+ arg1 arg2 +{ --bar } # 'arg1' with '--foo' and
- # 'arg2' with '--bar'
+ { --foo }+ arg1 arg2 +{ --bar } # 'arg1' with '--foo'
+ # 'arg2' with '--bar'
+
+ { --foo }+ { arg1 arg2 } +{ --bar } # 'arg1' with '--foo' '--bar'
+ # 'arg2' with '--foo' '--bar'
\
The group separators ('\cb{{}', '\cb{\}+'}, etc) must be separate command
@@ -167,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},
@@ -188,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
@@ -253,6 +276,13 @@ class options
files, and would like their usage to have the same indentation level."
};
+ bool --ascii-tree
+ {
+ "Convert UTF-8 \cb{tree(1)} output to ASCII. Specifically, box-drawing
+ characters used in the \cb{--charset=UTF-8} output are replaced with
+ ASCII characters used in the \cb{--charset=ASCII} output."
+ };
+
bool --ansi-color
{
"Use ANSI color escape sequences when printing usage. By \"color\" we
@@ -568,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 6ef0d11..44109b3 100644
--- a/cli/cli/parser.test.cxx
+++ b/cli/cli/parser.test.cxx
@@ -9,6 +9,9 @@
#include <cli/semantics.hxx>
#include <cli/traversal.hxx>
+#undef NDEBUG
+#include <cassert>
+
using namespace std;
int
@@ -29,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/options.cxx b/cli/cli/pregenerated/cli/options.cxx
index d64e801..9f0be5f 100644
--- a/cli/cli/options.cxx
+++ b/cli/cli/pregenerated/cli/options.cxx
@@ -15,6 +15,7 @@
#include <set>
#include <string>
#include <vector>
+#include <utility>
#include <ostream>
#include <sstream>
#include <cstring>
@@ -196,6 +197,7 @@ namespace cli
else
++i_;
+ ++start_position_;
return r;
}
else
@@ -206,11 +208,20 @@ namespace cli
skip ()
{
if (i_ < argc_)
+ {
++i_;
+ ++start_position_;
+ }
else
throw eos_reached ();
}
+ std::size_t argv_scanner::
+ position ()
+ {
+ return start_position_;
+ }
+
// argv_file_scanner
//
int argv_file_scanner::zero_argc_ = 0;
@@ -321,6 +332,7 @@ namespace cli
{
hold_[i_ == 0 ? ++i_ : --i_].swap (args_.front ().value);
args_.pop_front ();
+ ++start_position_;
return hold_[i_].c_str ();
}
}
@@ -334,7 +346,10 @@ namespace cli
if (args_.empty ())
return base::skip ();
else
+ {
args_.pop_front ();
+ ++start_position_;
+ }
}
const argv_file_scanner::option_info* argv_file_scanner::
@@ -347,6 +362,12 @@ namespace cli
return 0;
}
+ std::size_t argv_file_scanner::
+ position ()
+ {
+ return start_position_;
+ }
+
void argv_file_scanner::
load (const std::string& file)
{
@@ -459,12 +480,28 @@ namespace cli
if (oi->search_func != 0)
{
- std::string f (oi->search_func (s2.c_str (), oi->arg));
+ string f (oi->search_func (s2.c_str (), oi->arg));
if (!f.empty ())
load (f);
}
else
+ {
+ // If the path of the file being parsed is not simple and the
+ // path of the file that needs to be loaded is relative, then
+ // complete the latter using the former as a base.
+ //
+#ifndef _WIN32
+ string::size_type p (file.find_last_of ('/'));
+ bool c (p != string::npos && s2[0] != '/');
+#else
+ string::size_type p (file.find_last_of ("/\\"));
+ bool c (p != string::npos && s2[1] != ':');
+#endif
+ if (c)
+ s2.insert (0, file, 0, p + 1);
+
load (s2);
+ }
continue;
}
@@ -505,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;
}
};
@@ -530,6 +588,17 @@ namespace cli
};
template <typename X>
+ struct parser<std::pair<X, std::size_t> >
+ {
+ static void
+ parse (std::pair<X, std::size_t>& x, bool& xs, scanner& s)
+ {
+ x.second = s.position ();
+ parser<X>::parse (x.first, xs, s);
+ }
+ };
+
+ template <typename X>
struct parser<std::vector<X> >
{
static void
@@ -543,11 +612,11 @@ namespace cli
}
};
- template <typename X>
- struct parser<std::set<X> >
+ template <typename X, typename C>
+ struct parser<std::set<X, C> >
{
static void
- parse (std::set<X>& c, bool& xs, scanner& s)
+ parse (std::set<X, C>& c, bool& xs, scanner& s)
{
X x;
bool dummy;
@@ -557,16 +626,17 @@ namespace cli
}
};
- template <typename K, typename V>
- struct parser<std::map<K, V> >
+ template <typename K, typename V, typename C>
+ struct parser<std::map<K, V, C> >
{
static void
- parse (std::map<K, V>& m, bool& xs, scanner& s)
+ parse (std::map<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 ('=');
@@ -586,14 +656,14 @@ namespace cli
if (!kstr.empty ())
{
av[1] = const_cast<char*> (kstr.c_str ());
- argv_scanner s (0, ac, av);
+ 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);
+ argv_scanner s (0, ac, av, false, pos);
parser<V>::parse (v, dummy, s);
}
@@ -606,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)
@@ -613,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)
@@ -622,7 +750,6 @@ namespace cli
}
#include <map>
-#include <cstring>
// options
//
@@ -653,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_ (),
@@ -666,6 +796,7 @@ options ()
page_usage_specified_ (false),
option_length_ (0),
option_length_specified_ (false),
+ ascii_tree_ (),
ansi_color_ (),
exclude_base_ (),
include_base_last_ (),
@@ -745,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_ ("--"),
@@ -794,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_ (),
@@ -807,6 +945,7 @@ options (int& argc,
page_usage_specified_ (false),
option_length_ (0),
option_length_specified_ (false),
+ ascii_tree_ (),
ansi_color_ (),
exclude_base_ (),
include_base_last_ (),
@@ -886,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_ ("--"),
@@ -938,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_ (),
@@ -951,6 +1097,7 @@ options (int start,
page_usage_specified_ (false),
option_length_ (0),
option_length_specified_ (false),
+ ascii_tree_ (),
ansi_color_ (),
exclude_base_ (),
include_base_last_ (),
@@ -1030,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_ ("--"),
@@ -1082,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_ (),
@@ -1095,6 +1249,7 @@ options (int& argc,
page_usage_specified_ (false),
option_length_ (0),
option_length_specified_ (false),
+ ascii_tree_ (),
ansi_color_ (),
exclude_base_ (),
include_base_last_ (),
@@ -1174,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_ ("--"),
@@ -1228,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_ (),
@@ -1241,6 +1403,7 @@ options (int start,
page_usage_specified_ (false),
option_length_ (0),
option_length_specified_ (false),
+ ascii_tree_ (),
ansi_color_ (),
exclude_base_ (),
include_base_last_ (),
@@ -1320,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_ ("--"),
@@ -1370,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_ (),
@@ -1383,6 +1553,7 @@ options (::cli::scanner& s,
page_usage_specified_ (false),
option_length_ (0),
option_length_specified_ (false),
+ ascii_tree_ (),
ansi_color_ (),
exclude_base_ (),
include_base_last_ (),
@@ -1462,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_ ("--"),
@@ -1535,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;
@@ -1544,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
@@ -1564,6 +1745,8 @@ print_usage (::std::ostream& os, ::cli::usage_para p)
os << "--option-length <len> Indent option descriptions <len> characters when" << ::std::endl
<< " printing usage." << ::std::endl;
+ os << "--ascii-tree Convert UTF-8 tree(1) output to ASCII." << ::std::endl;
+
os << "--ansi-color Use ANSI color escape sequences when printing" << ::std::endl
<< " usage." << ::std::endl;
@@ -1692,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;
@@ -1742,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_ >;
@@ -1761,61 +1951,68 @@ 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_ >;
_cli_options_map_["--option-length"] =
&::cli::thunk< options, std::size_t, &options::option_length_,
&options::option_length_specified_ >;
+ _cli_options_map_["--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_ >;
@@ -1832,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_ >;
@@ -1934,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_ >;
@@ -1941,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/options.hxx b/cli/cli/pregenerated/cli/options.hxx
index b54d81f..f44258f 100644
--- a/cli/cli/options.hxx
+++ b/cli/cli/pregenerated/cli/options.hxx
@@ -236,6 +236,14 @@ namespace cli
// for the two previous arguments up until a call to a third
// peek() or next().
//
+ // The position() function returns a monotonically-increasing
+ // number which, if stored, can later be used to determine the
+ // relative position of the argument returned by the following
+ // call to next(). Note that if multiple scanners are used to
+ // extract arguments from multiple sources, then the end
+ // position of the previous scanner should be used as the
+ // start position of the next.
+ //
class scanner
{
public:
@@ -253,13 +261,24 @@ namespace cli
virtual void
skip () = 0;
+
+ virtual std::size_t
+ position () = 0;
};
class argv_scanner: public scanner
{
public:
- argv_scanner (int& argc, char** argv, bool erase = false);
- argv_scanner (int start, int& argc, char** argv, bool erase = false);
+ argv_scanner (int& argc,
+ char** argv,
+ bool erase = false,
+ std::size_t start_position = 0);
+
+ argv_scanner (int start,
+ int& argc,
+ char** argv,
+ bool erase = false,
+ std::size_t start_position = 0);
int
end () const;
@@ -276,7 +295,11 @@ namespace cli
virtual void
skip ();
- private:
+ virtual std::size_t
+ position ();
+
+ protected:
+ std::size_t start_position_;
int i_;
int& argc_;
char** argv_;
@@ -289,16 +312,19 @@ namespace cli
argv_file_scanner (int& argc,
char** argv,
const std::string& option,
- bool erase = false);
+ bool erase = false,
+ std::size_t start_position = 0);
argv_file_scanner (int start,
int& argc,
char** argv,
const std::string& option,
- bool erase = false);
+ bool erase = false,
+ std::size_t start_position = 0);
argv_file_scanner (const std::string& file,
- const std::string& option);
+ const std::string& option,
+ std::size_t start_position = 0);
struct option_info
{
@@ -315,18 +341,21 @@ namespace cli
char** argv,
const option_info* options,
std::size_t options_count,
- bool erase = false);
+ bool erase = false,
+ std::size_t start_position = 0);
argv_file_scanner (int start,
int& argc,
char** argv,
const option_info* options,
std::size_t options_count,
- bool erase = false);
+ bool erase = false,
+ std::size_t start_position = 0);
argv_file_scanner (const std::string& file,
const option_info* options = 0,
- std::size_t options_count = 0);
+ std::size_t options_count = 0,
+ std::size_t start_position = 0);
virtual bool
more ();
@@ -340,6 +369,9 @@ namespace cli
virtual void
skip ();
+ virtual std::size_t
+ position ();
+
// Return the file path if the peeked at argument came from a file and
// the empty string otherwise. The reference is guaranteed to be valid
// till the end of the scanner lifetime.
@@ -641,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;
@@ -678,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&
@@ -753,6 +809,15 @@ class options
option_length_specified (bool);
const bool&
+ ascii_tree () const;
+
+ bool&
+ ascii_tree ();
+
+ void
+ ascii_tree (const bool&);
+
+ const bool&
ansi_color () const;
bool&
@@ -1353,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&
@@ -1521,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_;
@@ -1534,6 +1632,7 @@ class options
bool page_usage_specified_;
std::size_t option_length_;
bool option_length_specified_;
+ bool ascii_tree_;
bool ansi_color_;
bool exclude_base_;
bool include_base_last_;
@@ -1613,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/options.ixx b/cli/cli/pregenerated/cli/options.ixx
index 5916883..54fa54a 100644
--- a/cli/cli/options.ixx
+++ b/cli/cli/pregenerated/cli/options.ixx
@@ -141,14 +141,29 @@ namespace cli
// argv_scanner
//
inline argv_scanner::
- argv_scanner (int& argc, char** argv, bool erase)
- : i_ (1), argc_ (argc), argv_ (argv), erase_ (erase)
+ argv_scanner (int& argc,
+ char** argv,
+ bool erase,
+ std::size_t sp)
+ : start_position_ (sp + 1),
+ i_ (1),
+ argc_ (argc),
+ argv_ (argv),
+ erase_ (erase)
{
}
inline argv_scanner::
- argv_scanner (int start, int& argc, char** argv, bool erase)
- : i_ (start), argc_ (argc), argv_ (argv), erase_ (erase)
+ argv_scanner (int start,
+ int& argc,
+ char** argv,
+ bool erase,
+ std::size_t sp)
+ : start_position_ (sp + static_cast<std::size_t> (start)),
+ i_ (start),
+ argc_ (argc),
+ argv_ (argv),
+ erase_ (erase)
{
}
@@ -164,8 +179,9 @@ namespace cli
argv_file_scanner (int& argc,
char** argv,
const std::string& option,
- bool erase)
- : argv_scanner (argc, argv, erase),
+ bool erase,
+ std::size_t sp)
+ : argv_scanner (argc, argv, erase, sp),
option_ (option),
options_ (&option_info_),
options_count_ (1),
@@ -181,8 +197,9 @@ namespace cli
int& argc,
char** argv,
const std::string& option,
- bool erase)
- : argv_scanner (start, argc, argv, erase),
+ bool erase,
+ std::size_t sp)
+ : argv_scanner (start, argc, argv, erase, sp),
option_ (option),
options_ (&option_info_),
options_count_ (1),
@@ -195,8 +212,9 @@ namespace cli
inline argv_file_scanner::
argv_file_scanner (const std::string& file,
- const std::string& option)
- : argv_scanner (0, zero_argc_, 0),
+ const std::string& option,
+ std::size_t sp)
+ : argv_scanner (0, zero_argc_, 0, sp),
option_ (option),
options_ (&option_info_),
options_count_ (1),
@@ -214,8 +232,9 @@ namespace cli
char** argv,
const option_info* options,
std::size_t options_count,
- bool erase)
- : argv_scanner (argc, argv, erase),
+ bool erase,
+ std::size_t sp)
+ : argv_scanner (argc, argv, erase, sp),
options_ (options),
options_count_ (options_count),
i_ (1),
@@ -229,8 +248,9 @@ namespace cli
char** argv,
const option_info* options,
std::size_t options_count,
- bool erase)
- : argv_scanner (start, argc, argv, erase),
+ bool erase,
+ std::size_t sp)
+ : argv_scanner (start, argc, argv, erase, sp),
options_ (options),
options_count_ (options_count),
i_ (1),
@@ -241,8 +261,9 @@ namespace cli
inline argv_file_scanner::
argv_file_scanner (const std::string& file,
const option_info* options,
- std::size_t options_count)
- : argv_scanner (0, zero_argc_, 0),
+ std::size_t options_count,
+ std::size_t sp)
+ : argv_scanner (0, zero_argc_, 0, sp),
options_ (options),
options_count_ (options_count),
i_ (1),
@@ -268,7 +289,7 @@ build2_metadata ()
}
inline void options::
-build2_metadata(const std::uint64_t& x)
+build2_metadata (const std::uint64_t& x)
{
this->build2_metadata_ = x;
}
@@ -280,7 +301,7 @@ build2_metadata_specified () const
}
inline void options::
-build2_metadata_specified(bool x)
+build2_metadata_specified (bool x)
{
this->build2_metadata_specified_ = x;
}
@@ -298,7 +319,7 @@ help ()
}
inline void options::
-help(const bool& x)
+help (const bool& x)
{
this->help_ = x;
}
@@ -316,7 +337,7 @@ version ()
}
inline void options::
-version(const bool& x)
+version (const bool& x)
{
this->version_ = x;
}
@@ -334,7 +355,7 @@ include_path ()
}
inline void options::
-include_path(const std::vector<std::string>& x)
+include_path (const std::vector<std::string>& x)
{
this->include_path_ = x;
}
@@ -346,7 +367,7 @@ include_path_specified () const
}
inline void options::
-include_path_specified(bool x)
+include_path_specified (bool x)
{
this->include_path_specified_ = x;
}
@@ -364,7 +385,7 @@ output_dir ()
}
inline void options::
-output_dir(const std::string& x)
+output_dir (const std::string& x)
{
this->output_dir_ = x;
}
@@ -376,7 +397,7 @@ output_dir_specified () const
}
inline void options::
-output_dir_specified(bool x)
+output_dir_specified (bool x)
{
this->output_dir_specified_ = x;
}
@@ -394,7 +415,7 @@ std ()
}
inline void options::
-std(const cxx_version& x)
+std (const cxx_version& x)
{
this->std_ = x;
}
@@ -406,7 +427,7 @@ std_specified () const
}
inline void options::
-std_specified(bool x)
+std_specified (bool x)
{
this->std_specified_ = x;
}
@@ -424,7 +445,7 @@ generate_modifier ()
}
inline void options::
-generate_modifier(const bool& x)
+generate_modifier (const bool& x)
{
this->generate_modifier_ = x;
}
@@ -442,7 +463,7 @@ generate_specifier ()
}
inline void options::
-generate_specifier(const bool& x)
+generate_specifier (const bool& x)
{
this->generate_specifier_ = x;
}
@@ -460,7 +481,7 @@ generate_parse ()
}
inline void options::
-generate_parse(const bool& x)
+generate_parse (const bool& x)
{
this->generate_parse_ = x;
}
@@ -478,7 +499,7 @@ generate_merge ()
}
inline void options::
-generate_merge(const bool& x)
+generate_merge (const bool& x)
{
this->generate_merge_ = x;
}
@@ -496,7 +517,7 @@ generate_description ()
}
inline void options::
-generate_description(const bool& x)
+generate_description (const bool& x)
{
this->generate_description_ = x;
}
@@ -514,7 +535,7 @@ generate_file_scanner ()
}
inline void options::
-generate_file_scanner(const bool& x)
+generate_file_scanner (const bool& x)
{
this->generate_file_scanner_ = x;
}
@@ -532,7 +553,7 @@ generate_vector_scanner ()
}
inline void options::
-generate_vector_scanner(const bool& x)
+generate_vector_scanner (const bool& x)
{
this->generate_vector_scanner_ = x;
}
@@ -550,7 +571,7 @@ generate_group_scanner ()
}
inline void options::
-generate_group_scanner(const bool& x)
+generate_group_scanner (const bool& x)
{
this->generate_group_scanner_ = x;
}
@@ -568,7 +589,7 @@ suppress_inline ()
}
inline void options::
-suppress_inline(const bool& x)
+suppress_inline (const bool& x)
{
this->suppress_inline_ = x;
}
@@ -586,7 +607,7 @@ suppress_cli ()
}
inline void options::
-suppress_cli(const bool& x)
+suppress_cli (const bool& x)
{
this->suppress_cli_ = x;
}
@@ -604,7 +625,7 @@ cli_namespace ()
}
inline void options::
-cli_namespace(const std::string& x)
+cli_namespace (const std::string& x)
{
this->cli_namespace_ = x;
}
@@ -616,7 +637,7 @@ cli_namespace_specified () const
}
inline void options::
-cli_namespace_specified(bool x)
+cli_namespace_specified (bool x)
{
this->cli_namespace_specified_ = x;
}
@@ -634,7 +655,7 @@ ostream_type ()
}
inline void options::
-ostream_type(const std::string& x)
+ostream_type (const std::string& x)
{
this->ostream_type_ = x;
}
@@ -646,11 +667,41 @@ ostream_type_specified () const
}
inline void options::
-ostream_type_specified(bool x)
+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
{
@@ -664,7 +715,7 @@ generate_cxx ()
}
inline void options::
-generate_cxx(const bool& x)
+generate_cxx (const bool& x)
{
this->generate_cxx_ = x;
}
@@ -682,7 +733,7 @@ generate_man ()
}
inline void options::
-generate_man(const bool& x)
+generate_man (const bool& x)
{
this->generate_man_ = x;
}
@@ -700,7 +751,7 @@ generate_html ()
}
inline void options::
-generate_html(const bool& x)
+generate_html (const bool& x)
{
this->generate_html_ = x;
}
@@ -718,12 +769,30 @@ generate_txt ()
}
inline void options::
-generate_txt(const bool& x)
+generate_txt (const bool& x)
{
this->generate_txt_ = 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__;
@@ -736,7 +805,7 @@ stdout_ ()
}
inline void options::
-stdout_(const bool& x)
+stdout_ (const bool& x)
{
this->stdout__ = x;
}
@@ -754,7 +823,7 @@ suppress_undocumented ()
}
inline void options::
-suppress_undocumented(const bool& x)
+suppress_undocumented (const bool& x)
{
this->suppress_undocumented_ = x;
}
@@ -772,7 +841,7 @@ suppress_usage ()
}
inline void options::
-suppress_usage(const bool& x)
+suppress_usage (const bool& x)
{
this->suppress_usage_ = x;
}
@@ -790,7 +859,7 @@ long_usage ()
}
inline void options::
-long_usage(const bool& x)
+long_usage (const bool& x)
{
this->long_usage_ = x;
}
@@ -808,7 +877,7 @@ short_usage ()
}
inline void options::
-short_usage(const bool& x)
+short_usage (const bool& x)
{
this->short_usage_ = x;
}
@@ -826,7 +895,7 @@ page_usage ()
}
inline void options::
-page_usage(const std::string& x)
+page_usage (const std::string& x)
{
this->page_usage_ = x;
}
@@ -838,7 +907,7 @@ page_usage_specified () const
}
inline void options::
-page_usage_specified(bool x)
+page_usage_specified (bool x)
{
this->page_usage_specified_ = x;
}
@@ -856,7 +925,7 @@ option_length ()
}
inline void options::
-option_length(const std::size_t& x)
+option_length (const std::size_t& x)
{
this->option_length_ = x;
}
@@ -868,12 +937,30 @@ option_length_specified () const
}
inline void options::
-option_length_specified(bool x)
+option_length_specified (bool x)
{
this->option_length_specified_ = x;
}
inline const bool& options::
+ascii_tree () const
+{
+ return this->ascii_tree_;
+}
+
+inline bool& options::
+ascii_tree ()
+{
+ return this->ascii_tree_;
+}
+
+inline void options::
+ascii_tree (const bool& x)
+{
+ this->ascii_tree_ = x;
+}
+
+inline const bool& options::
ansi_color () const
{
return this->ansi_color_;
@@ -886,7 +973,7 @@ ansi_color ()
}
inline void options::
-ansi_color(const bool& x)
+ansi_color (const bool& x)
{
this->ansi_color_ = x;
}
@@ -904,7 +991,7 @@ exclude_base ()
}
inline void options::
-exclude_base(const bool& x)
+exclude_base (const bool& x)
{
this->exclude_base_ = x;
}
@@ -922,7 +1009,7 @@ include_base_last ()
}
inline void options::
-include_base_last(const bool& x)
+include_base_last (const bool& x)
{
this->include_base_last_ = x;
}
@@ -940,7 +1027,7 @@ class_doc ()
}
inline void options::
-class_doc(const std::map<std::string, std::string>& x)
+class_doc (const std::map<std::string, std::string>& x)
{
this->class_doc_ = x;
}
@@ -952,7 +1039,7 @@ class_doc_specified () const
}
inline void options::
-class_doc_specified(bool x)
+class_doc_specified (bool x)
{
this->class_doc_specified_ = x;
}
@@ -970,7 +1057,7 @@ class_ ()
}
inline void options::
-class_(const std::vector<std::string>& x)
+class_ (const std::vector<std::string>& x)
{
this->class__ = x;
}
@@ -982,7 +1069,7 @@ class__specified () const
}
inline void options::
-class__specified(bool x)
+class__specified (bool x)
{
this->class__specified_ = x;
}
@@ -1000,7 +1087,7 @@ docvar ()
}
inline void options::
-docvar(const std::map<std::string, std::string>& x)
+docvar (const std::map<std::string, std::string>& x)
{
this->docvar_ = x;
}
@@ -1012,7 +1099,7 @@ docvar_specified () const
}
inline void options::
-docvar_specified(bool x)
+docvar_specified (bool x)
{
this->docvar_specified_ = x;
}
@@ -1030,7 +1117,7 @@ link_regex ()
}
inline void options::
-link_regex(const std::vector<std::string>& x)
+link_regex (const std::vector<std::string>& x)
{
this->link_regex_ = x;
}
@@ -1042,7 +1129,7 @@ link_regex_specified () const
}
inline void options::
-link_regex_specified(bool x)
+link_regex_specified (bool x)
{
this->link_regex_specified_ = x;
}
@@ -1060,7 +1147,7 @@ link_regex_trace ()
}
inline void options::
-link_regex_trace(const bool& x)
+link_regex_trace (const bool& x)
{
this->link_regex_trace_ = x;
}
@@ -1078,7 +1165,7 @@ html_heading_map ()
}
inline void options::
-html_heading_map(const std::map<char, std::string>& x)
+html_heading_map (const std::map<char, std::string>& x)
{
this->html_heading_map_ = x;
}
@@ -1090,7 +1177,7 @@ html_heading_map_specified () const
}
inline void options::
-html_heading_map_specified(bool x)
+html_heading_map_specified (bool x)
{
this->html_heading_map_specified_ = x;
}
@@ -1108,7 +1195,7 @@ omit_link_check ()
}
inline void options::
-omit_link_check(const bool& x)
+omit_link_check (const bool& x)
{
this->omit_link_check_ = x;
}
@@ -1126,7 +1213,7 @@ hxx_prologue ()
}
inline void options::
-hxx_prologue(const std::vector<std::string>& x)
+hxx_prologue (const std::vector<std::string>& x)
{
this->hxx_prologue_ = x;
}
@@ -1138,7 +1225,7 @@ hxx_prologue_specified () const
}
inline void options::
-hxx_prologue_specified(bool x)
+hxx_prologue_specified (bool x)
{
this->hxx_prologue_specified_ = x;
}
@@ -1156,7 +1243,7 @@ ixx_prologue ()
}
inline void options::
-ixx_prologue(const std::vector<std::string>& x)
+ixx_prologue (const std::vector<std::string>& x)
{
this->ixx_prologue_ = x;
}
@@ -1168,7 +1255,7 @@ ixx_prologue_specified () const
}
inline void options::
-ixx_prologue_specified(bool x)
+ixx_prologue_specified (bool x)
{
this->ixx_prologue_specified_ = x;
}
@@ -1186,7 +1273,7 @@ cxx_prologue ()
}
inline void options::
-cxx_prologue(const std::vector<std::string>& x)
+cxx_prologue (const std::vector<std::string>& x)
{
this->cxx_prologue_ = x;
}
@@ -1198,7 +1285,7 @@ cxx_prologue_specified () const
}
inline void options::
-cxx_prologue_specified(bool x)
+cxx_prologue_specified (bool x)
{
this->cxx_prologue_specified_ = x;
}
@@ -1216,7 +1303,7 @@ man_prologue ()
}
inline void options::
-man_prologue(const std::vector<std::string>& x)
+man_prologue (const std::vector<std::string>& x)
{
this->man_prologue_ = x;
}
@@ -1228,7 +1315,7 @@ man_prologue_specified () const
}
inline void options::
-man_prologue_specified(bool x)
+man_prologue_specified (bool x)
{
this->man_prologue_specified_ = x;
}
@@ -1246,7 +1333,7 @@ html_prologue ()
}
inline void options::
-html_prologue(const std::vector<std::string>& x)
+html_prologue (const std::vector<std::string>& x)
{
this->html_prologue_ = x;
}
@@ -1258,7 +1345,7 @@ html_prologue_specified () const
}
inline void options::
-html_prologue_specified(bool x)
+html_prologue_specified (bool x)
{
this->html_prologue_specified_ = x;
}
@@ -1276,7 +1363,7 @@ txt_prologue ()
}
inline void options::
-txt_prologue(const std::vector<std::string>& x)
+txt_prologue (const std::vector<std::string>& x)
{
this->txt_prologue_ = x;
}
@@ -1288,7 +1375,7 @@ txt_prologue_specified () const
}
inline void options::
-txt_prologue_specified(bool x)
+txt_prologue_specified (bool x)
{
this->txt_prologue_specified_ = x;
}
@@ -1306,7 +1393,7 @@ hxx_epilogue ()
}
inline void options::
-hxx_epilogue(const std::vector<std::string>& x)
+hxx_epilogue (const std::vector<std::string>& x)
{
this->hxx_epilogue_ = x;
}
@@ -1318,7 +1405,7 @@ hxx_epilogue_specified () const
}
inline void options::
-hxx_epilogue_specified(bool x)
+hxx_epilogue_specified (bool x)
{
this->hxx_epilogue_specified_ = x;
}
@@ -1336,7 +1423,7 @@ ixx_epilogue ()
}
inline void options::
-ixx_epilogue(const std::vector<std::string>& x)
+ixx_epilogue (const std::vector<std::string>& x)
{
this->ixx_epilogue_ = x;
}
@@ -1348,7 +1435,7 @@ ixx_epilogue_specified () const
}
inline void options::
-ixx_epilogue_specified(bool x)
+ixx_epilogue_specified (bool x)
{
this->ixx_epilogue_specified_ = x;
}
@@ -1366,7 +1453,7 @@ cxx_epilogue ()
}
inline void options::
-cxx_epilogue(const std::vector<std::string>& x)
+cxx_epilogue (const std::vector<std::string>& x)
{
this->cxx_epilogue_ = x;
}
@@ -1378,7 +1465,7 @@ cxx_epilogue_specified () const
}
inline void options::
-cxx_epilogue_specified(bool x)
+cxx_epilogue_specified (bool x)
{
this->cxx_epilogue_specified_ = x;
}
@@ -1396,7 +1483,7 @@ man_epilogue ()
}
inline void options::
-man_epilogue(const std::vector<std::string>& x)
+man_epilogue (const std::vector<std::string>& x)
{
this->man_epilogue_ = x;
}
@@ -1408,7 +1495,7 @@ man_epilogue_specified () const
}
inline void options::
-man_epilogue_specified(bool x)
+man_epilogue_specified (bool x)
{
this->man_epilogue_specified_ = x;
}
@@ -1426,7 +1513,7 @@ html_epilogue ()
}
inline void options::
-html_epilogue(const std::vector<std::string>& x)
+html_epilogue (const std::vector<std::string>& x)
{
this->html_epilogue_ = x;
}
@@ -1438,7 +1525,7 @@ html_epilogue_specified () const
}
inline void options::
-html_epilogue_specified(bool x)
+html_epilogue_specified (bool x)
{
this->html_epilogue_specified_ = x;
}
@@ -1456,7 +1543,7 @@ txt_epilogue ()
}
inline void options::
-txt_epilogue(const std::vector<std::string>& x)
+txt_epilogue (const std::vector<std::string>& x)
{
this->txt_epilogue_ = x;
}
@@ -1468,7 +1555,7 @@ txt_epilogue_specified () const
}
inline void options::
-txt_epilogue_specified(bool x)
+txt_epilogue_specified (bool x)
{
this->txt_epilogue_specified_ = x;
}
@@ -1486,7 +1573,7 @@ hxx_prologue_file ()
}
inline void options::
-hxx_prologue_file(const std::string& x)
+hxx_prologue_file (const std::string& x)
{
this->hxx_prologue_file_ = x;
}
@@ -1498,7 +1585,7 @@ hxx_prologue_file_specified () const
}
inline void options::
-hxx_prologue_file_specified(bool x)
+hxx_prologue_file_specified (bool x)
{
this->hxx_prologue_file_specified_ = x;
}
@@ -1516,7 +1603,7 @@ ixx_prologue_file ()
}
inline void options::
-ixx_prologue_file(const std::string& x)
+ixx_prologue_file (const std::string& x)
{
this->ixx_prologue_file_ = x;
}
@@ -1528,7 +1615,7 @@ ixx_prologue_file_specified () const
}
inline void options::
-ixx_prologue_file_specified(bool x)
+ixx_prologue_file_specified (bool x)
{
this->ixx_prologue_file_specified_ = x;
}
@@ -1546,7 +1633,7 @@ cxx_prologue_file ()
}
inline void options::
-cxx_prologue_file(const std::string& x)
+cxx_prologue_file (const std::string& x)
{
this->cxx_prologue_file_ = x;
}
@@ -1558,7 +1645,7 @@ cxx_prologue_file_specified () const
}
inline void options::
-cxx_prologue_file_specified(bool x)
+cxx_prologue_file_specified (bool x)
{
this->cxx_prologue_file_specified_ = x;
}
@@ -1576,7 +1663,7 @@ man_prologue_file ()
}
inline void options::
-man_prologue_file(const std::string& x)
+man_prologue_file (const std::string& x)
{
this->man_prologue_file_ = x;
}
@@ -1588,7 +1675,7 @@ man_prologue_file_specified () const
}
inline void options::
-man_prologue_file_specified(bool x)
+man_prologue_file_specified (bool x)
{
this->man_prologue_file_specified_ = x;
}
@@ -1606,7 +1693,7 @@ html_prologue_file ()
}
inline void options::
-html_prologue_file(const std::string& x)
+html_prologue_file (const std::string& x)
{
this->html_prologue_file_ = x;
}
@@ -1618,7 +1705,7 @@ html_prologue_file_specified () const
}
inline void options::
-html_prologue_file_specified(bool x)
+html_prologue_file_specified (bool x)
{
this->html_prologue_file_specified_ = x;
}
@@ -1636,7 +1723,7 @@ txt_prologue_file ()
}
inline void options::
-txt_prologue_file(const std::string& x)
+txt_prologue_file (const std::string& x)
{
this->txt_prologue_file_ = x;
}
@@ -1648,7 +1735,7 @@ txt_prologue_file_specified () const
}
inline void options::
-txt_prologue_file_specified(bool x)
+txt_prologue_file_specified (bool x)
{
this->txt_prologue_file_specified_ = x;
}
@@ -1666,7 +1753,7 @@ hxx_epilogue_file ()
}
inline void options::
-hxx_epilogue_file(const std::string& x)
+hxx_epilogue_file (const std::string& x)
{
this->hxx_epilogue_file_ = x;
}
@@ -1678,7 +1765,7 @@ hxx_epilogue_file_specified () const
}
inline void options::
-hxx_epilogue_file_specified(bool x)
+hxx_epilogue_file_specified (bool x)
{
this->hxx_epilogue_file_specified_ = x;
}
@@ -1696,7 +1783,7 @@ ixx_epilogue_file ()
}
inline void options::
-ixx_epilogue_file(const std::string& x)
+ixx_epilogue_file (const std::string& x)
{
this->ixx_epilogue_file_ = x;
}
@@ -1708,7 +1795,7 @@ ixx_epilogue_file_specified () const
}
inline void options::
-ixx_epilogue_file_specified(bool x)
+ixx_epilogue_file_specified (bool x)
{
this->ixx_epilogue_file_specified_ = x;
}
@@ -1726,7 +1813,7 @@ cxx_epilogue_file ()
}
inline void options::
-cxx_epilogue_file(const std::string& x)
+cxx_epilogue_file (const std::string& x)
{
this->cxx_epilogue_file_ = x;
}
@@ -1738,7 +1825,7 @@ cxx_epilogue_file_specified () const
}
inline void options::
-cxx_epilogue_file_specified(bool x)
+cxx_epilogue_file_specified (bool x)
{
this->cxx_epilogue_file_specified_ = x;
}
@@ -1756,7 +1843,7 @@ man_epilogue_file ()
}
inline void options::
-man_epilogue_file(const std::string& x)
+man_epilogue_file (const std::string& x)
{
this->man_epilogue_file_ = x;
}
@@ -1768,7 +1855,7 @@ man_epilogue_file_specified () const
}
inline void options::
-man_epilogue_file_specified(bool x)
+man_epilogue_file_specified (bool x)
{
this->man_epilogue_file_specified_ = x;
}
@@ -1786,7 +1873,7 @@ html_epilogue_file ()
}
inline void options::
-html_epilogue_file(const std::string& x)
+html_epilogue_file (const std::string& x)
{
this->html_epilogue_file_ = x;
}
@@ -1798,7 +1885,7 @@ html_epilogue_file_specified () const
}
inline void options::
-html_epilogue_file_specified(bool x)
+html_epilogue_file_specified (bool x)
{
this->html_epilogue_file_specified_ = x;
}
@@ -1816,7 +1903,7 @@ txt_epilogue_file ()
}
inline void options::
-txt_epilogue_file(const std::string& x)
+txt_epilogue_file (const std::string& x)
{
this->txt_epilogue_file_ = x;
}
@@ -1828,7 +1915,7 @@ txt_epilogue_file_specified () const
}
inline void options::
-txt_epilogue_file_specified(bool x)
+txt_epilogue_file_specified (bool x)
{
this->txt_epilogue_file_specified_ = x;
}
@@ -1846,7 +1933,7 @@ output_prefix ()
}
inline void options::
-output_prefix(const std::string& x)
+output_prefix (const std::string& x)
{
this->output_prefix_ = x;
}
@@ -1858,7 +1945,7 @@ output_prefix_specified () const
}
inline void options::
-output_prefix_specified(bool x)
+output_prefix_specified (bool x)
{
this->output_prefix_specified_ = x;
}
@@ -1876,7 +1963,7 @@ output_suffix ()
}
inline void options::
-output_suffix(const std::string& x)
+output_suffix (const std::string& x)
{
this->output_suffix_ = x;
}
@@ -1888,7 +1975,7 @@ output_suffix_specified () const
}
inline void options::
-output_suffix_specified(bool x)
+output_suffix_specified (bool x)
{
this->output_suffix_specified_ = x;
}
@@ -1906,7 +1993,7 @@ hxx_suffix ()
}
inline void options::
-hxx_suffix(const std::string& x)
+hxx_suffix (const std::string& x)
{
this->hxx_suffix_ = x;
}
@@ -1918,7 +2005,7 @@ hxx_suffix_specified () const
}
inline void options::
-hxx_suffix_specified(bool x)
+hxx_suffix_specified (bool x)
{
this->hxx_suffix_specified_ = x;
}
@@ -1936,7 +2023,7 @@ ixx_suffix ()
}
inline void options::
-ixx_suffix(const std::string& x)
+ixx_suffix (const std::string& x)
{
this->ixx_suffix_ = x;
}
@@ -1948,7 +2035,7 @@ ixx_suffix_specified () const
}
inline void options::
-ixx_suffix_specified(bool x)
+ixx_suffix_specified (bool x)
{
this->ixx_suffix_specified_ = x;
}
@@ -1966,7 +2053,7 @@ cxx_suffix ()
}
inline void options::
-cxx_suffix(const std::string& x)
+cxx_suffix (const std::string& x)
{
this->cxx_suffix_ = x;
}
@@ -1978,7 +2065,7 @@ cxx_suffix_specified () const
}
inline void options::
-cxx_suffix_specified(bool x)
+cxx_suffix_specified (bool x)
{
this->cxx_suffix_specified_ = x;
}
@@ -1996,7 +2083,7 @@ man_suffix ()
}
inline void options::
-man_suffix(const std::string& x)
+man_suffix (const std::string& x)
{
this->man_suffix_ = x;
}
@@ -2008,7 +2095,7 @@ man_suffix_specified () const
}
inline void options::
-man_suffix_specified(bool x)
+man_suffix_specified (bool x)
{
this->man_suffix_specified_ = x;
}
@@ -2026,7 +2113,7 @@ html_suffix ()
}
inline void options::
-html_suffix(const std::string& x)
+html_suffix (const std::string& x)
{
this->html_suffix_ = x;
}
@@ -2038,7 +2125,7 @@ html_suffix_specified () const
}
inline void options::
-html_suffix_specified(bool x)
+html_suffix_specified (bool x)
{
this->html_suffix_specified_ = x;
}
@@ -2056,7 +2143,7 @@ txt_suffix ()
}
inline void options::
-txt_suffix(const std::string& x)
+txt_suffix (const std::string& x)
{
this->txt_suffix_ = x;
}
@@ -2068,12 +2155,72 @@ txt_suffix_specified () const
}
inline void options::
-txt_suffix_specified(bool x)
+txt_suffix_specified (bool x)
{
this->txt_suffix_specified_ = 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_;
@@ -2086,7 +2233,7 @@ option_prefix ()
}
inline void options::
-option_prefix(const std::string& x)
+option_prefix (const std::string& x)
{
this->option_prefix_ = x;
}
@@ -2098,7 +2245,7 @@ option_prefix_specified () const
}
inline void options::
-option_prefix_specified(bool x)
+option_prefix_specified (bool x)
{
this->option_prefix_specified_ = x;
}
@@ -2116,7 +2263,7 @@ option_separator ()
}
inline void options::
-option_separator(const std::string& x)
+option_separator (const std::string& x)
{
this->option_separator_ = x;
}
@@ -2128,7 +2275,7 @@ option_separator_specified () const
}
inline void options::
-option_separator_specified(bool x)
+option_separator_specified (bool x)
{
this->option_separator_specified_ = x;
}
@@ -2146,7 +2293,7 @@ keep_separator ()
}
inline void options::
-keep_separator(const bool& x)
+keep_separator (const bool& x)
{
this->keep_separator_ = x;
}
@@ -2164,7 +2311,7 @@ no_combined_flags ()
}
inline void options::
-no_combined_flags(const bool& x)
+no_combined_flags (const bool& x)
{
this->no_combined_flags_ = x;
}
@@ -2182,7 +2329,7 @@ no_combined_values ()
}
inline void options::
-no_combined_values(const bool& x)
+no_combined_values (const bool& x)
{
this->no_combined_values_ = x;
}
@@ -2200,7 +2347,7 @@ include_with_brackets ()
}
inline void options::
-include_with_brackets(const bool& x)
+include_with_brackets (const bool& x)
{
this->include_with_brackets_ = x;
}
@@ -2218,7 +2365,7 @@ include_prefix ()
}
inline void options::
-include_prefix(const std::string& x)
+include_prefix (const std::string& x)
{
this->include_prefix_ = x;
}
@@ -2230,7 +2377,7 @@ include_prefix_specified () const
}
inline void options::
-include_prefix_specified(bool x)
+include_prefix_specified (bool x)
{
this->include_prefix_specified_ = x;
}
@@ -2248,7 +2395,7 @@ guard_prefix ()
}
inline void options::
-guard_prefix(const std::string& x)
+guard_prefix (const std::string& x)
{
this->guard_prefix_ = x;
}
@@ -2260,7 +2407,7 @@ guard_prefix_specified () const
}
inline void options::
-guard_prefix_specified(bool x)
+guard_prefix_specified (bool x)
{
this->guard_prefix_specified_ = x;
}
@@ -2278,7 +2425,7 @@ reserved_name ()
}
inline void options::
-reserved_name(const std::map<std::string, std::string>& x)
+reserved_name (const std::map<std::string, std::string>& x)
{
this->reserved_name_ = x;
}
@@ -2290,7 +2437,7 @@ reserved_name_specified () const
}
inline void options::
-reserved_name_specified(bool x)
+reserved_name_specified (bool x)
{
this->reserved_name_specified_ = x;
}
@@ -2308,7 +2455,7 @@ options_file ()
}
inline void options::
-options_file(const std::string& x)
+options_file (const std::string& x)
{
this->options_file_ = x;
}
@@ -2320,7 +2467,7 @@ options_file_specified () const
}
inline void options::
-options_file_specified(bool x)
+options_file_specified (bool x)
{
this->options_file_specified_ = x;
}
diff --git a/cli/cli/runtime-header.cxx b/cli/cli/runtime-header.cxx
index adf70dd..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_;"
@@ -308,13 +315,21 @@ generate_runtime_header (context& ctx)
// scanner
//
- os << "// Command line argument scanner interface." << endl
- << "//" << endl
- << "// The values returned by next() are guaranteed to be valid" << endl
- << "// for the two previous arguments up until a call to a third" << endl
- << "// peek() or next()." << endl
- << "//" << endl
- << "class scanner"
+ os << "// Command line argument scanner interface." << endl
+ << "//" << endl
+ << "// The values returned by next() are guaranteed to be valid" << endl
+ << "// for the two previous arguments up until a call to a third" << endl
+ << "// peek() or next()." << endl
+ << "//" << endl
+ << "// The position() function returns a monotonically-increasing" << endl
+ << "// number which, if stored, can later be used to determine the"<< endl
+ << "// relative position of the argument returned by the following"<< endl
+ << "// call to next(). Note that if multiple scanners are used to" << endl
+ << "// extract arguments from multiple sources, then the end" << endl
+ << "// position of the previous scanner should be used as the" << endl
+ << "// start position of the next." << endl
+ << "//" << endl
+ << "class " << exp << "scanner"
<< "{"
<< "public:" << endl
<< "virtual" << endl
@@ -331,15 +346,26 @@ generate_runtime_header (context& ctx)
<< endl
<< "virtual void" << endl
<< "skip () = 0;"
+ << endl
+ << "virtual std::size_t" << endl
+ << "position () = 0;"
<< "};";
// argv_scanner
//
- os << "class argv_scanner: public scanner"
+ os << "class " << exp << "argv_scanner: public scanner"
<< "{"
<< "public:" << endl
- << "argv_scanner (int& argc, char** argv, bool erase = false);"
- << "argv_scanner (int start, int& argc, char** argv, bool erase = false);"
+ << "argv_scanner (int& argc," << endl
+ << "char** argv," << endl
+ << "bool erase = false," << endl
+ << "std::size_t start_position = 0);"
+ << endl
+ << "argv_scanner (int start," << endl
+ << "int& argc," << endl
+ << "char** argv," << endl
+ << "bool erase = false," << endl
+ << "std::size_t start_position = 0);"
<< endl
<< "int" << endl
<< "end () const;"
@@ -356,7 +382,11 @@ generate_runtime_header (context& ctx)
<< "virtual void" << endl
<< "skip ();"
<< endl
- << "private:" << endl
+ << "virtual std::size_t" << endl
+ << "position ();"
+ << endl
+ << "protected:" << endl
+ << "std::size_t start_position_;"
<< "int i_;"
<< "int& argc_;"
<< "char** argv_;"
@@ -367,17 +397,18 @@ 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>&, " <<
- "std::size_t start = 0);"
+ << "vector_scanner (const std::vector<std::string>&," << endl
+ << "std::size_t start = 0," << endl
+ << "std::size_t start_position = 0);"
<< endl
<< "std::size_t" << endl
<< "end () const;"
<< endl
<< "void" << endl
- << "reset (std::size_t start = 0);"
+ << "reset (std::size_t start = 0, std::size_t start_position = 0);"
<< endl
<< "virtual bool" << endl
<< "more ();"
@@ -391,7 +422,11 @@ generate_runtime_header (context& ctx)
<< "virtual void" << endl
<< "skip ();"
<< endl
+ << "virtual std::size_t" << endl
+ << "position ();"
+ << endl
<< "private:" << endl
+ << "std::size_t start_position_;"
<< "const std::vector<std::string>& v_;"
<< "std::size_t i_;"
<< "};";
@@ -401,22 +436,25 @@ 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
<< "char** argv," << endl
<< "const std::string& option," << endl
- << "bool erase = false);"
+ << "bool erase = false," << endl
+ << "std::size_t start_position = 0);"
<< endl
<< "argv_file_scanner (int start," << endl
<< "int& argc," << endl
<< "char** argv," << endl
<< "const std::string& option," << endl
- << "bool erase = false);"
+ << "bool erase = false," << endl
+ << "std::size_t start_position = 0);"
<< endl
<< "argv_file_scanner (const std::string& file," << endl
- << "const std::string& option);"
+ << "const std::string& option," << endl
+ << "std::size_t start_position = 0);"
<< endl
<< "struct option_info"
<< "{"
@@ -432,18 +470,21 @@ generate_runtime_header (context& ctx)
<< "char** argv," << endl
<< "const option_info* options," << endl
<< "std::size_t options_count," << endl
- << "bool erase = false);"
+ << "bool erase = false," << endl
+ << "std::size_t start_position = 0);"
<< endl
<< "argv_file_scanner (int start," << endl
<< "int& argc," << endl
<< "char** argv," << endl
<< "const option_info* options," << endl
<< "std::size_t options_count," << endl
- << "bool erase = false);"
+ << "bool erase = false," << endl
+ << "std::size_t start_position = 0);"
<< endl
<< "argv_file_scanner (const std::string& file," << endl
<< "const option_info* options = 0," << endl
- << "std::size_t options_count = 0);"
+ << "std::size_t options_count = 0," << endl
+ << "std::size_t start_position = 0);"
<< endl
<< "virtual bool" << endl
<< "more ();"
@@ -457,6 +498,9 @@ generate_runtime_header (context& ctx)
<< "virtual void" << endl
<< "skip ();"
<< endl
+ << "virtual std::size_t" << endl
+ << "position ();"
+ << endl
<< "// Return the file path if the peeked at argument came from a file and" << endl
<< "// the empty string otherwise. The reference is guaranteed to be valid" << endl
<< "// till the end of the scanner lifetime." << endl
@@ -512,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&);"
@@ -529,12 +573,18 @@ generate_runtime_header (context& ctx)
<< "virtual void" << endl
<< "skip ();"
<< endl
+ << "virtual std::size_t" << endl
+ << "position ();"
+ << endl
<< "// The group is only available after the call to next()" << endl
<< "// (and skip() -- in case one needs to make sure the group" << endl
<< "// was empty, or some such) and is only valid (and must be" << endl
<< "// handled) until the next call to any of the scanner" << endl
<< "// functions (including more())." << endl
<< "//" << endl
+ << "// Note also that argument positions within each group start"<< endl
+ << "// from 0." << endl
+ << "//" << endl
<< "scanner&" << endl
<< "group ();"
<< endl
@@ -562,21 +612,20 @@ generate_runtime_header (context& ctx)
<< "static separator" << endl
<< "sense (const char*);"
<< endl
- << "// If the state is scanned or skipped, then scan the" << endl
- << "// leading groups and save the next (unescaped) argument in" << endl
- << "// arg_. If the state is peeked, then scan the trailing" << endl
- << "// groups. In both cases set the new state." << endl
+
+ << "// Scan the leading groups, the next argument/argument pack,"<< endl
+ << "// and the trailing groups." << endl
<< "//" << endl
<< "void" << endl
- << "scan_group (state);"
+ << "scan_group ();"
<< endl
<< "scanner& scan_;"
<< "state state_;"
<< endl
<< "// Circular buffer of two arguments." << endl
<< "//" << endl
- << "std::string arg_[2];"
- << "std::size_t i_;"
+ << "std::vector<std::string> arg_[2];"
+ << "std::size_t i_, j_, pos_;"
<< endl
<< "std::vector<std::string> group_;"
<< "vector_scanner group_scan_;"
@@ -590,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
@@ -620,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-inline.cxx b/cli/cli/runtime-inline.cxx
index 8f0e84c..ce18e92 100644
--- a/cli/cli/runtime-inline.cxx
+++ b/cli/cli/runtime-inline.cxx
@@ -232,14 +232,29 @@ generate_runtime_inline (context& ctx)
<< "//" << endl;
os << inl << "argv_scanner::" << endl
- << "argv_scanner (int& argc, char** argv, bool erase)" << endl
- << ": i_ (1), argc_ (argc), argv_ (argv), erase_ (erase)"
+ << "argv_scanner (int& argc," << endl
+ << "char** argv," << endl
+ << "bool erase," << endl
+ << "std::size_t sp)" << endl
+ << ": start_position_ (sp + 1)," << endl
+ << " i_ (1)," << endl
+ << " argc_ (argc)," << endl
+ << " argv_ (argv)," << endl
+ << " erase_ (erase)"
<< "{"
<< "}";
os << inl << "argv_scanner::" << endl
- << "argv_scanner (int start, int& argc, char** argv, bool erase)" << endl
- << ": i_ (start), argc_ (argc), argv_ (argv), erase_ (erase)"
+ << "argv_scanner (int start," << endl
+ << "int& argc," << endl
+ << "char** argv," << endl
+ << "bool erase," << endl
+ << "std::size_t sp)" << endl
+ << ": start_position_ (sp + static_cast<std::size_t> (start))," << endl
+ << " i_ (start)," << endl
+ << " argc_ (argc)," << endl
+ << " argv_ (argv)," << endl
+ << " erase_ (erase)"
<< "{"
<< "}";
@@ -257,9 +272,10 @@ generate_runtime_inline (context& ctx)
<< "//" << endl;
os << inl << "vector_scanner::" << endl
- << "vector_scanner (const std::vector<std::string>& v, " <<
- "std::size_t i)" << endl
- << ": v_ (v), i_ (i)"
+ << "vector_scanner (const std::vector<std::string>& v," << endl
+ << "std::size_t i," << endl
+ << "std::size_t sp)" << endl
+ << ": start_position_ (sp), v_ (v), i_ (i)"
<< "{"
<< "}";
@@ -270,9 +286,10 @@ generate_runtime_inline (context& ctx)
<< "}";
os << inl << "void vector_scanner::" << endl
- << "reset (std::size_t i)"
+ << "reset (std::size_t i, std::size_t sp)"
<< "{"
<< "i_ = i;"
+ << "start_position_ = sp;"
<< "}";
}
@@ -289,8 +306,9 @@ generate_runtime_inline (context& ctx)
<< "argv_file_scanner (int& argc," << endl
<< "char** argv," << endl
<< "const std::string& option," << endl
- << "bool erase)" << endl
- << ": argv_scanner (argc, argv, erase)," << endl
+ << "bool erase," << endl
+ << "std::size_t sp)" << endl
+ << ": argv_scanner (argc, argv, erase, sp)," << endl
<< " option_ (option)," << endl
<< " options_ (&option_info_)," << endl
<< " options_count_ (1)," << endl
@@ -308,8 +326,9 @@ generate_runtime_inline (context& ctx)
<< "int& argc," << endl
<< "char** argv," << endl
<< "const std::string& option," << endl
- << "bool erase)" << endl
- << ": argv_scanner (start, argc, argv, erase)," << endl
+ << "bool erase," << endl
+ << "std::size_t sp)" << endl
+ << ": argv_scanner (start, argc, argv, erase, sp)," << endl
<< " option_ (option)," << endl
<< " options_ (&option_info_)," << endl
<< " options_count_ (1)," << endl
@@ -324,8 +343,9 @@ generate_runtime_inline (context& ctx)
os << inl << "argv_file_scanner::" << endl
<< "argv_file_scanner (const std::string& file," << endl
- << "const std::string& option)" << endl
- << ": argv_scanner (0, zero_argc_, 0)," << endl
+ << "const std::string& option," << endl
+ << "std::size_t sp)" << endl
+ << ": argv_scanner (0, zero_argc_, 0, sp)," << endl
<< " option_ (option)," << endl
<< " options_ (&option_info_)," << endl
<< " options_count_ (1)," << endl
@@ -345,8 +365,9 @@ generate_runtime_inline (context& ctx)
<< "char** argv," << endl
<< "const option_info* options," << endl
<< "std::size_t options_count," << endl
- << "bool erase)" << endl
- << ": argv_scanner (argc, argv, erase)," << endl
+ << "bool erase," << endl
+ << "std::size_t sp)" << endl
+ << ": argv_scanner (argc, argv, erase, sp)," << endl
<< " options_ (options)," << endl
<< " options_count_ (options_count)," << endl
<< " i_ (1)";
@@ -362,8 +383,9 @@ generate_runtime_inline (context& ctx)
<< "char** argv," << endl
<< "const option_info* options," << endl
<< "std::size_t options_count," << endl
- << "bool erase)" << endl
- << ": argv_scanner (start, argc, argv, erase)," << endl
+ << "bool erase," << endl
+ << "std::size_t sp)" << endl
+ << ": argv_scanner (start, argc, argv, erase, sp)," << endl
<< " options_ (options)," << endl
<< " options_count_ (options_count)," << endl
<< " i_ (1)";
@@ -376,8 +398,9 @@ generate_runtime_inline (context& ctx)
os << inl << "argv_file_scanner::" << endl
<< "argv_file_scanner (const std::string& file," << endl
<< "const option_info* options," << endl
- << "std::size_t options_count)" << endl
- << ": argv_scanner (0, zero_argc_, 0)," << endl
+ << "std::size_t options_count," << endl
+ << "std::size_t sp)" << endl
+ << ": argv_scanner (0, zero_argc_, 0, sp)," << endl
<< " options_ (options)," << endl
<< " options_count_ (options_count)," << endl
<< " i_ (1)";
@@ -398,7 +421,7 @@ generate_runtime_inline (context& ctx)
<< inl << "group_scanner::" << endl
<< "group_scanner (scanner& s)" << endl
- << ": scan_ (s), state_ (skipped), i_ (1), group_scan_ (group_)"
+ << ": scan_ (s), state_ (skipped), i_ (1), j_ (0), group_scan_ (group_)"
<< "{"
<< "}"
diff --git a/cli/cli/runtime-source.cxx b/cli/cli/runtime-source.cxx
index e3d904a..11cd746 100644
--- a/cli/cli/runtime-source.cxx
+++ b/cli/cli/runtime-source.cxx
@@ -15,12 +15,13 @@ generate_runtime_source (context& ctx, bool complete)
<< "#include <set>" << endl
<< "#include <string>" << endl
<< "#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;
@@ -30,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
<< "{"
<< "}"
@@ -46,7 +51,7 @@ generate_runtime_source (context& ctx, bool complete)
<< "}"
<< "const char* unknown_option::" << endl
- << "what () const throw ()"
+ << "what () const " << nothrow
<< "{"
<< "return \"unknown option\";"
<< "}";
@@ -56,7 +61,7 @@ generate_runtime_source (context& ctx, bool complete)
os << "// unknown_argument" << endl
<< "//" << endl
<< "unknown_argument::" << endl
- << "~unknown_argument () throw ()"
+ << "~unknown_argument () " << nothrow
<< "{"
<< "}"
@@ -67,7 +72,7 @@ generate_runtime_source (context& ctx, bool complete)
<< "}"
<< "const char* unknown_argument::" << endl
- << "what () const throw ()"
+ << "what () const " << nothrow
<< "{"
<< "return \"unknown argument\";"
<< "}";
@@ -77,7 +82,7 @@ generate_runtime_source (context& ctx, bool complete)
os << "// missing_value" << endl
<< "//" << endl
<< "missing_value::" << endl
- << "~missing_value () throw ()"
+ << "~missing_value () " << nothrow
<< "{"
<< "}"
@@ -88,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\";"
<< "}";
@@ -98,7 +103,7 @@ generate_runtime_source (context& ctx, bool complete)
os << "// invalid_value" << endl
<< "//" << endl
<< "invalid_value::" << endl
- << "~invalid_value () throw ()"
+ << "~invalid_value () " << nothrow
<< "{"
<< "}"
@@ -114,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\";"
<< "}";
@@ -130,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\";"
<< "}";
@@ -142,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
<< "{"
<< "}"
@@ -154,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\";"
<< "}";
@@ -164,7 +169,7 @@ generate_runtime_source (context& ctx, bool complete)
os << "// unmatched_quote" << endl
<< "//" << endl
<< "unmatched_quote::" << endl
- << "~unmatched_quote () throw ()"
+ << "~unmatched_quote () " << nothrow
<< "{"
<< "}"
@@ -176,7 +181,7 @@ generate_runtime_source (context& ctx, bool complete)
<< "}"
<< "const char* unmatched_quote::" << endl
- << "what () const throw ()"
+ << "what () const " << nothrow
<< "{"
<< "return \"unmatched quote\";"
<< "}";
@@ -190,7 +195,7 @@ generate_runtime_source (context& ctx, bool complete)
<< "//" << endl
<< "unexpected_group::" << endl
- << "~unexpected_group () throw ()"
+ << "~unexpected_group () " << nothrow
<< "{"
<< "}"
@@ -202,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\";"
<< "}";
@@ -213,7 +218,7 @@ generate_runtime_source (context& ctx, bool complete)
<< "//" << endl
<< "group_separator::" << endl
- << "~group_separator () throw ()"
+ << "~group_separator () " << nothrow
<< "{"
<< "}"
@@ -237,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 ());"
@@ -259,6 +264,10 @@ generate_runtime_source (context& ctx, bool complete)
// argv_scanner
//
+ // Note that due to the erase logic we cannot just add i_ to
+ // start_position and so have to increment it instead. See also
+ // argv_file_scanner that continues with this logic.
+ //
os << "// argv_scanner" << endl
<< "//" << endl
@@ -295,6 +304,7 @@ generate_runtime_source (context& ctx, bool complete)
<< "else" << endl
<< "++i_;"
<< endl
+ << "++start_position_;"
<< "return r;"
<< "}"
<< "else" << endl
@@ -304,10 +314,19 @@ generate_runtime_source (context& ctx, bool complete)
<< "void argv_scanner::" << endl
<< "skip ()"
<< "{"
- << "if (i_ < argc_)" << endl
+ << "if (i_ < argc_)"
+ << "{"
<< "++i_;"
+ << "++start_position_;"
+ << "}"
<< "else" << endl
<< "throw eos_reached ();"
+ << "}"
+
+ << "std::size_t argv_scanner::" << endl
+ << "position ()"
+ << "{"
+ << "return start_position_;"
<< "}";
// vector_scanner
@@ -348,11 +367,19 @@ generate_runtime_source (context& ctx, bool complete)
<< "++i_;"
<< "else" << endl
<< "throw eos_reached ();"
+ << "}"
+
+ << "std::size_t vector_scanner::" << endl
+ << "position ()"
+ << "{"
+ << "return start_position_ + i_;"
<< "}";
}
// argv_file_scanner
//
+ // Note that we continue incrementing start_position like argv_scanner.
+ //
if (ctx.options.generate_file_scanner ())
{
bool sep (!ctx.opt_sep.empty ());
@@ -486,6 +513,7 @@ generate_runtime_source (context& ctx, bool complete)
<< "{"
<< "hold_[i_ == 0 ? ++i_ : --i_].swap (args_.front ().value);"
<< "args_.pop_front ();"
+ << "++start_position_;"
<< "return hold_[i_].c_str ();"
<< "}"
<< "}"
@@ -498,8 +526,11 @@ generate_runtime_source (context& ctx, bool complete)
<< endl
<< "if (args_.empty ())" << endl
<< "return base::skip ();"
- << "else" << endl
+ << "else"
+ << "{"
<< "args_.pop_front ();"
+ << "++start_position_;"
+ << "}"
<< "}"
<< "const argv_file_scanner::option_info* argv_file_scanner::" << endl
@@ -512,6 +543,12 @@ generate_runtime_source (context& ctx, bool complete)
<< "return 0;"
<< "}"
+ << "std::size_t argv_file_scanner::" << endl
+ << "position ()"
+ << "{"
+ << "return start_position_;"
+ << "}"
+
<< "void argv_file_scanner::" << endl
<< "load (const std::string& file)"
<< "{"
@@ -648,13 +685,28 @@ generate_runtime_source (context& ctx, bool complete)
<< endl
<< "if (oi->search_func != 0)"
<< "{"
- << "std::string f (oi->search_func (s2.c_str (), oi->arg));"
+ << "string f (oi->search_func (s2.c_str (), oi->arg));"
<< "if (!f.empty ())" << endl
<< "load (f);"
<< "}"
<< "else" << endl
- << "load (s2);"
+ << "{"
+ << "// If the path of the file being parsed is not simple and the" << endl
+ << "// path of the file that needs to be loaded is relative, then" << endl
+ << "// complete the latter using the former as a base." << endl
+ << "//" << endl
+ << "#ifndef _WIN32" << endl
+ << "string::size_type p (file.find_last_of ('/'));"
+ << "bool c (p != string::npos && s2[0] != '/');"
+ << "#else" << endl
+ << "string::size_type p (file.find_last_of (\"/\\\\\"));"
+ << "bool c (p != string::npos && s2[1] != ':');"
+ << "#endif" << endl
+ << "if (c)" << endl
+ << "s2.insert (0, file, 0, p + 1);"
<< endl
+ << "load (s2);"
+ << "}"
<< "continue;"
<< "}"
<< "a.value = s1;"
@@ -684,43 +736,50 @@ generate_runtime_source (context& ctx, bool complete)
<< "if (state_ == scanned)"
<< "{"
<< "if (group_scan_.end () != group_.size ())" << endl
- << "throw unexpected_group (arg_[i_], group_scan_.next ());"
+ << "throw unexpected_group (arg_[i_][j_], group_scan_.next ());"
<< "}"
- << "return scan_.more ();"
+ << "return j_ != 0 || scan_.more ();"
<< "}"
<< "const char* group_scanner::" << endl
<< "peek ()"
<< "{"
- << "if (state_ != peeked)" << endl
- << "scan_group (peeked);"
- << "scan_.peek ();"
+ << "if (state_ != peeked)"
+ << "{"
+ << "scan_group ();"
+ << "state_ = peeked;"
+ << "}"
<< "// Return unescaped." << endl
- << "return arg_[i_].c_str ();"
+ << "return arg_[i_][j_ - 1].c_str ();"
<< "}"
<< "const char* group_scanner::" << endl
<< "next ()"
<< "{"
<< "if (state_ != peeked)" << endl
- << "scan_group (peeked);"
- << "scan_.next ();"
- << "scan_group (scanned);"
+ << "scan_group ();"
+ << "state_ = scanned;"
<< "// Return unescaped." << endl
- << "return arg_[i_].c_str ();"
+ << "return arg_[i_][--j_].c_str ();"
<< "}"
<< "void group_scanner::" << endl
<< "skip ()"
<< "{"
<< "if (state_ != peeked)" << endl
- << "scan_group (peeked);"
- << "scan_.skip ();"
- << "scan_group (skipped);"
+ << "scan_group ();"
+ << "state_ = skipped;"
+ << "--j_;"
+ << "}"
+
+ << "std::size_t group_scanner::" << endl
+ << "position ()"
+ << "{"
+ << "return j_ == 0 ? scan_.position () : pos_ + (arg_[i_].size () - j_);"
<< "}"
<< "void group_scanner::" << endl
- << "scan_group (state st)"
+ << "scan_group ()"
<< "{"
<< "// If the previous argument has been scanned, then make" << endl
<< "// sure the group has been scanned (handled) as well." << endl
@@ -728,53 +787,66 @@ generate_runtime_source (context& ctx, bool complete)
<< "if (state_ == scanned)"
<< "{"
<< "if (group_scan_.end () != group_.size ())" << endl
- << "throw unexpected_group (arg_[i_], group_scan_.next ());"
+ << "throw unexpected_group (arg_[i_][j_], group_scan_.next ());"
<< "}"
- << "if (state_ != peeked)"
+ << "// If we still have arguments in the pack, rewind the group." << endl
+ << "//" << endl
+ << "if (j_ != 0)"
<< "{"
- << "arg_[i_ == 0 ? ++i_ : --i_].clear ();"
- << "group_.clear ();"
<< "group_scan_.reset ();"
+ << "return;"
<< "}"
- << "// We recognize all group sequences both before and " << endl
- << "// after the argument and diagnose any misuse. We may" << endl
- << "// also have multiple groups:" << endl
- << "//" << endl
- << "// { -x }+ { -y }+ arg" << endl
- << "//" << endl
+ // Position must remain the same from before the first call to peek()
+ // (comes directly from the scanner) and until next().
+ //
+ // Note that while it may seem like a good idea to pass
+ // scan_.position() to reset() below, the trailing group positions
+ // will overlap with the argument's. So it seems best to start
+ // positions of each argument in a group from 0.
+ //
+ // Note also that we try hard not to throw away allocated memory in
+ // arg_[][0].
+ //
+ << "i_ += (i_ == 0 ? 1 : -1);"
+ << "group_.clear ();"
+ << "group_scan_.reset ();"
+ << "pos_ = scan_.position ();"
<< endl
- << "// Using group_ won't cover empty groups." << endl
+
+ << "// Note: using group_ won't cover empty groups and using" << endl
+ << "// j_ won't cover single-argument packs." << endl
<< "//" << endl
- << "bool g (false);"
+ << "bool group (false), pack (false);"
<< endl
- << "while (scan_.more ())"
+ << "do"
<< "{"
- << "const char* a (scan_.peek ());"
+ << "const char* a (scan_.next ());"
<< "size_t i (*a == '\\\\' ? 1 : 0);"
<< "separator s (sense (a + i));"
<< endl
<< "if (s == none || i != 0)"
<< "{"
- << "if (state_ != peeked)" << endl
- << "arg_[i_] = a + (s != none ? i : 0);"
+ << "if (arg_[i_].size () != 1)" << endl
+ << "arg_[i_].resize (1);"
+ << endl
+ << "arg_[i_][0] = a + (s != none ? i : 0);"
+ << "j_ = 1;"
<< "break;"
<< "}"
- << "// Start of a leading group for the next argument." << endl
+ << "// Start of a leading group for the next argument or" << endl
+ << "// argument pack. We will only know which once we see" << endl
+ << "// the closing separator." << endl
<< "//" << endl
- << "if (s == open && state_ == peeked)" << endl
- << "break;"
- << endl
- << "if (s != (state_ == peeked ? open_plus : open))" << endl
+ << "if (s != open)" << endl
<< "throw group_separator (a, \"\");"
<< endl
- << "g = true;"
+ << "size_t n (group_.size ());"
<< endl
<< "// Scan the group until the closing separator." << endl
<< "//" << endl
- << "scan_.next ();"
<< "s = none;"
<< "while (s == none && scan_.more ())"
<< "{"
@@ -789,20 +861,88 @@ generate_runtime_source (context& ctx, bool complete)
<< "}"
<< "}"
- << "if (s != (state_ == peeked ? close : close_plus))"
+ << "if (s == close)"
<< "{"
- << "throw group_separator ((s != none ? a : \"\")," << endl
- << "(state_ == peeked ? \"}\" : \"}+\"));"
+ << "size_t m (group_.size ());"
+ << endl
+ << "j_ = m - n;"
+ << "if (j_ == 0)" << endl
+ << "throw group_separator (\"{\", \"\");"
+ << endl
+ << "if (arg_[i_].size () != j_)" << endl
+ << "arg_[i_].resize (j_);"
+ << endl
+ << "// Move from group_ to arg_. Add in reverse for ease " << endl
+ << "// of iteration." << endl
+ << "//" << endl
+ << "for (size_t j (0); j != j_; ++j)" << endl
+ << "arg_[i_][j] = group_[m - j - 1];"
+ << "group_.resize (n);"
+ << endl
+ << "pack = true;"
+ << "break;"
<< "}"
+ << "else if (s == close_plus)" << endl
+ << "group = true;"
+ << "else" << endl
+ << "throw group_separator ((s != none ? a : \"\"), \"}+\");"
<< "}"
+ << "while (scan_.more ());"
+ << endl
<< "// Handle the case where we have seen the leading group" << endl
<< "// but there are no more arguments." << endl
<< "//" << endl
- << "if (g && state_ != peeked && !scan_.more ())" << endl
+ << "if (group && j_ == 0)" << endl
<< "throw group_separator (\"{\", \"\");"
<< endl
- << "state_ = st;"
+ << "// Handle trailing groups, if any." << endl
+ << "//" << endl
+
+ << "while (scan_.more ())"
+ << "{"
+ << "const char* a (scan_.peek ());"
+ << "size_t i (*a == '\\\\' ? 1 : 0);"
+ << "separator s (sense (a + i));"
+ << endl
+
+ << "// Next argument, argument pack, or leading group." << endl
+ << "//" << endl
+ << "if (s == none || s == open || i != 0)" << endl
+ << "break;"
+ << endl
+ << "if (s != open_plus)" << endl
+ << "throw group_separator (a, \"\");"
+ << endl
+ << "group = true;"
+ << endl
+ << "// Scan the group until the closing separator." << endl
+ << "//" << endl
+ << "scan_.next ();"
+ << "s = none;"
+ << "while (s == none && scan_.more ())"
+ << "{"
+ << "a = scan_.next ();"
+ << "i = (*a == '\\\\' ? 1 : 0);"
+ << "s = sense (a + i);"
+ << endl
+ << "if (s == none || i != 0)"
+ << "{"
+ << "group_.push_back (a + (s != none ? i : 0));"
+ << "s = none;"
+ << "}"
+ << "}"
+
+ << "if (s != close)" << endl
+ << "throw group_separator ((s != none ? a : \"\"), \"}\");"
+ << "}"
+
+ << "// Handle the case where we have seen the argument pack" << endl
+ << "// without leading or trailing group." << endl
+ << "//" << endl
+ << "if (pack && !group)" << endl
+ << "throw group_separator (\"{\", \"\");"
+
<< "}";
}
@@ -875,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
@@ -919,6 +1081,28 @@ generate_runtime_source (context& ctx, bool complete)
os << "};";
+ // parser<std::pair<X, std::size_t>>
+ //
+ os << "template <typename X>" << endl
+ << "struct parser<std::pair<X, std::size_t> >"
+ << "{";
+
+ os << "static void" << endl
+ << "parse (std::pair<X, std::size_t>& x, " << (sp ? "bool& xs, " : "") << "scanner& s)"
+ << "{"
+ << "x.second = s.position ();"
+ << "parser<X>::parse (x.first, " << (sp ? "xs, " : "") << "s);"
+ << "}";
+
+ if (gen_merge)
+ os << "static void" << endl
+ << "merge (std::pair<X, std::size_t>& b, const std::pair<X, std::size_t>& a)"
+ << "{"
+ << "b = a;"
+ << "}";
+
+ os << "};";
+
// parser<std::vector<X>>
//
os << "template <typename X>" << endl
@@ -986,6 +1170,7 @@ generate_runtime_source (context& ctx, bool complete)
<< endl
<< "if (s.more ())"
<< "{"
+ << "std::size_t pos (s.position ());"
<< "std::string ov (s.next ());"
<< "std::string::size_type p = ov.find ('=');"
<< endl
@@ -1005,13 +1190,13 @@ generate_runtime_source (context& ctx, bool complete)
os << "if (!kstr.empty ())"
<< "{"
<< "av[1] = const_cast<char*> (kstr.c_str ());"
- << "argv_scanner s (0, ac, av);"
+ << "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);"
+ << "argv_scanner s (0, ac, av, false, pos);"
<< "parser<V>::parse (v, " << (sp ? "dummy, " : "") << "s);"
<< "}"
<< "m[k] = v;"
@@ -1035,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
@@ -1044,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/semantics/class.cxx b/cli/cli/semantics/class.cxx
index 494d5d0..cd90f8e 100644
--- a/cli/cli/semantics/class.cxx
+++ b/cli/cli/semantics/class.cxx
@@ -2,7 +2,7 @@
// author : Boris Kolpackov <boris@codesynthesis.com>
// license : MIT; see accompanying LICENSE file
-#include <cutl/compiler/type-info.hxx>
+#include <libcutl/compiler/type-info.hxx>
#include <cli/semantics/class.hxx>
diff --git a/cli/cli/semantics/doc.cxx b/cli/cli/semantics/doc.cxx
index c31260c..a12893d 100644
--- a/cli/cli/semantics/doc.cxx
+++ b/cli/cli/semantics/doc.cxx
@@ -2,7 +2,7 @@
// author : Boris Kolpackov <boris@codesynthesis.com>
// license : MIT; see accompanying LICENSE file
-#include <cutl/compiler/type-info.hxx>
+#include <libcutl/compiler/type-info.hxx>
#include <cli/semantics/doc.hxx>
diff --git a/cli/cli/semantics/elements.cxx b/cli/cli/semantics/elements.cxx
index ed8eb7d..3c43f91 100644
--- a/cli/cli/semantics/elements.cxx
+++ b/cli/cli/semantics/elements.cxx
@@ -2,7 +2,7 @@
// author : Boris Kolpackov <boris@codesynthesis.com>
// license : MIT; see accompanying LICENSE file
-#include <cutl/compiler/type-info.hxx>
+#include <libcutl/compiler/type-info.hxx>
#include <cli/semantics/elements.hxx>
diff --git a/cli/cli/semantics/elements.hxx b/cli/cli/semantics/elements.hxx
index 6235a06..e43f707 100644
--- a/cli/cli/semantics/elements.hxx
+++ b/cli/cli/semantics/elements.hxx
@@ -14,12 +14,12 @@
#include <utility> // std::pair
#include <cassert>
-#include <cutl/fs/path.hxx>
+#include <libcutl/fs/path.hxx>
-#include <cutl/container/graph.hxx>
-#include <cutl/container/pointer-iterator.hxx>
+#include <libcutl/container/graph.hxx>
+#include <libcutl/container/pointer-iterator.hxx>
-#include <cutl/compiler/context.hxx>
+#include <libcutl/compiler/context.hxx>
namespace semantics
{
diff --git a/cli/cli/semantics/expression.cxx b/cli/cli/semantics/expression.cxx
index 18d3312..5d1260d 100644
--- a/cli/cli/semantics/expression.cxx
+++ b/cli/cli/semantics/expression.cxx
@@ -2,7 +2,7 @@
// author : Boris Kolpackov <boris@codesynthesis.com>
// license : MIT; see accompanying LICENSE file
-#include <cutl/compiler/type-info.hxx>
+#include <libcutl/compiler/type-info.hxx>
#include <cli/semantics/expression.hxx>
diff --git a/cli/cli/semantics/namespace.cxx b/cli/cli/semantics/namespace.cxx
index 3c2643c..b9ed422 100644
--- a/cli/cli/semantics/namespace.cxx
+++ b/cli/cli/semantics/namespace.cxx
@@ -2,7 +2,7 @@
// author : Boris Kolpackov <boris@codesynthesis.com>
// license : MIT; see accompanying LICENSE file
-#include <cutl/compiler/type-info.hxx>
+#include <libcutl/compiler/type-info.hxx>
#include <cli/semantics/namespace.hxx>
diff --git a/cli/cli/semantics/option.cxx b/cli/cli/semantics/option.cxx
index 8746a5e..215a169 100644
--- a/cli/cli/semantics/option.cxx
+++ b/cli/cli/semantics/option.cxx
@@ -2,7 +2,7 @@
// author : Boris Kolpackov <boris@codesynthesis.com>
// license : MIT; see accompanying LICENSE file
-#include <cutl/compiler/type-info.hxx>
+#include <libcutl/compiler/type-info.hxx>
#include <cli/semantics/option.hxx>
diff --git a/cli/cli/semantics/unit.cxx b/cli/cli/semantics/unit.cxx
index 9c532ea..690011f 100644
--- a/cli/cli/semantics/unit.cxx
+++ b/cli/cli/semantics/unit.cxx
@@ -2,7 +2,7 @@
// author : Boris Kolpackov <boris@codesynthesis.com>
// license : MIT; see accompanying LICENSE file
-#include <cutl/compiler/type-info.hxx>
+#include <libcutl/compiler/type-info.hxx>
#include <cli/semantics/unit.hxx>
diff --git a/cli/cli/source.cxx b/cli/cli/source.cxx
index b6df839..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
@@ -278,6 +282,9 @@ namespace
: (n == 1 ? ds[0] : ds[1]); // Else, use common (no first sentence).
}
+ if (options.ascii_tree ())
+ preprocess_ascii_tree (d);
+
std::set<string> arg_set;
if (n > 1 && options.ansi_color ())
translate_arg (ds[0], arg_set);
@@ -345,6 +352,8 @@ namespace
{
l++; // ' ' seperator
+ // Note: we naturally assume this doesn't need --ascii-tree treatment.
+ //
string s (doc.size () > 0 ? doc[0] : string ("<arg>"));
if (options.ansi_color ())
@@ -439,6 +448,8 @@ namespace
os << ' ';
l++;
+ // Note: we naturally assume this doesn't need --ascii-tree treatment.
+ //
string s (doc.size () > 0 ? doc[0] : string ("<arg>"));
if (color)
@@ -475,6 +486,9 @@ namespace
}
}
+ if (options.ascii_tree ())
+ preprocess_ascii_tree (d);
+
// Format the documentation string.
//
if (color)
@@ -1262,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/cli/traversal/elements.hxx b/cli/cli/traversal/elements.hxx
index a2ada23..f56de49 100644
--- a/cli/cli/traversal/elements.hxx
+++ b/cli/cli/traversal/elements.hxx
@@ -5,7 +5,7 @@
#ifndef CLI_TRAVERSAL_ELEMENTS_HXX
#define CLI_TRAVERSAL_ELEMENTS_HXX
-#include <cutl/compiler/traversal.hxx>
+#include <libcutl/compiler/traversal.hxx>
#include <cli/semantics/elements.hxx>
diff --git a/cli/cli/txt.cxx b/cli/cli/txt.cxx
index 16de45a..1e9094d 100644
--- a/cli/cli/txt.cxx
+++ b/cli/cli/txt.cxx
@@ -164,13 +164,16 @@ namespace
// n > 2 - arg string, short string, long string
//
size_t n (ds.size ());
- const string& d (
+ string d (
n == 1
? (cd_ == cd_short ? first_sentence (ds[0]) : ds[0])
: (n == 2
? (cd_ == cd_short ? first_sentence (ds[1]) : ds[1])
: ds[cd_ == cd_short ? 1 : 2]));
+ if (options.ascii_tree ())
+ preprocess_ascii_tree (d);
+
std::set<string> arg_set;
if (n > 1 && options.ansi_color ())
translate_arg (ds[0], arg_set);
diff --git a/cli/cli/version.hxx.in b/cli/cli/version.hxx.in
index ceb5389..11db861 100644
--- a/cli/cli/version.hxx.in
+++ b/cli/cli/version.hxx.in
@@ -38,7 +38,7 @@
#define CLI_VERSION_FULL "$cli.version$"
-#include <cutl/version.hxx>
+#include <libcutl/version.hxx>
$libcutl.check(LIBCUTL_VERSION, LIBCUTL_SNAPSHOT)$
diff --git a/cli/doc/.gitignore b/cli/doc/.gitignore
index 562ecbd..84c93ab 100644
--- a/cli/doc/.gitignore
+++ b/cli/doc/.gitignore
@@ -1,2 +1,5 @@
-cli.xhtml
-cli.1
+/cli.1
+/cli.xhtml
+
+*.ps
+*.pdf
diff --git a/cli/doc/buildfile b/cli/doc/buildfile
index f47adad..753b620 100644
--- a/cli/doc/buildfile
+++ b/cli/doc/buildfile
@@ -7,14 +7,193 @@ css{*}: extension = css
define xhtml: doc
xhtml{*}: extension = xhtml
-./: {man1 xhtml}{cli} \
- css{default} \
- file{cli-*}
+define ps: doc
+ps{*}: extension = ps
-./: guide/doc{cli-guide*} \
- guide/xhtml{index} \
- guide/file{*.html2ps}
+define pdf: doc
+pdf{*}: extension = pdf
-doc{*}: install.subdirs = true
+define html2ps: file
+html2ps{*}: extension = html2ps
-./: file{doc.sh}
+./: css{default} xhtml{cli-guide}
+
+# 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"
+ if $version.pre_release
+ doc_version += "-$version.pre_release_string"
+
+ # 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')
+
+ man_options = -v project="CLI" -v version="$doc_version" \
+ -v copyright="$copyright" --suppress-undocumented
+
+ # We use the cli version we've built to generate the documentation.
+ #
+ include ../cli/
+}
+
+# Note: avoid cleaning exe{cli} through this dependency.
+#
+{man1 xhtml}{cli}: ../cli/exe{cli}: clean = false
+
+# 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}
+
+ html2pdf = ($html2ps != [null] && $ps2pdf != [null])
+
+ if! $html2pdf
+ warn "html2ps and/or ps2pdf14 are not available, not generating .ps and .pdf documentation"
+}
+
+./: {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/guide/index.xhtml b/cli/doc/cli-guide.xhtml
index 675db03..94c006c 100644
--- a/cli/doc/guide/index.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/cli-prologue.1 b/cli/doc/cli-prologue.1
index 165cd1a..2b34fee 100644
--- a/cli/doc/cli-prologue.1
+++ b/cli/doc/cli-prologue.1
@@ -1,7 +1,7 @@
.\" Process this file with
.\" groff -man -Tascii cli.1
.\"
-.TH CLI 1 "December 2009" "CLI 1.2.0"
+.TH CLI 1 "$date$" "$project$ $version$"
.SH NAME
cli \- command line interface compiler for C++
.\"
diff --git a/cli/doc/cli-prologue.xhtml b/cli/doc/cli-prologue.xhtml
index 9a57f0e..386c4f0 100644
--- a/cli/doc/cli-prologue.xhtml
+++ b/cli/doc/cli-prologue.xhtml
@@ -2,7 +2,7 @@
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
- <title>CLI 1.2.0 Compiler Command Line Manual</title>
+ <title>$project$ $version$ Compiler Command Line Manual</title>
<meta name="copyright" content="&#169; $copyright$"/>
<meta name="keywords" content="cli,command,line,interface,compiler,c++"/>
diff --git a/cli/doc/doc.sh b/cli/doc/doc.sh
deleted file mode 100755
index dde9aca..0000000
--- a/cli/doc/doc.sh
+++ /dev/null
@@ -1,78 +0,0 @@
-#! /usr/bin/env bash
-
-version=1.2.0-b.6
-
-trap 'exit 1' ERR
-set -o errtrace # Trap in functions.
-
-function info () { echo "$*" 1>&2; }
-function error () { info "$*"; exit 1; }
-
-date="$(date +"%B %Y")"
-copyright="$(sed -n -re 's%^Copyright \(c\) (.+)\.$%\1%p' ../LICENSE)"
-
-while [ $# -gt 0 ]; do
- case $1 in
- --clean)
- rm -f cli.xhtml cli.1
- rm -f guide/cli-guide.ps guide/cli-guide.pdf
- exit 0
- ;;
- *)
- error "unexpected $1"
- ;;
- esac
-done
-
-function compile () # <input-name> <output-name>
-{
- local i=$1; shift
- local o=$1; shift
-
- # Use a bash array to handle empty arguments.
- #
- local ops=()
- while [ $# -gt 0 ]; do
- ops=("${ops[@]}" "$1")
- shift
- done
-
- # --html-suffix .xhtml
- ../cli/cli -I .. \
--v project="cli" \
--v version="$version" \
--v date="$date" \
--v copyright="$copyright" \
-"${ops[@]}" --generate-html --stdout \
---html-prologue-file cli-prologue.xhtml \
---html-epilogue-file cli-epilogue.xhtml \
-"../cli/$i.cli" >"$o.xhtml"
-
- # --man-suffix .1
- ../cli/cli -I .. \
--v project="cli" \
--v version="$version" \
--v date="$date" \
--v copyright="$copyright" \
-"${ops[@]}" --generate-man --stdout \
---man-prologue-file cli-prologue.1 \
---man-epilogue-file cli-epilogue.1 \
-"../cli/$i.cli" >"$o.1"
-}
-
-compile options cli --suppress-undocumented
-
-# Manual.
-#
-
-#function compile_doc ()
-#{
-# html2ps -f doc.html2ps:a4.html2ps -o "$n-a4.ps" "$n.xhtml"
-# ps2pdf14 -sPAPERSIZE=a4 -dOptimize=true -dEmbedAllFonts=true "$n-a4.ps" "$n-a4.pdf"
-#
-# html2ps -f doc.html2ps:letter.html2ps -o "$n-letter.ps" "$n.xhtml"
-# ps2pdf14 -sPAPERSIZE=letter -dOptimize=true -dEmbedAllFonts=true "$n-letter.ps" "$n-letter.pdf"
-#}
-
-html2ps -f guide/guide.html2ps -o guide/cli-guide.ps guide/index.xhtml
-ps2pdf14 -dOptimize=true -dEmbedAllFonts=true guide/cli-guide.ps guide/cli-guide.pdf
diff --git a/cli/doc/guide/guide.html2ps b/cli/doc/guide.html2ps
index a691002..a691002 100644
--- a/cli/doc/guide/guide.html2ps
+++ b/cli/doc/guide.html2ps
diff --git a/cli/doc/guide/.gitignore b/cli/doc/guide/.gitignore
deleted file mode 100644
index 239cc7f..0000000
--- a/cli/doc/guide/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-*.ps
-*.pdf
diff --git a/cli/doc/pregenerated/cli.1 b/cli/doc/pregenerated/cli.1
new file mode 100644
index 0000000..d452ca4
--- /dev/null
+++ b/cli/doc/pregenerated/cli.1
@@ -0,0 +1,438 @@
+.\" Process this file with
+.\" groff -man -Tascii cli.1
+.\"
+.TH CLI 1 "January 2023" "CLI 1.2.0"
+.SH NAME
+cli \- command line interface compiler for C++
+.\"
+.\"
+.\"
+.\"--------------------------------------------------------------------
+.SH SYNOPSIS
+.\"--------------------------------------------------------------------
+.B cli
+.B [
+.I options
+.B ]
+.I file
+.\"
+.\"
+.\"
+.\"--------------------------------------------------------------------
+.SH DESCRIPTION
+.\"--------------------------------------------------------------------
+.B cli
+generates C++ implementation and documentation in various formats for a
+command line interface defined in the CLI language. For an input file in
+the form
+.B name.cli
+the following is generated. By default or if the
+.B --generate-cxx
+option is specified, the following C++ files are generated:
+.B name.hxx
+(header file),
+.B name.ixx
+(inline file, generated unless the
+.B --suppress-inline
+option is specified), and
+.B name.cxx (source file).
+If the
+.B --generate-html
+option is specified, then the
+.B name.html
+HTML documentation file is generated. If the
+.B --generate-man
+option is specified, then the
+.B name.1
+man page file is generated. When
+.B --generate-html
+or
+.B --generate-man
+is specified, the
+.B --stdout
+option can be used to redirect the output to STDOUT instead of a file.
+.\"
+.\"
+.\"
+.\"--------------------------------------------------------------------
+.SH OPTIONS
+.\"--------------------------------------------------------------------
+.IP "\fB--help\fR"
+Print usage information and exit\.
+.IP "\fB--version\fR"
+Print version and exit\.
+.IP "\fB--include-path\fR|\fB-I\fR \fIdir\fR"
+Search \fIdir\fR for bracket-included (\fB<>\fR) options files\.
+.IP "\fB--output-dir\fR|\fB-o\fR \fIdir\fR"
+Write the generated files to \fIdir\fR instead of the current directory\.
+.IP "\fB--std\fR \fIversion\fR"
+Specify the C++ standard that should be used during compilation\. Valid values
+are \fBc++98\fR (default), \fBc++11\fR, and \fBc++14\fR\.
+.IP "\fB--generate-modifier\fR"
+Generate option value modifiers in addition to accessors\.
+.IP "\fB--generate-specifier\fR"
+Generate functions for determining whether the option was specified on the
+command line\.
+.IP "\fB--generate-parse\fR"
+Generate \fBparse()\fR functions instead of parsing constructors\. This is
+primarily useful for being able to parse into an already initialized options
+class instance, for example, to implement option appending/overriding\.
+.IP "\fB--generate-merge\fR"
+Generate \fBmerge()\fR functions\. This is primarily useful for being able to
+merge several already parsed options class instances, for example, to
+implement option appending/overriding\. Note that this option forces
+\fB--generate-specifier\fR\.
+.IP "\fB--generate-description\fR"
+Generate the option description list that can be examined at runtime\.
+.IP "\fB--generate-file-scanner\fR"
+Generate the \fBargv_file_scanner\fR implementation\. This scanner is capable
+of reading command line arguments from the \fBargv\fR array as well as files
+specified with command line options\.
+.IP "\fB--generate-vector-scanner\fR"
+Generate the \fBvector_scanner\fR implementation\. This scanner is capable of
+reading command line arguments from \fBvector<string>\fR\.
+.IP "\fB--generate-group-scanner\fR"
+Generate the \fBgroup_scanner\fR implementation\. This scanner supports
+grouping of arguments (usually options) to apply only to a certain argument\.
+
+Groups can be specified before (leading) and/or after (trailing) the argument
+they apply to\. A leading group starts with '\fB{\fR' and ends with '\fB}+\fR'
+while a trailing group starts with '\fB+{\fR' and ends with '\fB}\fR'\. For
+example:
+
+.nf
+{ --foo --bar }+ arg # 'arg' with '--foo' '--bar'
+arg +{ fox=1 baz=2 } # 'arg' with 'fox=1' 'baz=2'
+.fi
+
+Multiple leading and/or trailing groups can be specified for the same
+argument\. For example:
+
+.nf
+{ -f }+ { -b }+ arg +{ f=1 } +{ b=2 } # 'arg' with '-f' 'b' 'f=1' 'b=2'
+.fi
+
+The group applies to a single argument only unless multiple arguments are
+themselves grouped with '\fB{\fR' and '\fB}\fR'\. For example:
+
+.nf
+{ --foo }+ arg1 arg2 +{ --bar } # 'arg1' with '--foo'
+ # 'arg2' with '--bar'
+
+{ --foo }+ { arg1 arg2 } +{ --bar } # 'arg1' with '--foo' '--bar'
+ # 'arg2' with '--foo' '--bar'
+.fi
+
+The group separators ('\fB{\fR', '\fB}+'\fR, etc) must be separate command
+line arguments\. In particular, they must not be adjacent either to the
+arguments inside the group nor to the argument they apply to\. All such cases
+will be treated as ordinary arguments\. For example:
+
+.nf
+{--foo}+ arg # '{--foo}+' \.\.\.
+arg+{ --foo } # 'arg+{' \.\.\.
+.fi
+
+If one of the group separators needs to be specified as an argument verbatim,
+then it must be escaped with '\fB\e\fR'\. For example:
+
+.nf
+} # error: unexpected group separator
+}x # '}x'
+\\} # '}'
+{ \\}+ }+ arg # 'arg' with '}+'
+.fi
+.IP "\fB--suppress-inline\fR"
+Generate all functions non-inline\. By default simple functions are made
+inline\. This option suppresses creation of the inline file\.
+.IP "\fB--suppress-cli\fR"
+Do not generate the CLI support types (scanners, parser, etc)\. Normally, the
+support types are generated unless another \fB\.cli\fR was included, in which
+case the support types are expected to be provided by its generated code\.
+.IP "\fB--cli-namespace\fR \fIns\fR"
+Generate the CLI support types in the \fIns\fR namespace (\fBcli\fR by
+default)\. The namespace can be nested, for example \fBdetails::cli\fR\. If
+the namespace is empty, then the support types are generated in the global
+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\.
+.IP "\fB--generate-man\fR"
+Generate documentation in the man page format\.
+.IP "\fB--generate-html\fR"
+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
+for several option classes in a single file\.
+.IP "\fB--suppress-undocumented\fR"
+Suppress the generation of documentation entries for undocumented options\.
+.IP "\fB--suppress-usage\fR"
+Suppress the generation of the usage printing code\.
+.IP "\fB--long-usage\fR"
+If no short documentation string is provided, use the complete long
+documentation string in usage\. By default, in this situation only the first
+sentence from the long string is used\.
+.IP "\fB--short-usage\fR"
+If specified together with \fB--long-usage\fR, generate both short and long
+usage versions\. In this mode, the long usage printing function is called
+\fBprint_long_usage()\fR and in its implementation the long documentation
+string is always used, even if the short version is provided\.
+.IP "\fB--page-usage\fR \fIname\fR"
+Generate the combined usage printing code for the entire page\. Specifically,
+this will include all the namespace-level documentation as well as usage for
+all the options classes printed in the order they are defined in the main
+translation unit (documentation/classes from included units are ignored except
+for base classes)\.
+
+The \fIname\fR argument is used as a prefix to form the name of the usage
+printing function\. It can include the namespace qualification as well as
+documentation variable expansion, for example:
+
+.nf
+--page-usage print_ # print_usage() in global namespace
+--page-usage app::print_ # print_usage() in app namespace
+--page-usage print_$name$_ # print_foo_usage() if name is foo
+.fi
+
+If both \fB--long-usage\fR and \fB--short-usage\fR options are specified, then
+the long usage function has the \fB*long_usage()\fR suffix\.
+.IP "\fB--option-length\fR \fIlen\fR"
+Indent option descriptions \fIlen\fR characters when printing usage\. This is
+useful when you have multiple options classes, potentially in separate files,
+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 \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
+not recognize ANSI escape sequences and will display them as garbage\.
+However, if you pipe such output through \fBless(1)\fR, it will display them
+correctly\.
+.IP "\fB--exclude-base\fR"
+Exclude base class information from usage and documentation\.
+.IP "\fB--include-base-last\fR"
+Include base class information after derived for usage and documentation\. By
+default, base classes are included first\.
+.IP "\fB--class-doc\fR \fIname\fR=\fIkind\fR"
+Specify the documentation \fIkind\fR that should be used for the options class
+\fIname\fR\. The \fIname\fR value should be a fully-qualified class name, for
+example, \fBapp::options\fR\. The \fIkind\fR value can be \fBshort\fR,
+\fBlong\fR, \fBexclude\fR, or \fBexclude-base\fR\. If the value is
+\fBexclude\fR, then the class documentation is excluded from usage and
+man/HTML/text output\. If it is \fBexclude-base\fR, then it is only excluded
+when used as a base\. For usage, the \fBshort\fR and \fBlong\fR values
+determine which usage function will be called when the class is used as base
+or as part of the page usage (see \fB--page-usage\fR)\. For man/HTML/text,
+these values determine which documentation strings are used in the output\.
+.IP "\fB--class\fR \fIname\fR"
+Generate the man page, HTML, or text documentation only for the options class
+\fIname\fR\. The \fIname\fR value should be a fully-qualified options class
+name, for example, \fBapp::options\fR\. To generate documentation for multiple
+classes, repeat this option and the documentation will be produced in the
+order specified\. This functionality is useful if you need to assemble
+documentation from multiple classes in a specific order or to insert custom
+documentation between options belonging to different classes\.
+.IP "\fB--docvar\fR|\fB-v\fR \fIname\fR=\fIval\fR"
+Set documentation variable \fIname\fR to the value \fIval\fR\. Documentation
+variables can be substituted in prologues and epilogues (see
+\fB--*-prologue*\fR and \fB--*-epilogue*\fR options) using the
+\fB$\fR\fIname\fR\fB$\fR expansion syntax (use \fB$$\fR to escape expansion)\.
+They can also be defined in \fB\.cli\fR files using the
+\&"\e\fIname\fR=\fIval\fR"\fR syntax\.
+.IP "\fB--link-regex\fR \fIregex\fR"
+Add \fIregex\fR to the list of regular expressions used to transform link
+targets in the generated documentation\. The argument to this option is a
+Perl-like regular expression in the form
+\fB/\fR\fIpattern\fR\fB/\fR\fIreplacement\fR\fB/\fR\fR\. Any character can be
+used as a delimiter instead of '\fB/\fR' and the delimiter can be escaped
+inside \fIpattern\fR and \fIreplacement\fR with a backslash (\fB\e\fR)\. You
+can specify multiple regular expressions by repeating this option\. All the
+regular expressions are tried in the order specified and the first expression
+that matches is used\. Use the \fB--link-regex-trace\fR option to debug link
+transformation\.
+.IP "\fB--link-regex-trace\fR"
+Trace the process of applying regular expressions specified with the
+\fB--link-regex\fR option\. Use this option to find out why your regular
+expressions don't do what you expected them to do\.
+.IP "\fB--html-heading-map\fR \fIc\fR=\fIh\fR"
+Map CLI heading \fIc\fR (valid values: '\fBH\fR', '\fB0\fR', '\fB1\fR',
+\&'\fBh\fR', and '\fB2\fR') to HTML heading \fIh\fR (for example, '\fBh1\fR',
+\&'\fBh2\fR', etc)\.
+.IP "\fB--omit-link-check\fR"
+Don't check that local fragment link references (\el{#ref \.\.\.}) resolve to
+ids\.
+.IP "\fB--hxx-prologue\fR \fItext\fR"
+Insert \fItext\fR at the beginning of the generated C++ header file\.
+.IP "\fB--ixx-prologue\fR \fItext\fR"
+Insert \fItext\fR at the beginning of the generated C++ inline file\.
+.IP "\fB--cxx-prologue\fR \fItext\fR"
+Insert \fItext\fR at the beginning of the generated C++ source file\.
+.IP "\fB--man-prologue\fR \fItext\fR"
+Insert \fItext\fR at the beginning of the generated man page file\.
+.IP "\fB--html-prologue\fR \fItext\fR"
+Insert \fItext\fR at the beginning of the generated HTML file\.
+.IP "\fB--txt-prologue\fR \fItext\fR"
+Insert \fItext\fR at the beginning of the generated text file\.
+.IP "\fB--hxx-epilogue\fR \fItext\fR"
+Insert \fItext\fR at the end of the generated C++ header file\.
+.IP "\fB--ixx-epilogue\fR \fItext\fR"
+Insert \fItext\fR at the end of the generated C++ inline file\.
+.IP "\fB--cxx-epilogue\fR \fItext\fR"
+Insert \fItext\fR at the end of the generated C++ source file\.
+.IP "\fB--man-epilogue\fR \fItext\fR"
+Insert \fItext\fR at the end of the generated man page file\.
+.IP "\fB--html-epilogue\fR \fItext\fR"
+Insert \fItext\fR at the end of the generated HTML file\.
+.IP "\fB--txt-epilogue\fR \fItext\fR"
+Insert \fItext\fR at the end of the generated text file\.
+.IP "\fB--hxx-prologue-file\fR \fIfile\fR"
+Insert the content of \fIfile\fR at the beginning of the generated C++ header
+file\.
+.IP "\fB--ixx-prologue-file\fR \fIfile\fR"
+Insert the content of \fIfile\fR at the beginning of the generated C++ inline
+file\.
+.IP "\fB--cxx-prologue-file\fR \fIfile\fR"
+Insert the content of \fIfile\fR at the beginning of the generated C++ source
+file\.
+.IP "\fB--man-prologue-file\fR \fIfile\fR"
+Insert the content of \fIfile\fR at the beginning of the generated man page
+file\.
+.IP "\fB--html-prologue-file\fR \fIfile\fR"
+Insert the content of \fIfile\fR at the beginning of the generated HTML file\.
+.IP "\fB--txt-prologue-file\fR \fIfile\fR"
+Insert the content of \fIfile\fR at the beginning of the generated text file\.
+.IP "\fB--hxx-epilogue-file\fR \fIfile\fR"
+Insert the content of \fIfile\fR at the end of the generated C++ header file\.
+.IP "\fB--ixx-epilogue-file\fR \fIfile\fR"
+Insert the content of \fIfile\fR at the end of the generated C++ inline file\.
+.IP "\fB--cxx-epilogue-file\fR \fIfile\fR"
+Insert the content of \fIfile\fR at the end of the generated C++ source file\.
+.IP "\fB--man-epilogue-file\fR \fIfile\fR"
+Insert the content of \fIfile\fR at the end of the generated man page file\.
+.IP "\fB--html-epilogue-file\fR \fIfile\fR"
+Insert the content of \fIfile\fR at the end of the generated HTML file\.
+.IP "\fB--txt-epilogue-file\fR \fIfile\fR"
+Insert the content of \fIfile\fR at the end of the generated text file\.
+.IP "\fB--output-prefix\fR \fIprefix\fR"
+Add \fIprefix\fR at the beginning of the generated output file name(s)\.
+.IP "\fB--output-suffix\fR \fIsuffix\fR"
+Add \fIsuffix\fR at the end of the generated output file name(s)\. Note that
+it is added before any file type-specific suffixes; see \fB--*-suffix\fR
+below\.
+.IP "\fB--hxx-suffix\fR \fIsuffix\fR"
+Use \fIsuffix\fR instead of the default \fB\.hxx\fR to construct the name of
+the generated header file\.
+.IP "\fB--ixx-suffix\fR \fIsuffix\fR"
+Use \fIsuffix\fR instead of the default \fB\.ixx\fR to construct the name of
+the generated inline file\.
+.IP "\fB--cxx-suffix\fR \fIsuffix\fR"
+Use \fIsuffix\fR instead of the default \fB\.cxx\fR to construct the name of
+the generated source file\.
+.IP "\fB--man-suffix\fR \fIsuffix\fR"
+Use \fIsuffix\fR instead of the default \fB\.1\fR to construct the name of the
+generated man page file\.
+.IP "\fB--html-suffix\fR \fIsuffix\fR"
+Use \fIsuffix\fR instead of the default \fB\.html\fR to construct the name of
+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
+unknown options\. If you set the option prefix to the empty value, then all
+the unknown command line arguments will be treated as program arguments\.
+.IP "\fB--option-separator\fR \fIsep\fR"
+Use \fIsep\fR instead of the default '\fB--\fR' as an optional separator
+between options and arguments\. All the command line arguments that are parsed
+after this separator are treated as program arguments\. Set the option
+separator to the empty value if you don't want this functionality\.
+.IP "\fB--keep-separator\fR"
+Leave the option separator in the scanner\. This is primarily useful for
+incremental option parsing\.
+.IP "\fB--no-combined-flags\fR"
+Disable support for combining multiple single-character flags into a single
+argument (the \fB-xyz\fR form that is equivalent to \fB-x\fR \fB-y\fR
+\fB-z\fR)\. An argument is considered a combination of flags if it starts with
+a single option prefix (\fB--option-prefix\fR) and only contains letters and
+digits\. Note that an option with a value may not be part of such a
+combination, not even if it is specified last\.
+.IP "\fB--no-combined-values\fR"
+Disable support for combining an option and its value into a single argument
+with the assignment sign (the \fIoption\fR\fB=\fR\fIvalue\fR\fR form)\. This
+functionality requires a non-empty option prefix (\fB--option-prefix\fR)\.
+.IP "\fB--include-with-brackets\fR"
+Use angle brackets (\fB<>\fR) instead of quotes (\fB""\fR) in the generated
+\fB#include\fR directives\.
+.IP "\fB--include-prefix\fR \fIprefix\fR"
+Add \fIprefix\fR to the generated \fB#include\fR directive paths\.
+.IP "\fB--guard-prefix\fR \fIprefix\fR"
+Add \fIprefix\fR to the generated header inclusion guards\. The prefix is
+transformed to upper case and characters that are illegal in a preprocessor
+macro name are replaced with underscores\.
+.IP "\fB--reserved-name\fR \fIname\fR=\fIrep\fR"
+Add \fIname\fR with an optional \fIrep\fR replacement to the list of names
+that should not be used as identifiers\. If provided, the replacement name is
+used instead\. All C++ keywords are already in this list\.
+.IP "\fB--options-file\fR \fIfile\fR"
+Read additional options from \fIfile\fR\. Each option should appear on a
+separate line optionally followed by space or equal sign (\fB=\fR) and an
+option value\. Empty lines and lines starting with \fB#\fR are ignored\.
+Option values can be enclosed in double (\fB"\fR) or single (\fB'\fR) quotes
+to preserve leading and trailing whitespaces as well as to specify empty
+values\. If the value itself contains trailing or leading quotes, enclose it
+with an extra pair of quotes, for example \fB'"x"'\fR\. Non-leading and
+non-trailing quotes are interpreted as being part of the option value\.
+
+The semantics of providing options in a file is equivalent to providing the
+same set of options in the same order on the command line at the point where
+the \fB--options-file\fR option is specified except that the shell escaping
+and quoting is not required\. Repeat this option to specify more than one
+options file\.
+.\"
+.\" DIAGNOSTICS
+.\"
+.SH DIAGNOSTICS
+If the input file is not a valid CLI definition,
+.B cli
+will issue diagnostic messages to STDERR and exit with non-zero exit code.
+.\"
+.\" BUGS
+.\"
+.SH BUGS
+Send bug reports to the cli-users@codesynthesis.com mailing list.
+.\"
+.\" COPYRIGHT
+.\"
+.SH COPYRIGHT
+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
+http://www.codesynthesis.com/licenses/mit.txt
diff --git a/cli/doc/pregenerated/cli.xhtml b/cli/doc/pregenerated/cli.xhtml
new file mode 100644
index 0000000..2a4f751
--- /dev/null
+++ b/cli/doc/pregenerated/cli.xhtml
@@ -0,0 +1,605 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+
+<head>
+ <title>CLI 1.2.0 Compiler Command Line Manual</title>
+
+ <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"/>
+
+ <link rel="stylesheet" type="text/css" href="default.css" />
+
+<style type="text/css">
+
+ #synopsis {
+ list-style-type: none;
+ }
+
+ #synopsis li {
+ padding-top : 0.0em;
+ padding-bottom : 0.0em;
+ }
+
+ .options {
+ margin: 1em 0 1em 0;
+ }
+
+ .options dt {
+ margin: 1em 0 0 0;
+ }
+
+ .options dd {
+ margin: .1em 0 0 4.5em;
+ }
+
+</style>
+</head>
+
+<body>
+<div id="container">
+ <div id="content">
+
+ <h1>NAME</h1>
+
+ <p>cli - command line interface compiler for C++</p>
+
+ <h1>SYNOPSIS</h1>
+
+ <dl id="synopsis">
+ <dt><code><b>cli</b> [<i>options</i>] <i>file</i></code></dt>
+ </dl>
+
+ <h1>DESCRIPTION</h1>
+
+ <p><code><b>cli</b></code> generates C++ implementation and
+ documentation in various formats for a command line interface
+ defined in the CLI language. For an input file in the form
+ <code><b>name.cli</b></code> the following is generated. By
+ default or if the <code><b>--generate-cxx</b></code> option is
+ specified, the following C++ files are generated:
+ <code><b>name.hxx</b></code> (header file), <code><b>name.ixx</b></code>
+ (inline file, generated unless the <code><b>--suppress-inline</b></code>
+ option is specified), and <code><b>name.cxx</b></code> (source file).
+ If the <code><b>--generate-html</b></code> option is specified, then
+ the <code><b>name.html</b></code> HTML documentation file is generated.
+ If the <code><b>--generate-man</b></code> option is specified, then
+ the <code><b>name.1</b></code> man page file is generated. When
+ <code><b>--generate-html</b></code> or <code><b>--generate-man</b></code>
+ is specified, the <code><b>--stdout</b></code> option can be used to
+ redirect the output to STDOUT instead of a file.</p>
+
+ <h1>OPTIONS</h1>
+ <dl class="options">
+ <dt><code><b>--help</b></code></dt>
+ <dd>Print usage information and exit.</dd>
+
+ <dt><code><b>--version</b></code></dt>
+ <dd>Print version and exit.</dd>
+
+ <dt><code><b>--include-path</b></code>|<code><b>-I</b></code> <code><i>dir</i></code></dt>
+ <dd>Search <code><i>dir</i></code> for bracket-included
+ (<code><b>&lt;></b></code>) options files.</dd>
+
+ <dt><code><b>--output-dir</b></code>|<code><b>-o</b></code> <code><i>dir</i></code></dt>
+ <dd>Write the generated files to <code><i>dir</i></code> instead of the
+ current directory.</dd>
+
+ <dt><code><b>--std</b></code> <code><i>version</i></code></dt>
+ <dd>Specify the C++ standard that should be used during compilation. Valid
+ values are <code><b>c++98</b></code> (default), <code><b>c++11</b></code>,
+ and <code><b>c++14</b></code>.</dd>
+
+ <dt><code><b>--generate-modifier</b></code></dt>
+ <dd>Generate option value modifiers in addition to accessors.</dd>
+
+ <dt><code><b>--generate-specifier</b></code></dt>
+ <dd>Generate functions for determining whether the option was specified on
+ the command line.</dd>
+
+ <dt><code><b>--generate-parse</b></code></dt>
+ <dd>Generate <code><b>parse()</b></code> functions instead of parsing
+ constructors. This is primarily useful for being able to parse into an
+ already initialized options class instance, for example, to implement
+ option appending/overriding.</dd>
+
+ <dt><code><b>--generate-merge</b></code></dt>
+ <dd>Generate <code><b>merge()</b></code> functions. This is primarily
+ useful for being able to merge several already parsed options class
+ instances, for example, to implement option appending/overriding. Note
+ that this option forces <code><b>--generate-specifier</b></code>.</dd>
+
+ <dt><code><b>--generate-description</b></code></dt>
+ <dd>Generate the option description list that can be examined at
+ runtime.</dd>
+
+ <dt><code><b>--generate-file-scanner</b></code></dt>
+ <dd>Generate the <code><b>argv_file_scanner</b></code> implementation.
+ This scanner is capable of reading command line arguments from the
+ <code><b>argv</b></code> array as well as files specified with command
+ line options.</dd>
+
+ <dt><code><b>--generate-vector-scanner</b></code></dt>
+ <dd>Generate the <code><b>vector_scanner</b></code> implementation. This
+ scanner is capable of reading command line arguments from
+ <code><b>vector&lt;string></b></code>.</dd>
+
+ <dt><code><b>--generate-group-scanner</b></code></dt>
+ <dd>Generate the <code><b>group_scanner</b></code> implementation. This
+ scanner supports grouping of arguments (usually options) to apply only to
+ a certain argument.
+
+ <p>Groups can be specified before (leading) and/or after (trailing) the
+ argument they apply to. A leading group starts with
+ '<code><b>{</b></code>' and ends with '<code><b>}+</b></code>' while a
+ trailing group starts with '<code><b>+{</b></code>' and ends with
+ '<code><b>}</b></code>'. For example:</p>
+
+ <pre>{ --foo --bar }+ arg # 'arg' with '--foo' '--bar'
+arg +{ fox=1 baz=2 } # 'arg' with 'fox=1' 'baz=2'</pre>
+
+ <p>Multiple leading and/or trailing groups can be specified for the same
+ argument. For example:</p>
+
+ <pre>{ -f }+ { -b }+ arg +{ f=1 } +{ b=2 } # 'arg' with '-f' 'b' 'f=1' 'b=2'</pre>
+
+ <p>The group applies to a single argument only unless multiple arguments
+ are themselves grouped with '<code><b>{</b></code>' and
+ '<code><b>}</b></code>'. For example:</p>
+
+ <pre>{ --foo }+ arg1 arg2 +{ --bar } # 'arg1' with '--foo'
+ # 'arg2' with '--bar'
+
+{ --foo }+ { arg1 arg2 } +{ --bar } # 'arg1' with '--foo' '--bar'
+ # 'arg2' with '--foo' '--bar'</pre>
+
+ <p>The group separators ('<code><b>{</b></code>',
+ '<code><b>}+'</b></code>, etc) must be separate command line arguments. In
+ particular, they must not be adjacent either to the arguments inside the
+ group nor to the argument they apply to. All such cases will be treated as
+ ordinary arguments. For example:</p>
+
+ <pre>{--foo}+ arg # '{--foo}+' ...
+arg+{ --foo } # 'arg+{' ...</pre>
+
+ <p>If one of the group separators needs to be specified as an argument
+ verbatim, then it must be escaped with '<code><b>\</b></code>'. For
+ example:</p>
+
+ <pre>} # error: unexpected group separator
+}x # '}x'
+\} # '}'
+{ \}+ }+ arg # 'arg' with '}+'</pre></dd>
+
+ <dt><code><b>--suppress-inline</b></code></dt>
+ <dd>Generate all functions non-inline. By default simple functions are
+ made inline. This option suppresses creation of the inline file.</dd>
+
+ <dt><code><b>--suppress-cli</b></code></dt>
+ <dd>Do not generate the CLI support types (scanners, parser, etc).
+ Normally, the support types are generated unless another
+ <code><b>.cli</b></code> was included, in which case the support types are
+ expected to be provided by its generated code.</dd>
+
+ <dt><code><b>--cli-namespace</b></code> <code><i>ns</i></code></dt>
+ <dd>Generate the CLI support types in the <code><i>ns</i></code> namespace
+ (<code><b>cli</b></code> by default). The namespace can be nested, for
+ example <code><b>details::cli</b></code>. If the namespace is empty, then
+ the support types are generated in the global namespace.</dd>
+
+ <dt><code><b>--ostream-type</b></code> <code><i>type</i></code></dt>
+ <dd>Output stream type instead of the default
+ <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
+ <code><b>--generate-txt</b></code> is specified, this mode is assumed by
+ default.</dd>
+
+ <dt><code><b>--generate-man</b></code></dt>
+ <dd>Generate documentation in the man page format.</dd>
+
+ <dt><code><b>--generate-html</b></code></dt>
+ <dd>Generate documentation in the HTML format.</dd>
+
+ <dt><code><b>--generate-txt</b></code></dt>
+ <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
+ documentation for several option classes in a single file.</dd>
+
+ <dt><code><b>--suppress-undocumented</b></code></dt>
+ <dd>Suppress the generation of documentation entries for undocumented
+ options.</dd>
+
+ <dt><code><b>--suppress-usage</b></code></dt>
+ <dd>Suppress the generation of the usage printing code.</dd>
+
+ <dt><code><b>--long-usage</b></code></dt>
+ <dd>If no short documentation string is provided, use the complete long
+ documentation string in usage. By default, in this situation only the
+ first sentence from the long string is used.</dd>
+
+ <dt><code><b>--short-usage</b></code></dt>
+ <dd>If specified together with <code><b>--long-usage</b></code>, generate
+ both short and long usage versions. In this mode, the long usage printing
+ function is called <code><b>print_long_usage()</b></code> and in its
+ implementation the long documentation string is always used, even if the
+ short version is provided.</dd>
+
+ <dt><code><b>--page-usage</b></code> <code><i>name</i></code></dt>
+ <dd>Generate the combined usage printing code for the entire page.
+ Specifically, this will include all the namespace-level documentation as
+ well as usage for all the options classes printed in the order they are
+ defined in the main translation unit (documentation/classes from included
+ units are ignored except for base classes).
+
+ <p>The <code><i>name</i></code> argument is used as a prefix to form the
+ name of the usage printing function. It can include the namespace
+ qualification as well as documentation variable expansion, for
+ example:</p>
+
+ <pre>--page-usage print_ # print_usage() in global namespace
+--page-usage app::print_ # print_usage() in app namespace
+--page-usage print_$name$_ # print_foo_usage() if name is foo</pre>
+
+ <p>If both <code><b>--long-usage</b></code> and
+ <code><b>--short-usage</b></code> options are specified, then the long
+ usage function has the <code><b>*long_usage()</b></code> suffix.</p></dd>
+
+ <dt><code><b>--option-length</b></code> <code><i>len</i></code></dt>
+ <dd>Indent option descriptions <code><i>len</i></code> characters when
+ printing usage. This is useful when you have multiple options classes,
+ potentially in separate files, and would like their usage to have the same
+ indentation level.</dd>
+
+ <dt><code><b>--ascii-tree</b></code></dt>
+ <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><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
+ really only mean the bold and underline modifiers. Note that Windows
+ console does not recognize ANSI escape sequences and will display them as
+ garbage. However, if you pipe such output through
+ <code><b>less(1)</b></code>, it will display them correctly.</dd>
+
+ <dt><code><b>--exclude-base</b></code></dt>
+ <dd>Exclude base class information from usage and documentation.</dd>
+
+ <dt><code><b>--include-base-last</b></code></dt>
+ <dd>Include base class information after derived for usage and
+ documentation. By default, base classes are included first.</dd>
+
+ <dt><code><b>--class-doc</b></code> <code><i>name</i></code>=<code><i>kind</i></code></dt>
+ <dd>Specify the documentation <code><i>kind</i></code> that should be used
+ for the options class <code><i>name</i></code>. The
+ <code><i>name</i></code> value should be a fully-qualified class name, for
+ example, <code><b>app::options</b></code>. The <code><i>kind</i></code>
+ value can be <code><b>short</b></code>, <code><b>long</b></code>,
+ <code><b>exclude</b></code>, or <code><b>exclude-base</b></code>. If the
+ value is <code><b>exclude</b></code>, then the class documentation is
+ excluded from usage and man/HTML/text output. If it is
+ <code><b>exclude-base</b></code>, then it is only excluded when used as a
+ base. For usage, the <code><b>short</b></code> and
+ <code><b>long</b></code> values determine which usage function will be
+ called when the class is used as base or as part of the page usage (see
+ <code><b>--page-usage</b></code>). For man/HTML/text, these values
+ determine which documentation strings are used in the output.</dd>
+
+ <dt><code><b>--class</b></code> <code><i>name</i></code></dt>
+ <dd>Generate the man page, HTML, or text documentation only for the
+ options class <code><i>name</i></code>. The <code><i>name</i></code> value
+ should be a fully-qualified options class name, for example,
+ <code><b>app::options</b></code>. To generate documentation for multiple
+ classes, repeat this option and the documentation will be produced in the
+ order specified. This functionality is useful if you need to assemble
+ documentation from multiple classes in a specific order or to insert
+ custom documentation between options belonging to different classes.</dd>
+
+ <dt><code><b>--docvar</b></code>|<code><b>-v</b></code> <code><i>name</i></code>=<code><i>val</i></code></dt>
+ <dd>Set documentation variable <code><i>name</i></code> to the value
+ <code><i>val</i></code>. Documentation variables can be substituted in
+ prologues and epilogues (see <code><b>--*-prologue*</b></code> and
+ <code><b>--*-epilogue*</b></code> options) using the
+ <code><b>$</b></code><code><i>name</i></code><code><b>$</b></code>
+ expansion syntax (use <code><b>$$</b></code> to escape expansion). They
+ can also be defined in <code><b>.cli</b></code> files using the
+ <code>"\<code><i>name</i></code>=<code><i>val</i></code>"</code>
+ syntax.</dd>
+
+ <dt><code><b>--link-regex</b></code> <code><i>regex</i></code></dt>
+ <dd>Add <code><i>regex</i></code> to the list of regular expressions used
+ to transform link targets in the generated documentation. The argument to
+ this option is a Perl-like regular expression in the form
+ <code><b>/</b><i>pattern</i><b>/</b><i>replacement</i><b>/</b></code>. Any
+ character can be used as a delimiter instead of '<code><b>/</b></code>'
+ and the delimiter can be escaped inside <code><i>pattern</i></code> and
+ <code><i>replacement</i></code> with a backslash (<code><b>\</b></code>).
+ You can specify multiple regular expressions by repeating this option. All
+ the regular expressions are tried in the order specified and the first
+ expression that matches is used. Use the
+ <code><b>--link-regex-trace</b></code> option to debug link
+ transformation.</dd>
+
+ <dt><code><b>--link-regex-trace</b></code></dt>
+ <dd>Trace the process of applying regular expressions specified with the
+ <code><b>--link-regex</b></code> option. Use this option to find out why
+ your regular expressions don't do what you expected them to do.</dd>
+
+ <dt><code><b>--html-heading-map</b></code> <code><i>c</i></code>=<code><i>h</i></code></dt>
+ <dd>Map CLI heading <code><i>c</i></code> (valid values:
+ '<code><b>H</b></code>', '<code><b>0</b></code>', '<code><b>1</b></code>',
+ '<code><b>h</b></code>', and '<code><b>2</b></code>') to HTML heading
+ <code><i>h</i></code> (for example, '<code><b>h1</b></code>',
+ '<code><b>h2</b></code>', etc).</dd>
+
+ <dt><code><b>--omit-link-check</b></code></dt>
+ <dd>Don't check that local fragment link references (\l{#ref ...}) resolve
+ to ids.</dd>
+
+ <dt><code><b>--hxx-prologue</b></code> <code><i>text</i></code></dt>
+ <dd>Insert <code><i>text</i></code> at the beginning of the generated C++
+ header file.</dd>
+
+ <dt><code><b>--ixx-prologue</b></code> <code><i>text</i></code></dt>
+ <dd>Insert <code><i>text</i></code> at the beginning of the generated C++
+ inline file.</dd>
+
+ <dt><code><b>--cxx-prologue</b></code> <code><i>text</i></code></dt>
+ <dd>Insert <code><i>text</i></code> at the beginning of the generated C++
+ source file.</dd>
+
+ <dt><code><b>--man-prologue</b></code> <code><i>text</i></code></dt>
+ <dd>Insert <code><i>text</i></code> at the beginning of the generated man
+ page file.</dd>
+
+ <dt><code><b>--html-prologue</b></code> <code><i>text</i></code></dt>
+ <dd>Insert <code><i>text</i></code> at the beginning of the generated HTML
+ file.</dd>
+
+ <dt><code><b>--txt-prologue</b></code> <code><i>text</i></code></dt>
+ <dd>Insert <code><i>text</i></code> at the beginning of the generated text
+ file.</dd>
+
+ <dt><code><b>--hxx-epilogue</b></code> <code><i>text</i></code></dt>
+ <dd>Insert <code><i>text</i></code> at the end of the generated C++ header
+ file.</dd>
+
+ <dt><code><b>--ixx-epilogue</b></code> <code><i>text</i></code></dt>
+ <dd>Insert <code><i>text</i></code> at the end of the generated C++ inline
+ file.</dd>
+
+ <dt><code><b>--cxx-epilogue</b></code> <code><i>text</i></code></dt>
+ <dd>Insert <code><i>text</i></code> at the end of the generated C++ source
+ file.</dd>
+
+ <dt><code><b>--man-epilogue</b></code> <code><i>text</i></code></dt>
+ <dd>Insert <code><i>text</i></code> at the end of the generated man page
+ file.</dd>
+
+ <dt><code><b>--html-epilogue</b></code> <code><i>text</i></code></dt>
+ <dd>Insert <code><i>text</i></code> at the end of the generated HTML
+ file.</dd>
+
+ <dt><code><b>--txt-epilogue</b></code> <code><i>text</i></code></dt>
+ <dd>Insert <code><i>text</i></code> at the end of the generated text
+ file.</dd>
+
+ <dt><code><b>--hxx-prologue-file</b></code> <code><i>file</i></code></dt>
+ <dd>Insert the content of <code><i>file</i></code> at the beginning of the
+ generated C++ header file.</dd>
+
+ <dt><code><b>--ixx-prologue-file</b></code> <code><i>file</i></code></dt>
+ <dd>Insert the content of <code><i>file</i></code> at the beginning of the
+ generated C++ inline file.</dd>
+
+ <dt><code><b>--cxx-prologue-file</b></code> <code><i>file</i></code></dt>
+ <dd>Insert the content of <code><i>file</i></code> at the beginning of the
+ generated C++ source file.</dd>
+
+ <dt><code><b>--man-prologue-file</b></code> <code><i>file</i></code></dt>
+ <dd>Insert the content of <code><i>file</i></code> at the beginning of the
+ generated man page file.</dd>
+
+ <dt><code><b>--html-prologue-file</b></code> <code><i>file</i></code></dt>
+ <dd>Insert the content of <code><i>file</i></code> at the beginning of the
+ generated HTML file.</dd>
+
+ <dt><code><b>--txt-prologue-file</b></code> <code><i>file</i></code></dt>
+ <dd>Insert the content of <code><i>file</i></code> at the beginning of the
+ generated text file.</dd>
+
+ <dt><code><b>--hxx-epilogue-file</b></code> <code><i>file</i></code></dt>
+ <dd>Insert the content of <code><i>file</i></code> at the end of the
+ generated C++ header file.</dd>
+
+ <dt><code><b>--ixx-epilogue-file</b></code> <code><i>file</i></code></dt>
+ <dd>Insert the content of <code><i>file</i></code> at the end of the
+ generated C++ inline file.</dd>
+
+ <dt><code><b>--cxx-epilogue-file</b></code> <code><i>file</i></code></dt>
+ <dd>Insert the content of <code><i>file</i></code> at the end of the
+ generated C++ source file.</dd>
+
+ <dt><code><b>--man-epilogue-file</b></code> <code><i>file</i></code></dt>
+ <dd>Insert the content of <code><i>file</i></code> at the end of the
+ generated man page file.</dd>
+
+ <dt><code><b>--html-epilogue-file</b></code> <code><i>file</i></code></dt>
+ <dd>Insert the content of <code><i>file</i></code> at the end of the
+ generated HTML file.</dd>
+
+ <dt><code><b>--txt-epilogue-file</b></code> <code><i>file</i></code></dt>
+ <dd>Insert the content of <code><i>file</i></code> at the end of the
+ generated text file.</dd>
+
+ <dt><code><b>--output-prefix</b></code> <code><i>prefix</i></code></dt>
+ <dd>Add <code><i>prefix</i></code> at the beginning of the generated
+ output file name(s).</dd>
+
+ <dt><code><b>--output-suffix</b></code> <code><i>suffix</i></code></dt>
+ <dd>Add <code><i>suffix</i></code> at the end of the generated output file
+ name(s). Note that it is added before any file type-specific suffixes; see
+ <code><b>--*-suffix</b></code> below.</dd>
+
+ <dt><code><b>--hxx-suffix</b></code> <code><i>suffix</i></code></dt>
+ <dd>Use <code><i>suffix</i></code> instead of the default
+ <code><b>.hxx</b></code> to construct the name of the generated header
+ file.</dd>
+
+ <dt><code><b>--ixx-suffix</b></code> <code><i>suffix</i></code></dt>
+ <dd>Use <code><i>suffix</i></code> instead of the default
+ <code><b>.ixx</b></code> to construct the name of the generated inline
+ file.</dd>
+
+ <dt><code><b>--cxx-suffix</b></code> <code><i>suffix</i></code></dt>
+ <dd>Use <code><i>suffix</i></code> instead of the default
+ <code><b>.cxx</b></code> to construct the name of the generated source
+ file.</dd>
+
+ <dt><code><b>--man-suffix</b></code> <code><i>suffix</i></code></dt>
+ <dd>Use <code><i>suffix</i></code> instead of the default
+ <code><b>.1</b></code> to construct the name of the generated man page
+ file.</dd>
+
+ <dt><code><b>--html-suffix</b></code> <code><i>suffix</i></code></dt>
+ <dd>Use <code><i>suffix</i></code> instead of the default
+ <code><b>.html</b></code> to construct the name of the generated HTML
+ file.</dd>
+
+ <dt><code><b>--txt-suffix</b></code> <code><i>suffix</i></code></dt>
+ <dd>Use <code><i>suffix</i></code> instead of the default
+ <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
+ arguments that start with this prefix are treated as unknown options. If
+ you set the option prefix to the empty value, then all the unknown command
+ line arguments will be treated as program arguments.</dd>
+
+ <dt><code><b>--option-separator</b></code> <code><i>sep</i></code></dt>
+ <dd>Use <code><i>sep</i></code> instead of the default
+ '<code><b>--</b></code>' as an optional separator between options and
+ arguments. All the command line arguments that are parsed after this
+ separator are treated as program arguments. Set the option separator to
+ the empty value if you don't want this functionality.</dd>
+
+ <dt><code><b>--keep-separator</b></code></dt>
+ <dd>Leave the option separator in the scanner. This is primarily useful
+ for incremental option parsing.</dd>
+
+ <dt><code><b>--no-combined-flags</b></code></dt>
+ <dd>Disable support for combining multiple single-character flags into a
+ single argument (the <code><b>-xyz</b></code> form that is equivalent to
+ <code><b>-x</b></code> <code><b>-y</b></code> <code><b>-z</b></code>). An
+ argument is considered a combination of flags if it starts with a single
+ option prefix (<code><b>--option-prefix</b></code>) and only contains
+ letters and digits. Note that an option with a value may not be part of
+ such a combination, not even if it is specified last.</dd>
+
+ <dt><code><b>--no-combined-values</b></code></dt>
+ <dd>Disable support for combining an option and its value into a single
+ argument with the assignment sign (the
+ <code><i>option</i><b>=</b><i>value</i></code> form). This functionality
+ requires a non-empty option prefix
+ (<code><b>--option-prefix</b></code>).</dd>
+
+ <dt><code><b>--include-with-brackets</b></code></dt>
+ <dd>Use angle brackets (<code><b>&lt;></b></code>) instead of quotes
+ (<code><b>""</b></code>) in the generated <code><b>#include</b></code>
+ directives.</dd>
+
+ <dt><code><b>--include-prefix</b></code> <code><i>prefix</i></code></dt>
+ <dd>Add <code><i>prefix</i></code> to the generated
+ <code><b>#include</b></code> directive paths.</dd>
+
+ <dt><code><b>--guard-prefix</b></code> <code><i>prefix</i></code></dt>
+ <dd>Add <code><i>prefix</i></code> to the generated header inclusion
+ guards. The prefix is transformed to upper case and characters that are
+ illegal in a preprocessor macro name are replaced with underscores.</dd>
+
+ <dt><code><b>--reserved-name</b></code> <code><i>name</i></code>=<code><i>rep</i></code></dt>
+ <dd>Add <code><i>name</i></code> with an optional <code><i>rep</i></code>
+ replacement to the list of names that should not be used as identifiers.
+ If provided, the replacement name is used instead. All C++ keywords are
+ already in this list.</dd>
+
+ <dt><code><b>--options-file</b></code> <code><i>file</i></code></dt>
+ <dd>Read additional options from <code><i>file</i></code>. Each option
+ should appear on a separate line optionally followed by space or equal
+ sign (<code><b>=</b></code>) and an option value. Empty lines and lines
+ starting with <code><b>#</b></code> are ignored. Option values can be
+ enclosed in double (<code><b>"</b></code>) or single
+ (<code><b>'</b></code>) quotes to preserve leading and trailing
+ whitespaces as well as to specify empty values. If the value itself
+ contains trailing or leading quotes, enclose it with an extra pair of
+ quotes, for example <code><b>'"x"'</b></code>. Non-leading and
+ non-trailing quotes are interpreted as being part of the option value.
+
+ <p>The semantics of providing options in a file is equivalent to providing
+ the same set of options in the same order on the command line at the point
+ where the <code><b>--options-file</b></code> option is specified except
+ that the shell escaping and quoting is not required. Repeat this option to
+ specify more than one options file.</p></dd>
+ </dl>
+
+ <h1>DIAGNOSTICS</h1>
+
+ <p>If the input file is not a valid CLI definition, <code><b>cli</b></code>
+ will issue diagnostic messages to STDERR and exit with non-zero exit
+ code.</p>
+
+ <h1>BUGS</h1>
+
+ <p>Send bug reports to the
+ <a href="mailto:cli-users@codesynthesis.com">cli-users@codesynthesis.com</a> mailing list.</p>
+
+ </div>
+ <div id="footer">
+ Copyright &#169; 2009-2023 Code Synthesis Tools CC.
+
+ <div id="terms">
+ Permission is granted to copy, distribute and/or modify this
+ document under the terms of the
+ <a href="http://www.codesynthesis.com/licenses/mit.txt">MIT License</a>.
+ </div>
+ </div>
+</div>
+</body>
+</html>
diff --git a/cli/manifest b/cli/manifest
index 95300b4..a90072b 100644
--- a/cli/manifest
+++ b/cli/manifest
@@ -1,6 +1,6 @@
: 1
name: cli
-version: 1.2.0-b.7.z
+version: 1.2.0
summary: Command line interface (CLI) compiler for C++
license: MIT
topics: C++, command line interface, source code generation, \
@@ -9,13 +9,13 @@ description-file: README
changes-file: NEWS
url: https://www.codesynthesis.com/projects/cli/
doc-url: https://www.codesynthesis.com/projects/cli/doc/guide/
-src-url: https://git.codesynthesis.com/cgit/cli/cli/tree/cli
+src-url: https://git.codesynthesis.com/cgit/cli/cli/tree/cli/
email: cli-users@codesynthesis.com ; Mailing list
build-warning-email: builds@codesynthesis.com
-builds: all
requires: c++14
-depends: * build2 >= 0.13.0
-depends: * bpkg >= 0.13.0
+requires: host
+depends: * build2 >= 0.16.0
+depends: * bpkg >= 0.16.0
depends: libcutl ^1.11.0-
-tests: cli-tests == $
-examples: cli-examples == $
+tests: * cli-tests == $
+examples: * cli-examples == $
diff --git a/cli/tests/.gitignore b/cli/tests/.gitignore
new file mode 100644
index 0000000..d4a788b
--- /dev/null
+++ b/cli/tests/.gitignore
@@ -0,0 +1,2 @@
+test
+test-*
diff --git a/cli/tests/ascii-tree/buildfile b/cli/tests/ascii-tree/buildfile
new file mode 100644
index 0000000..6450286
--- /dev/null
+++ b/cli/tests/ascii-tree/buildfile
@@ -0,0 +1,8 @@
+# file : tests/ascii-tree/buildfile
+# license : MIT; see accompanying LICENSE file
+
+import! [metadata] cli = cli%exe{cli}
+
+./: testscript $cli
+
+testscript{*}: test = $cli
diff --git a/cli/tests/ascii-tree/testscript b/cli/tests/ascii-tree/testscript
new file mode 100644
index 0000000..f0546f6
--- /dev/null
+++ b/cli/tests/ascii-tree/testscript
@@ -0,0 +1,43 @@
+# file : tests/ascii-tree/testscript
+# license : MIT; see accompanying LICENSE file
+
+: basics
+:
+cat <<EOI >=test.cli;
+"
+\
+hello/
+├── build/
+│   ├── bootstrap.build
+│   └── root.build
+├── hello/
+│   ├── sub/
+│   │   ├── bar
+│   │   └── foo
+│   ├── buildfile
+│   ├── hello.cxx
+│   └── testscript
+├── buildfile
+├── manifest
+├── README.md
+└── repositories.manifest
+\
+"
+EOI
+$* --generate-txt --ascii-tree --stdout test.cli >>EOO
+hello/
+|-- build/
+| |-- bootstrap.build
+| `-- root.build
+|-- hello/
+| |-- sub/
+| | |-- bar
+| | `-- foo
+| |-- buildfile
+| |-- hello.cxx
+| `-- testscript
+|-- buildfile
+|-- manifest
+|-- README.md
+`-- repositories.manifest
+EOO
diff --git a/cli/tests/build/.gitignore b/cli/tests/build/.gitignore
new file mode 100644
index 0000000..4a730a3
--- /dev/null
+++ b/cli/tests/build/.gitignore
@@ -0,0 +1,3 @@
+config.build
+root/
+bootstrap/
diff --git a/cli/tests/build/bootstrap.build b/cli/tests/build/bootstrap.build
new file mode 100644
index 0000000..bb305a2
--- /dev/null
+++ b/cli/tests/build/bootstrap.build
@@ -0,0 +1,8 @@
+# file : tests/build/bootstrap.build
+# license : MIT; see accompanying LICENSE file
+
+project =
+
+using config
+using dist
+using test
diff --git a/cli/tests/build/root.build b/cli/tests/build/root.build
new file mode 100644
index 0000000..cb9ba03
--- /dev/null
+++ b/cli/tests/build/root.build
@@ -0,0 +1,8 @@
+# file : tests/build/root.build
+# license : MIT; see accompanying LICENSE file
+
+# Configure C++ module and specify the test target for cross-testing.
+#
+using cxx.config
+
+test.target = $cxx.target
diff --git a/cli/tests/buildfile b/cli/tests/buildfile
new file mode 100644
index 0000000..556ed55
--- /dev/null
+++ b/cli/tests/buildfile
@@ -0,0 +1,4 @@
+# file : tests/buildfile
+# license : MIT; see accompanying LICENSE file
+
+./: {*/ -build/}
diff --git a/cli/tests/headings/buildfile b/cli/tests/headings/buildfile
new file mode 100644
index 0000000..aa665c7
--- /dev/null
+++ b/cli/tests/headings/buildfile
@@ -0,0 +1,8 @@
+# file : tests/headings/buildfile
+# license : MIT; see accompanying LICENSE file
+
+import! [metadata] cli = cli%exe{cli}
+
+./: testscript $cli
+
+testscript{*}: test = $cli
diff --git a/cli/tests/headings/testscript b/cli/tests/headings/testscript
new file mode 100644
index 0000000..163ba5f
--- /dev/null
+++ b/cli/tests/headings/testscript
@@ -0,0 +1,36 @@
+# file : tests/headings/testscript
+# license : MIT; see accompanying LICENSE file
+
+: auto-headings
+:
+: Note that auto-headings break if we split into multiple doc strings.
+:
+cat <<EOI >=map.cli;
+"
+\h1|Heading 1|
+
+\h|Heading 1.1|
+
+\h2|Heading 1.1.1|
+
+\h|Heading 1.2|
+
+\h2|Heading 1.2.1|
+
+\h1|Heading 2|
+"
+EOI
+$* --generate-html --stdout map.cli >>EOO
+ <h1>Heading 1</h1>
+
+ <h2>Heading 1.1</h2>
+
+ <h3>Heading 1.1.1</h3>
+
+ <h2>Heading 1.2</h2>
+
+ <h3>Heading 1.2.1</h3>
+
+ <h1>Heading 2</h1>
+
+EOO
diff --git a/cli/tests/note/buildfile b/cli/tests/note/buildfile
new file mode 100644
index 0000000..b35a911
--- /dev/null
+++ b/cli/tests/note/buildfile
@@ -0,0 +1,8 @@
+# file : tests/note/buildfile
+# license : MIT; see accompanying LICENSE file
+
+import! [metadata] cli = cli%exe{cli}
+
+./: testscript $cli
+
+testscript{*}: test = $cli
diff --git a/cli/tests/note/testscript b/cli/tests/note/testscript
new file mode 100644
index 0000000..52bcecc
--- /dev/null
+++ b/cli/tests/note/testscript
@@ -0,0 +1,197 @@
+# file : tests/note/testscript
+# license : MIT; see accompanying LICENSE file
+
+: block-basics
+:
+cat <<EOI >=test.cli;
+"
+Leading paragraph.
+
+\N|This is a note block one.|
+
+Interleaving paragraph that is quite long and therefore it may span many
+lines in order to make text easy to read.
+
+\N|This is a note block two that is quite long and therefore it may span many
+lines in order to make text easy to read.|
+
+Trailing paragraph.
+"
+EOI
+$* --generate-html --stdout test.cli >>EOO;
+ <p>Leading paragraph.</p>
+
+ <div class="note">
+ <p>This is a note block one.</p>
+ </div>
+
+ <p>Interleaving paragraph that is quite long and therefore it may span many
+ lines in order to make text easy to read.</p>
+
+ <div class="note">
+ <p>This is a note block two that is quite long and therefore it may span
+ many lines in order to make text easy to read.</p>
+ </div>
+
+ <p>Trailing paragraph.</p>
+
+EOO
+ $* --generate-txt --stdout test.cli >>EOO
+Leading paragraph.
+
+| This is a note block one.
+
+Interleaving paragraph that is quite long and therefore it may span many lines
+in order to make text easy to read.
+
+| This is a note block two that is quite long and therefore it may span many
+| lines in order to make text easy to read.
+
+Trailing paragraph.
+EOO
+
+
+: block-multi-para
+:
+cat <<EOI >=test.cli;
+"
+\N|
+This is a note para one that is quite long and therefore it may span many
+lines in order to make text easy to read.
+
+This is a note para two.
+|
+"
+EOI
+$* --generate-html --stdout test.cli >>EOO;
+ <div class="note">
+ <p>This is a note para one that is quite long and therefore it may span many
+ lines in order to make text easy to read.</p>
+
+ <p>This is a note para two.</p>
+ </div>
+
+EOO
+$* --generate-txt --stdout test.cli >>EOO
+| This is a note para one that is quite long and therefore it may span many
+| lines in order to make text easy to read.
+|
+| This is a note para two.
+EOO
+
+: block-pre
+:
+cat <<EOI >=test.cli;
+"
+
+\N|
+This is a note para one.
+
+\
+And this is a
+pre-formatter text fragment.
+\
+
+|
+"
+EOI
+$* --generate-html --stdout test.cli >>EOO;
+ <div class="note">
+ <p>This is a note para one.</p>
+
+ <pre>And this is a
+pre-formatter text fragment.</pre>
+ </div>
+
+EOO
+$* --generate-txt --stdout test.cli >>EOO
+| This is a note para one.
+|
+| And this is a
+| pre-formatter text fragment.
+EOO
+
+# This is not yet supported (see txt_wrap_lines()).
+#
+#\
+: block-list
+:
+cat <<EOI >=test.cli;
+"
+\N|This is a note para one followed by a list.
+
+\ul|
+
+\li|This is a list item that is quite long and therefore it may span many
+lines in order to make text easy to read.|||
+"
+EOI
+$* --generate-html --stdout test.cli >>EOO;
+EOO
+$* --generate-txt --stdout test.cli >>EOO
+EOO
+#\
+
+: block-in-list
+:
+cat <<EOI >=test.cli;
+"
+\ul|
+
+\li|Normal text para.
+
+\N|This is a note para one that is quite long and therefore it may span many
+lines in order to make text easy to read.|||
+"
+EOI
+$* --generate-html --stdout test.cli >>EOO;
+ <ul>
+ <li>Normal text para.
+
+ <div class="note">
+ <p>This is a note para one that is quite long and therefore it may span many
+ lines in order to make text easy to read.</p>
+ </div></li>
+ </ul>
+
+EOO
+$* --generate-txt --stdout test.cli >>EOO
+* Normal text para.
+
+ | This is a note para one that is quite long and therefore it may span many
+ | lines in order to make text easy to read.
+EOO
+
+
+: span-basics
+:
+cat <<EOI >=test.cli;
+"
+This is normal text. \N{This is a note.} And this is normal text again.
+"
+EOI
+$* --generate-html --stdout test.cli >>EOO;
+ <p>This is normal text. <span class="note">This is a note.</span> And this
+ is normal text again.</p>
+
+EOO
+ $* --generate-txt --stdout test.cli >>EOO
+This is normal text. [Note: This is a note.] And this is normal text again.
+EOO
+
+
+: span-nested-link
+:
+cat <<EOI >=test.cli;
+"
+\N{This is a note with a \l{https://example.com link} inside.}
+"
+EOI
+$* --generate-html --stdout test.cli >>EOO;
+ <p><span class="note">This is a note with a <a
+ href="https://example.com">link</a> inside.</span></p>
+
+EOO
+$* --generate-txt --stdout test.cli >>EOO
+[Note: This is a note with a link (https://example.com) inside.]
+EOO
diff --git a/cli/tests/toc/buildfile b/cli/tests/toc/buildfile
new file mode 100644
index 0000000..50a9ec0
--- /dev/null
+++ b/cli/tests/toc/buildfile
@@ -0,0 +1,8 @@
+# file : tests/toc/buildfile
+# license : MIT; see accompanying LICENSE file
+
+import! [metadata] cli = cli%exe{cli}
+
+./: testscript $cli
+
+testscript{*}: test = $cli
diff --git a/cli/tests/toc/testscript b/cli/tests/toc/testscript
new file mode 100644
index 0000000..6b3ff3e
--- /dev/null
+++ b/cli/tests/toc/testscript
@@ -0,0 +1,155 @@
+# file : tests/toc/testscript
+# license : MIT; see accompanying LICENSE file
+
+: toc
+:
+cat <<EOI >=toc.cli;
+"\h1|Table of Contents|"
+"\$TOC$"
+
+"
+\h0#preface|Preface|
+
+This document describes something awesome.
+
+\h#about-document|About This Document|
+
+And this document is also awesome.
+
+\h#more-information|More Information|
+
+It is so awesome that no further information will be required."
+
+"
+\H#part1|PART I|
+
+Start of part one.
+
+\h1#intro|Introduction|
+
+Beginning of the first chapter.
+
+\h#arch-flow|Architecture and Workflow|
+
+Some basics.
+
+\h#benefits|Benefits|
+
+You will like them.
+
+\h1#hello|Hello World|
+
+Beginning of the second chapter.
+
+\h#hell-setup|Setup|
+
+More basics.
+
+\h#hello-compile|Compiling|
+
+How to build the example
+
+\h2#hello-compile-gcc|Compiling with GCC|
+
+GCC. For Clang see \l{#hello-compile-clang Compiling with Clang}.
+
+\h2#hello-compile-clang|Compiling with Clang|
+
+Clang. For GCC see \l{#hello-compile-gcc Compiling with GCC}.
+
+\h#hello-conclusion|Conclusion|
+
+Some remarks.
+"
+EOI
+$* --generate-html --stdout toc.cli >>EOO
+ <h1>Table of Contents</h1>
+
+ <table class="toc">
+ <tr><td class="preface" colspan="2"><a href="#preface">Preface</a>
+ <table class="toc">
+ <tr><td class="preface" colspan="2"><a href="#about-document">About
+This Document</a></td></tr>
+ <tr><td class="preface" colspan="2"><a href="#more-information">More
+Information</a></td></tr>
+ </table>
+ </td></tr>
+ <tr><th colspan="2"><a href="#part1">PART I</a></th></tr>
+ <tr><th>1</th><td><a href="#intro">Introduction</a>
+ <table class="toc">
+ <tr><th>1.1</th><td><a href="#arch-flow">Architecture and
+Workflow</a></td></tr>
+ <tr><th>1.2</th><td><a href="#benefits">Benefits</a></td></tr>
+ </table>
+ </td></tr>
+ <tr><th>2</th><td><a href="#hello">Hello World</a>
+ <table class="toc">
+ <tr><th>2.1</th><td><a href="#hell-setup">Setup</a></td></tr>
+ <tr><th>2.2</th><td><a href="#hello-compile">Compiling</a>
+ <table class="toc">
+ <tr><th>2.2.1</th><td><a href="#hello-compile-gcc">Compiling with
+GCC</a></td></tr>
+ <tr><th>2.2.2</th><td><a href="#hello-compile-clang">Compiling
+with Clang</a></td></tr>
+ </table>
+ </td></tr>
+ <tr><th>2.3</th><td><a href="#hello-conclusion">Conclusion</a></td></tr>
+ </table>
+ </td></tr>
+ </table>
+
+ <h1 id="preface" class="preface">Preface</h1>
+
+ <p>This document describes something awesome.</p>
+
+ <h2 id="about-document">About This Document</h2>
+
+ <p>And this document is also awesome.</p>
+
+ <h2 id="more-information">More Information</h2>
+
+ <p>It is so awesome that no further information will be required.</p>
+
+ <h1 id="part1" class="part">PART I</h1>
+
+ <p>Start of part one.</p>
+
+ <h1 id="intro">1 Introduction</h1>
+
+ <p>Beginning of the first chapter.</p>
+
+ <h2 id="arch-flow">1.1 Architecture and Workflow</h2>
+
+ <p>Some basics.</p>
+
+ <h2 id="benefits">1.2 Benefits</h2>
+
+ <p>You will like them.</p>
+
+ <h1 id="hello">2 Hello World</h1>
+
+ <p>Beginning of the second chapter.</p>
+
+ <h2 id="hell-setup">2.1 Setup</h2>
+
+ <p>More basics.</p>
+
+ <h2 id="hello-compile">2.2 Compiling</h2>
+
+ <p>How to build the example</p>
+
+ <h3 id="hello-compile-gcc">2.2.1 Compiling with GCC</h3>
+
+ <p>GCC. For Clang see <a href="#hello-compile-clang">Compiling with
+ Clang</a>.</p>
+
+ <h3 id="hello-compile-clang">2.2.2 Compiling with Clang</h3>
+
+ <p>Clang. For GCC see <a href="#hello-compile-gcc">Compiling with
+ GCC</a>.</p>
+
+ <h2 id="hello-conclusion">2.3 Conclusion</h2>
+
+ <p>Some remarks.</p>
+
+EOO