summaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2020-04-08 14:51:57 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2020-04-27 11:38:53 +0300
commit720c5a33b6a49cf328fdd7611f49153cf8f60247 (patch)
tree9725f3d1f42ec90fde84520f49647edea013ce5e /cli
parent3183f3bb927a90783ae0aeaf190a0919377aabe4 (diff)
Separate tests and examples into individual packages
Also make cli module to be explicitly enabled via the config.cli configuration variable.
Diffstat (limited to 'cli')
-rw-r--r--cli/.gitignore21
-rw-r--r--cli/INSTALL6
l---------cli/LICENSE1
-rw-r--r--cli/NEWS73
-rw-r--r--cli/README15
-rw-r--r--cli/build/.gitignore3
-rw-r--r--cli/build/bootstrap.build10
-rw-r--r--cli/build/export.build9
-rw-r--r--cli/build/root.build60
-rw-r--r--cli/buildfile55
-rw-r--r--cli/cli/.gitignore7
-rw-r--r--cli/cli/buildfile75
-rw-r--r--cli/cli/cli.cxx (renamed from cli/cli.cxx)0
-rw-r--r--cli/cli/context.cxx (renamed from cli/context.cxx)0
-rw-r--r--cli/cli/context.hxx (renamed from cli/context.hxx)0
-rw-r--r--cli/cli/generator.cxx (renamed from cli/generator.cxx)0
-rw-r--r--cli/cli/generator.hxx (renamed from cli/generator.hxx)0
-rw-r--r--cli/cli/header.cxx (renamed from cli/header.cxx)0
-rw-r--r--cli/cli/header.hxx (renamed from cli/header.hxx)0
-rw-r--r--cli/cli/html.cxx (renamed from cli/html.cxx)0
-rw-r--r--cli/cli/html.hxx (renamed from cli/html.hxx)0
-rw-r--r--cli/cli/inline.cxx (renamed from cli/inline.cxx)0
-rw-r--r--cli/cli/inline.hxx (renamed from cli/inline.hxx)0
-rw-r--r--cli/cli/lexer.cxx (renamed from cli/lexer.cxx)0
-rw-r--r--cli/cli/lexer.hxx (renamed from cli/lexer.hxx)0
-rw-r--r--cli/cli/lexer.ixx (renamed from cli/lexer.ixx)0
-rw-r--r--cli/cli/lexer.test.cxx122
-rw-r--r--cli/cli/lexer.test.testscript191
-rw-r--r--cli/cli/man.cxx (renamed from cli/man.cxx)0
-rw-r--r--cli/cli/man.hxx (renamed from cli/man.hxx)0
-rw-r--r--cli/cli/name-processor.cxx (renamed from cli/name-processor.cxx)0
-rw-r--r--cli/cli/name-processor.hxx (renamed from cli/name-processor.hxx)0
-rw-r--r--cli/cli/option-types.cxx (renamed from cli/option-types.cxx)0
-rw-r--r--cli/cli/option-types.hxx (renamed from cli/option-types.hxx)0
-rw-r--r--cli/cli/options.cli (renamed from cli/options.cli)0
-rw-r--r--cli/cli/options.cxx (renamed from cli/options.cxx)0
-rw-r--r--cli/cli/options.hxx (renamed from cli/options.hxx)0
-rw-r--r--cli/cli/options.ixx (renamed from cli/options.ixx)0
-rw-r--r--cli/cli/parser.cxx (renamed from cli/parser.cxx)0
-rw-r--r--cli/cli/parser.hxx (renamed from cli/parser.hxx)0
-rw-r--r--cli/cli/parser.test.cxx45
-rw-r--r--cli/cli/parser.test.testscript242
-rw-r--r--cli/cli/runtime-header.cxx (renamed from cli/runtime-header.cxx)0
-rw-r--r--cli/cli/runtime-header.hxx (renamed from cli/runtime-header.hxx)0
-rw-r--r--cli/cli/runtime-inline.cxx (renamed from cli/runtime-inline.cxx)0
-rw-r--r--cli/cli/runtime-inline.hxx (renamed from cli/runtime-inline.hxx)0
-rw-r--r--cli/cli/runtime-source.cxx (renamed from cli/runtime-source.cxx)0
-rw-r--r--cli/cli/runtime-source.hxx (renamed from cli/runtime-source.hxx)0
-rw-r--r--cli/cli/semantics.hxx (renamed from cli/semantics.hxx)0
-rw-r--r--cli/cli/semantics/class.cxx (renamed from cli/semantics/class.cxx)0
-rw-r--r--cli/cli/semantics/class.hxx (renamed from cli/semantics/class.hxx)0
-rw-r--r--cli/cli/semantics/doc.cxx (renamed from cli/semantics/doc.cxx)0
-rw-r--r--cli/cli/semantics/doc.hxx (renamed from cli/semantics/doc.hxx)0
-rw-r--r--cli/cli/semantics/elements.cxx (renamed from cli/semantics/elements.cxx)0
-rw-r--r--cli/cli/semantics/elements.hxx (renamed from cli/semantics/elements.hxx)0
-rw-r--r--cli/cli/semantics/expression.cxx (renamed from cli/semantics/expression.cxx)0
-rw-r--r--cli/cli/semantics/expression.hxx (renamed from cli/semantics/expression.hxx)0
-rw-r--r--cli/cli/semantics/namespace.cxx (renamed from cli/semantics/namespace.cxx)0
-rw-r--r--cli/cli/semantics/namespace.hxx (renamed from cli/semantics/namespace.hxx)0
-rw-r--r--cli/cli/semantics/option.cxx (renamed from cli/semantics/option.cxx)0
-rw-r--r--cli/cli/semantics/option.hxx (renamed from cli/semantics/option.hxx)0
-rw-r--r--cli/cli/semantics/unit.cxx (renamed from cli/semantics/unit.cxx)0
-rw-r--r--cli/cli/semantics/unit.hxx (renamed from cli/semantics/unit.hxx)0
-rw-r--r--cli/cli/semantics/unit.txx (renamed from cli/semantics/unit.txx)0
-rw-r--r--cli/cli/source.cxx (renamed from cli/source.cxx)0
-rw-r--r--cli/cli/source.hxx (renamed from cli/source.hxx)0
-rw-r--r--cli/cli/token.hxx (renamed from cli/token.hxx)0
-rw-r--r--cli/cli/token.ixx (renamed from cli/token.ixx)0
-rw-r--r--cli/cli/traversal.hxx (renamed from cli/traversal.hxx)0
-rw-r--r--cli/cli/traversal/class.cxx (renamed from cli/traversal/class.cxx)0
-rw-r--r--cli/cli/traversal/class.hxx (renamed from cli/traversal/class.hxx)0
-rw-r--r--cli/cli/traversal/doc.hxx (renamed from cli/traversal/doc.hxx)0
-rw-r--r--cli/cli/traversal/elements.cxx (renamed from cli/traversal/elements.cxx)0
-rw-r--r--cli/cli/traversal/elements.hxx (renamed from cli/traversal/elements.hxx)0
-rw-r--r--cli/cli/traversal/expression.hxx (renamed from cli/traversal/expression.hxx)0
-rw-r--r--cli/cli/traversal/namespace.cxx (renamed from cli/traversal/namespace.cxx)0
-rw-r--r--cli/cli/traversal/namespace.hxx (renamed from cli/traversal/namespace.hxx)0
-rw-r--r--cli/cli/traversal/option.cxx (renamed from cli/traversal/option.cxx)0
-rw-r--r--cli/cli/traversal/option.hxx (renamed from cli/traversal/option.hxx)0
-rw-r--r--cli/cli/traversal/unit.cxx (renamed from cli/traversal/unit.cxx)0
-rw-r--r--cli/cli/traversal/unit.hxx (renamed from cli/traversal/unit.hxx)0
-rw-r--r--cli/cli/txt.cxx (renamed from cli/txt.cxx)0
-rw-r--r--cli/cli/txt.hxx (renamed from cli/txt.hxx)0
-rw-r--r--cli/cli/version.hxx.in (renamed from cli/version.hxx.in)0
-rw-r--r--cli/doc/.gitignore2
-rw-r--r--cli/doc/buildfile20
-rw-r--r--cli/doc/cli-epilogue.121
-rw-r--r--cli/doc/cli-epilogue.xhtml24
-rw-r--r--cli/doc/cli-prologue.159
-rw-r--r--cli/doc/cli-prologue.xhtml72
-rw-r--r--cli/doc/default.css322
-rwxr-xr-xcli/doc/doc.sh78
-rw-r--r--cli/doc/guide/.gitignore2
-rw-r--r--cli/doc/guide/guide.html2ps63
-rw-r--r--cli/doc/guide/index.xhtml1336
-rw-r--r--cli/doc/language.txt128
-rw-r--r--cli/manifest21
97 files changed, 3031 insertions, 52 deletions
diff --git a/cli/.gitignore b/cli/.gitignore
index bb4f521..cece09c 100644
--- a/cli/.gitignore
+++ b/cli/.gitignore
@@ -1,2 +1,19 @@
-cli
-version.hxx
+# Compiler/linker output.
+#
+*.d
+*.t
+*.i
+*.ii
+*.o
+*.obj
+*.so
+*.dll
+*.a
+*.lib
+*.exp
+*.pdb
+*.ilk
+*.exe
+*.exe.dlls/
+*.exe.manifest
+*.pc
diff --git a/cli/INSTALL b/cli/INSTALL
new file mode 100644
index 0000000..abb0f51
--- /dev/null
+++ b/cli/INSTALL
@@ -0,0 +1,6 @@
+The easiest way to build this package is with the bpkg package manager:
+
+$ bpkg build cli
+
+But if you don't want to use the package manager, then you can also build it
+manually using the standard build2 build system.
diff --git a/cli/LICENSE b/cli/LICENSE
new file mode 120000
index 0000000..ea5b606
--- /dev/null
+++ b/cli/LICENSE
@@ -0,0 +1 @@
+../LICENSE \ No newline at end of file
diff --git a/cli/NEWS b/cli/NEWS
new file mode 100644
index 0000000..a1fe25e
--- /dev/null
+++ b/cli/NEWS
@@ -0,0 +1,73 @@
+Version 1.2.0
+
+ * New option, --generate-merge, triggers the generation of the merge()
+ 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, --suppress-undocumented, suppresses the generation of
+ documentation entries for undocumented options.
+
+ * New option, --cli-namespace, allows changing of the namespace for the
+ generated CLI support types.
+
+ * The argv_file_scanner now supports double and single-quoting option
+ values in option files. This is useful to preserve leading and trailing
+ whitespaces as well as to specify empty values.
+
+ * The argv_file_scanner now supports multiple file options as well as
+ file search callbacks.
+
+Version 1.1.0
+
+ * Support for option documentation. Option documentation is used to print
+ the usage information as well as to generate the program documentation in
+ the HTML and man page formats. For details, see Sections 2.5, "Adding
+ Documentation" and 3.3, "Option Documentation" in the Getting Started
+ Guide. New CLI compiler command line options related to this feature:
+
+ --suppress-usage
+ --long-usage
+ --option-length
+ --generate-cxx
+ --generate-man
+ --generate-html
+ --man-prologue
+ --man-epilogue
+ --html-prologue
+ --html-epilogue
+ --man-suffix
+ --html-suffix
+ --class
+ --stdout
+
+ The CLI compiler usage, HTML documentation, and man page are auto-generated
+ using this feature.
+
+ * New option, --generate-modifier, triggers the generation of the option
+ value modifiers in addition to the accessors.
+
+ * Support for erasing the parsed elements from the argc/argv array. See
+ Section 3.1, "Option Class Definition" in the Getting Started Guide for
+ more information.
+
+ * New scanner interface. Starting with this version, the option class has
+ a new constructor which accepts an abstract scanner interface. See Section
+ 3.1, "Option Class Definition" in the Getting Started Guide for more
+ information.
+
+ * New option, --generate-file-scanner, triggers the generation of the
+ argv_file_scanner scanner implementation which provides support for
+ reading command line arguments from the argv array as well as files
+ specified with command line options. For more information see Section
+ 3.1, "Option Class Definition" in the Getting Started Guide as well as
+ the 'file' example.
+
+ * New option, --options-file, allows additional CLI command line options
+ to be provided in files (implemented using argv_file_scanner).
+
+Version 1.0.0
+
+ * First public release.
diff --git a/cli/README b/cli/README
new file mode 100644
index 0000000..d2c6a02
--- /dev/null
+++ b/cli/README
@@ -0,0 +1,15 @@
+CLI is a Command Line Interface definition language for C++. This package
+contains the compiler implementation for this language.
+
+See the NEWS file for the user-visible changes from the previous release.
+
+See the LICENSE file for distribution conditions.
+
+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/.
+
+Send questions, bug reports, or any other feedback to
+cli-users@codesynthesis.com.
diff --git a/cli/build/.gitignore b/cli/build/.gitignore
new file mode 100644
index 0000000..e931f20
--- /dev/null
+++ b/cli/build/.gitignore
@@ -0,0 +1,3 @@
+config.build
+root/
+bootstrap/ \ No newline at end of file
diff --git a/cli/build/bootstrap.build b/cli/build/bootstrap.build
new file mode 100644
index 0000000..1e5c8a4
--- /dev/null
+++ b/cli/build/bootstrap.build
@@ -0,0 +1,10 @@
+# file : build/bootstrap.build
+# license : MIT; see accompanying LICENSE file
+
+project = cli
+
+using version
+using config
+using dist
+using test
+using install
diff --git a/cli/build/export.build b/cli/build/export.build
new file mode 100644
index 0000000..92c546c
--- /dev/null
+++ b/cli/build/export.build
@@ -0,0 +1,9 @@
+# file : build/export.build
+# license : MIT; see accompanying LICENSE file
+
+$out_root/
+{
+ include cli/
+}
+
+export $out_root/cli/exe{cli}
diff --git a/cli/build/root.build b/cli/build/root.build
new file mode 100644
index 0000000..c611c4f
--- /dev/null
+++ b/cli/build/root.build
@@ -0,0 +1,60 @@
+# file : build/root.build
+# license : MIT; see accompanying LICENSE file
+
+# Regenerate the options parsing code (included into the repository).
+#
+# 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
+
+cxx.std = latest
+
+using cxx
+
+hxx{*}: extension = hxx
+ixx{*}: extension = ixx
+txx{*}: extension = txx
+cxx{*}: extension = cxx
+
+if ($cxx.target.system == 'win32-msvc')
+ cxx.poptions += -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS
+
+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.
+#
+if ($config.cli != [null] && $config.cli != false)
+ using cli
+
+# All exe{} in unit-tests/ are, well, tests. Also don't link whole archives
+# by default there.
+#
+unit-tests/exe{*}: test = true
+unit-tests/{libue libul}{*}: bin.whole = false
+
+# Specify the test target for cross-testing.
+#
+test.target = $cxx.target
diff --git a/cli/buildfile b/cli/buildfile
index d6723d0..832328a 100644
--- a/cli/buildfile
+++ b/cli/buildfile
@@ -1,54 +1,9 @@
-# file : cli/buildfile
+# file : buildfile
# license : MIT; see accompanying LICENSE file
-import libs = libcutl%lib{cutl}
+./: {*/ -build/} doc{INSTALL LICENSE NEWS README} manifest
-exe{cli}: cxx{cli} libue{cli}
-{
- # Target metadata, see also --build2-metadata in cli.cxx.
- #
- cli.version = $version.project_id
- cli.checksum = $version
-}
-
-libue{cli}: {hxx ixx txx cxx}{** -cli -version -options} \
- {hxx}{version} {hxx ixx cxx}{options} \
- $libs
-
-hxx{version}: in{version} $src_root/manifest
-
-# 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 parser.
+# Don't install unit tests or the INSTALL file.
#
-if $cli.configured
-{
- cli.cxx{options}: cli{options}
-
- cli.options += --include-with-brackets --include-prefix cli \
---guard-prefix CLI --generate-file-scanner --generate-specifier \
---generate-modifier --reserved-name stdout
-
- 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)
-
- # We keep the generated code in the repository so copy it back to src
- # in case of a forwarded configuration.
- #
- backlink = overwrite
- }
-}
+unit-tests/: install = false
+doc{INSTALL}@./: install = false
diff --git a/cli/cli/.gitignore b/cli/cli/.gitignore
new file mode 100644
index 0000000..903d015
--- /dev/null
+++ b/cli/cli/.gitignore
@@ -0,0 +1,7 @@
+cli
+version.hxx
+
+# Unit test executables and Testscript output directories (can be symlinks).
+#
+*.test
+test-*.test
diff --git a/cli/cli/buildfile b/cli/cli/buildfile
new file mode 100644
index 0000000..ff562c2
--- /dev/null
+++ b/cli/cli/buildfile
@@ -0,0 +1,75 @@
+# file : cli/buildfile
+# license : MIT; see accompanying LICENSE file
+
+import libs = libcutl%lib{cutl}
+
+./: exe{cli}: cxx{cli} libue{cli}
+
+# Target metadata, see also --build2-metadata in cli.cxx.
+#
+exe{cli}:
+{
+ cli.version = $version.project_id
+ cli.checksum = $version
+}
+
+libue{cli}: {hxx ixx txx cxx}{** -cli -version -options -**.test...} \
+ {hxx}{version} {hxx ixx cxx}{options} \
+ $libs
+
+hxx{version}: in{version} $src_root/manifest
+
+# Unit tests.
+#
+exe{*.test}:
+{
+ test = true
+ install = false
+}
+
+for t: cxx{**.test...}
+{
+ d = $directory($t)
+ n = $name($t)...
+
+ ./: $d/exe{$n}: $t $d/{hxx ixx txx}{+$n} $d/testscript{+$n}
+ $d/exe{$n}: libue{cli}: bin.whole = false
+}
+
+# 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.
+#
+if ($config.cli != [null] && $config.cli != false)
+{
+ cli.cxx{options}: cli{options}
+
+ cli.options += --include-with-brackets --include-prefix cli \
+--guard-prefix CLI --generate-file-scanner --generate-specifier \
+--generate-modifier --reserved-name stdout
+
+ 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)
+
+ # We keep the generated code in the repository so copy it back to src
+ # in case of a forwarded configuration.
+ #
+ backlink = overwrite
+ }
+}
diff --git a/cli/cli.cxx b/cli/cli/cli.cxx
index c57caee..c57caee 100644
--- a/cli/cli.cxx
+++ b/cli/cli/cli.cxx
diff --git a/cli/context.cxx b/cli/cli/context.cxx
index 54bb988..54bb988 100644
--- a/cli/context.cxx
+++ b/cli/cli/context.cxx
diff --git a/cli/context.hxx b/cli/cli/context.hxx
index 633b8ad..633b8ad 100644
--- a/cli/context.hxx
+++ b/cli/cli/context.hxx
diff --git a/cli/generator.cxx b/cli/cli/generator.cxx
index df1b99e..df1b99e 100644
--- a/cli/generator.cxx
+++ b/cli/cli/generator.cxx
diff --git a/cli/generator.hxx b/cli/cli/generator.hxx
index f567528..f567528 100644
--- a/cli/generator.hxx
+++ b/cli/cli/generator.hxx
diff --git a/cli/header.cxx b/cli/cli/header.cxx
index a2a3ccd..a2a3ccd 100644
--- a/cli/header.cxx
+++ b/cli/cli/header.cxx
diff --git a/cli/header.hxx b/cli/cli/header.hxx
index e6e68ee..e6e68ee 100644
--- a/cli/header.hxx
+++ b/cli/cli/header.hxx
diff --git a/cli/html.cxx b/cli/cli/html.cxx
index b374b91..b374b91 100644
--- a/cli/html.cxx
+++ b/cli/cli/html.cxx
diff --git a/cli/html.hxx b/cli/cli/html.hxx
index 4ba5a41..4ba5a41 100644
--- a/cli/html.hxx
+++ b/cli/cli/html.hxx
diff --git a/cli/inline.cxx b/cli/cli/inline.cxx
index 05b83db..05b83db 100644
--- a/cli/inline.cxx
+++ b/cli/cli/inline.cxx
diff --git a/cli/inline.hxx b/cli/cli/inline.hxx
index 38e7768..38e7768 100644
--- a/cli/inline.hxx
+++ b/cli/cli/inline.hxx
diff --git a/cli/lexer.cxx b/cli/cli/lexer.cxx
index 573c76b..573c76b 100644
--- a/cli/lexer.cxx
+++ b/cli/cli/lexer.cxx
diff --git a/cli/lexer.hxx b/cli/cli/lexer.hxx
index bd7b0c9..bd7b0c9 100644
--- a/cli/lexer.hxx
+++ b/cli/cli/lexer.hxx
diff --git a/cli/lexer.ixx b/cli/cli/lexer.ixx
index 1c4c42e..1c4c42e 100644
--- a/cli/lexer.ixx
+++ b/cli/cli/lexer.ixx
diff --git a/cli/cli/lexer.test.cxx b/cli/cli/lexer.test.cxx
new file mode 100644
index 0000000..0eb4dcb
--- /dev/null
+++ b/cli/cli/lexer.test.cxx
@@ -0,0 +1,122 @@
+// file : cli/lexer.test.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// license : MIT; see accompanying LICENSE file
+
+#include <fstream>
+#include <iostream>
+
+#include <cli/token.hxx>
+#include <cli/lexer.hxx>
+
+using namespace std;
+
+const char* keywords[] =
+{
+ "source",
+ "include",
+ "namespace",
+ "class",
+ "signed",
+ "unsigned",
+ "bool",
+ "char",
+ "wchar_t",
+ "short",
+ "int",
+ "long",
+ "float",
+ "double"
+};
+
+const char* punctuation[] = {
+ ";", ",", ":", "::", "{", "}", /*"(", ")",*/ "=", "|"};
+
+int
+main (int argc, char* argv[])
+{
+ if (argc != 2)
+ {
+ cerr << "usage: " << argv[0] << " file.cli" << endl;
+ return 1;
+ }
+
+ ifstream ifs;
+ ifs.exceptions (ifstream::failbit | ifstream::badbit);
+ ifs.open (argv[1]);
+
+ lexer l (ifs, argv[1]);
+
+ while (true)
+ {
+ token t (l.next ());
+
+ switch (t.type ())
+ {
+ case token::t_eos:
+ {
+ cout << "<EOS>" << endl;
+ return 0;
+ }
+ case token::t_keyword:
+ {
+ cout << "keyword: " << keywords[t.keyword ()] << endl;
+ break;
+ }
+ case token::t_identifier:
+ {
+ cout << "identifier: " << t.identifier () << endl;
+ break;
+ }
+ case token::t_punctuation:
+ {
+ cout << punctuation[t.punctuation ()] << endl;
+ break;
+ }
+ case token::t_cxx_path_lit:
+ {
+ cout << "c++ path: " << t.literal () << endl;
+ break;
+ }
+ case token::t_cli_path_lit:
+ {
+ cout << "cli path: " << t.literal () << endl;
+ break;
+ }
+ case token::t_string_lit:
+ {
+ cout << t.literal () << endl;
+ break;
+ }
+ case token::t_char_lit:
+ {
+ cout << t.literal () << endl;
+ break;
+ }
+ case token::t_bool_lit:
+ {
+ cout << t.literal () << endl;
+ break;
+ }
+ case token::t_int_lit:
+ {
+ cout << t.literal () << endl;
+ break;
+ }
+ case token::t_float_lit:
+ {
+ cout << t.literal () << endl;
+ break;
+ }
+ case token::t_call_expr:
+ {
+ cout << t.expression () << endl;
+ break;
+ }
+ case token::t_template_expr:
+ {
+ cout << t.expression () << endl;
+ break;
+ }
+ }
+ }
+}
diff --git a/cli/cli/lexer.test.testscript b/cli/cli/lexer.test.testscript
new file mode 100644
index 0000000..e2df5f6
--- /dev/null
+++ b/cli/cli/lexer.test.testscript
@@ -0,0 +1,191 @@
+# file : cli/lexer.test.testscript
+# license : MIT; see accompanying LICENSE file
+
+# @@ Give tests some meaningfull descriptions.
+#
+
+: 000
+:
+cat <<EOI >=test.cli;
+help
+help-me
+-h
+--help
+--help-me
+--help-me-
+/h
+/help-me
+/help/me
+--_
+
+EOI
+$* test.cli >>EOO
+identifier: help
+identifier: help-me
+identifier: -h
+identifier: --help
+identifier: --help-me
+identifier: --help-me-
+identifier: /h
+identifier: /help-me
+identifier: /help
+identifier: /me
+identifier: --_
+<EOS>
+EOO
+
+: 001
+:
+cat <<EOI >=test.cli;
+5
+123456
+-12345
+- 1
+-
+123
+EOI
+$* test.cli >>EOO
+5
+123456
+-12345
+-1
+-123
+<EOS>
+EOO
+
+: 002
+:
+cat <<EOI >=test.cli;
+'a'
+'\n'
+'\\'
+'\0'
+'\''
+'\xaf'
+'\111'
+EOI
+$* test.cli >>EOO
+'a'
+'\n'
+'\\'
+'\0'
+'\''
+'\xaf'
+'\111'
+<EOS>
+EOO
+
+: 003
+:
+cat <<EOI >=test.cli;
+"abc";
+"a\nb";
+"abc\\";
+"aaa\0";
+"\"";
+"a\xaf";
+"a\111";
+"abc""def";
+"abc" "def";
+"abc
+ def
+
+ xyz";
+EOI
+$* test.cli >>EOO
+"abc"
+;
+"a\nb"
+;
+"abc\\"
+;
+"aaa\0"
+;
+"\""
+;
+"a\xaf"
+;
+"a\111"
+;
+"abc""def"
+;
+"abc""def"
+;
+"abc
+ def
+
+ xyz"
+;
+<EOS>
+EOO
+
+: 004
+:
+cat <<EOI >=test.cli;
+include "foo/abc.hxx";
+include <vector>;
+include "c++:map";
+include <cli:map>;
+include "map.cli"
+EOI
+$* test.cli >>EOO
+keyword: include
+c++ path: "foo/abc.hxx"
+;
+keyword: include
+c++ path: <vector>
+;
+keyword: include
+c++ path: "map"
+;
+keyword: include
+cli path: <map>
+;
+keyword: include
+cli path: "map.cli"
+<EOS>
+EOO
+
+: 005
+:
+cat <<EOI >=test.cli;
+(abc, 123 - 345, 12.34)
+<foo, bar::baz, 123*345>
+EOI
+$* test.cli >>EOO
+(abc, 123 - 345, 12.34)
+<foo, bar::baz, 123*345>
+<EOS>
+EOO
+
+: 006
+:
+cat <<EOI >=test.cli;
+// c++ comment ;
+/* c comment ; */
+;
+"a" // foo
+"b"
+"a" /* foo
+bar
+baz */ "b";
+- // aaa
+5;
+- /* a
+a
+a*/ 5
+// eos
+:
+::
+EOI
+$* test.cli >>EOO
+;
+"a""b""a""b"
+;
+-5
+;
+-5
+:
+::
+<EOS>
+EOO
diff --git a/cli/man.cxx b/cli/cli/man.cxx
index df703e8..df703e8 100644
--- a/cli/man.cxx
+++ b/cli/cli/man.cxx
diff --git a/cli/man.hxx b/cli/cli/man.hxx
index 0825305..0825305 100644
--- a/cli/man.hxx
+++ b/cli/cli/man.hxx
diff --git a/cli/name-processor.cxx b/cli/cli/name-processor.cxx
index ab125bc..ab125bc 100644
--- a/cli/name-processor.cxx
+++ b/cli/cli/name-processor.cxx
diff --git a/cli/name-processor.hxx b/cli/cli/name-processor.hxx
index c21561b..c21561b 100644
--- a/cli/name-processor.hxx
+++ b/cli/cli/name-processor.hxx
diff --git a/cli/option-types.cxx b/cli/cli/option-types.cxx
index da1f434..da1f434 100644
--- a/cli/option-types.cxx
+++ b/cli/cli/option-types.cxx
diff --git a/cli/option-types.hxx b/cli/cli/option-types.hxx
index 02d9ede..02d9ede 100644
--- a/cli/option-types.hxx
+++ b/cli/cli/option-types.hxx
diff --git a/cli/options.cli b/cli/cli/options.cli
index e564bc4..e564bc4 100644
--- a/cli/options.cli
+++ b/cli/cli/options.cli
diff --git a/cli/options.cxx b/cli/cli/options.cxx
index cc22a35..cc22a35 100644
--- a/cli/options.cxx
+++ b/cli/cli/options.cxx
diff --git a/cli/options.hxx b/cli/cli/options.hxx
index b253092..b253092 100644
--- a/cli/options.hxx
+++ b/cli/cli/options.hxx
diff --git a/cli/options.ixx b/cli/cli/options.ixx
index 12d40db..12d40db 100644
--- a/cli/options.ixx
+++ b/cli/cli/options.ixx
diff --git a/cli/parser.cxx b/cli/cli/parser.cxx
index 4685edc..4685edc 100644
--- a/cli/parser.cxx
+++ b/cli/cli/parser.cxx
diff --git a/cli/parser.hxx b/cli/cli/parser.hxx
index 326768e..326768e 100644
--- a/cli/parser.hxx
+++ b/cli/cli/parser.hxx
diff --git a/cli/cli/parser.test.cxx b/cli/cli/parser.test.cxx
new file mode 100644
index 0000000..6ef0d11
--- /dev/null
+++ b/cli/cli/parser.test.cxx
@@ -0,0 +1,45 @@
+// file : cli/parser.test.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// license : MIT; see accompanying LICENSE file
+
+#include <fstream>
+#include <iostream>
+
+#include <cli/parser.hxx>
+#include <cli/semantics.hxx>
+#include <cli/traversal.hxx>
+
+using namespace std;
+
+int
+main (int argc, char* argv[])
+{
+ if (argc != 2)
+ {
+ cerr << "usage: " << argv[0] << " file.cli" << endl;
+ return 1;
+ }
+
+ try
+ {
+ semantics::path path (argv[1]);
+
+ ifstream ifs;
+ ifs.exceptions (ifstream::failbit | ifstream::badbit);
+ ifs.open (path.string ().c_str ());
+
+ parser::paths include_paths;
+ parser p (include_paths);
+ p.parse (ifs, path);
+ }
+ catch (semantics::invalid_path const& e)
+ {
+ cerr << "error: '" << e.path () << "' is not a valid filesystem path"
+ << endl;
+ return 1;
+ }
+ catch (parser::invalid_input const&)
+ {
+ return 1;
+ }
+}
diff --git a/cli/cli/parser.test.testscript b/cli/cli/parser.test.testscript
new file mode 100644
index 0000000..9522dbe
--- /dev/null
+++ b/cli/cli/parser.test.testscript
@@ -0,0 +1,242 @@
+# file : cli/parser.test.testscript
+# license : MIT; see accompanying LICENSE file
+
+# @@ Give tests some meaningfull descriptions. Probably move c++-style comments
+# from the test.cli files to test descriptions.
+#
+
+: 000
+:
+cat <<EOI >=test.cli;
+// def-unit
+//
+include <string>;
+namespace n {}
+class c {};
+EOI
+$* test.cli >:""
+
+: 001
+:
+cat <<EOI >=base.cli;
+EOI
+cat <<EOI >=common.cli;
+include "base.cli";
+EOI
+cat <<EOI >=test.cli;
+// include-decl-seq, include-decl
+//
+include <string>;
+include "types.hxx";
+include "common.cli";
+include "../001/base.cli";
+EOI
+$* test.cli >:""
+
+: 002
+:
+cat <<EOI >=test.cli;
+// namespace-def, namespace-def-body
+//
+namespace n1 {}
+
+namespace n1
+{
+ namespace n2 {}
+ class c {};
+ namespace n2
+ {
+ namespace n3 {}
+ }
+}
+
+namespace n4 {}
+EOI
+$* test.cli >:""
+
+: 003
+:
+cat <<EOI >=test.cli;
+// class-def, inheritance-spec, abstract-spec
+//
+class c1
+{
+};
+
+class c2 = 0
+{
+};
+
+class c3: c1, ::c2
+{
+};
+
+namespace n1
+{
+ class c {};
+}
+
+class c4: n1::c = 0
+{
+};
+
+EOI
+$* test.cli >:""
+
+: 004
+:
+cat <<EOI >=test.cli;
+// option-def-seq
+//
+class c
+{
+ bool -a;
+ int -b;
+ float -c;
+};
+EOI
+$* test.cli >:""
+
+: 005
+:
+cat <<EOI >=test.cli;
+// option-def, type-spec, fundamental-type-spec, option-name-seq,
+// option-name, initializer, initializer-expr
+//
+class c
+{
+ bool --bool;
+ char --char;
+
+ int -i1;
+ unsigned int -i2;
+ int unsigned -i3;
+ long -i4;
+ long int -i5;
+ int long -i6;
+ unsigned long -i7;
+ long unsigned -i8;
+
+ unsigned long int -i9;
+ long unsigned int -i10;
+ int long unsigned -i11;
+ unsigned int long -i12;
+
+ short -i13;
+ unsigned short -i14;
+ short unsigned -i15;
+
+ char -i16;
+ signed char -i17;
+ char signed -i18;
+ unsigned char -i19;
+ char unsigned -i20;
+
+ long long -ll1;
+ long long int -ll2;
+ long long unsigned -ll3;
+ int long long -ll4;
+ unsigned long long -ll5;
+ long long int unsigned -ll6;
+ long long unsigned int -ll7;
+ unsigned long long int -ll8;
+ unsigned int long long -ll9;
+ int long long unsigned -ll10;
+ int unsigned long long -ll11;
+
+ double -d1;
+ long double -d2;
+ double long -d3;
+
+ foo -o1;
+ ::foo -o2;
+ ::foo<bar> -o3;
+ foo::bar -o4;
+ ::foo::bar -o5;
+ ::foo<bar>::baz -o6;
+ ::foo<bar>::baz< ::fox<2> > -o7;
+
+ bool -n1|--name1|/name1;
+ bool "-n2"|"--name2";
+
+ string -init1 = "string";
+ char -init2 = 'c';
+ int -init3 = -5;
+ bool -inti4 = true;
+ long -init5 = (2 * 4 - 5);
+ type -init6 = type::default_value;
+ type -init7 (abc, 2 - 1);
+};
+EOI
+$* test.cli >:""
+
+: 006
+:
+cat <<EOI >=test.cli;
+// option-doc
+//
+class c
+{
+ bool --help | -h {"Help me"};
+
+ int --comp = 5
+ {
+ "<level>",
+ "Set compression level",
+ "Set compression level to <level>.
+
+ The minimum value for this options is 0 and
+ maximum is 9."
+ };
+};
+EOI
+$* test.cli >:""
+
+: 007
+:
+cat <<EOI >=base.cli;
+class b1 {};
+
+namespace n1
+{
+ class b2 {};
+
+ namespace i1
+ {
+ class b3 {};
+ }
+}
+EOI
+cat <<EOI >=test.cli;
+// base class lookup
+//
+
+include "base.cli";
+
+class c1 {};
+class c2: c1 {};
+class c3: ::c1 {};
+
+namespace n1
+{
+ class c4 {};
+ class c5: c4 {};
+ class c6: n1::c4 {};
+ class c7: ::n1::c4 {};
+
+ class c8: b2 {}; // From included.
+ class c9: i1::b3 {}; // From included.
+
+ namespace i1
+ {
+ class c10: c4 {}; // Outer scope.
+ class c11: b3 {}; // From included.
+ class c12: b2 {}; // Outer scope from included.
+ class c4: n1::c4 {}; // Qualified name from outer scope.
+ }
+}
+
+class c13: n1::c4 {};
+class c14: ::n1::c4 {};
+EOI
+$* test.cli >:""
diff --git a/cli/runtime-header.cxx b/cli/cli/runtime-header.cxx
index adf70dd..adf70dd 100644
--- a/cli/runtime-header.cxx
+++ b/cli/cli/runtime-header.cxx
diff --git a/cli/runtime-header.hxx b/cli/cli/runtime-header.hxx
index f4bff7c..f4bff7c 100644
--- a/cli/runtime-header.hxx
+++ b/cli/cli/runtime-header.hxx
diff --git a/cli/runtime-inline.cxx b/cli/cli/runtime-inline.cxx
index 8f0e84c..8f0e84c 100644
--- a/cli/runtime-inline.cxx
+++ b/cli/cli/runtime-inline.cxx
diff --git a/cli/runtime-inline.hxx b/cli/cli/runtime-inline.hxx
index 045c060..045c060 100644
--- a/cli/runtime-inline.hxx
+++ b/cli/cli/runtime-inline.hxx
diff --git a/cli/runtime-source.cxx b/cli/cli/runtime-source.cxx
index 36d8968..36d8968 100644
--- a/cli/runtime-source.cxx
+++ b/cli/cli/runtime-source.cxx
diff --git a/cli/runtime-source.hxx b/cli/cli/runtime-source.hxx
index 0e51c4b..0e51c4b 100644
--- a/cli/runtime-source.hxx
+++ b/cli/cli/runtime-source.hxx
diff --git a/cli/semantics.hxx b/cli/cli/semantics.hxx
index 4b18629..4b18629 100644
--- a/cli/semantics.hxx
+++ b/cli/cli/semantics.hxx
diff --git a/cli/semantics/class.cxx b/cli/cli/semantics/class.cxx
index 494d5d0..494d5d0 100644
--- a/cli/semantics/class.cxx
+++ b/cli/cli/semantics/class.cxx
diff --git a/cli/semantics/class.hxx b/cli/cli/semantics/class.hxx
index ca7de8c..ca7de8c 100644
--- a/cli/semantics/class.hxx
+++ b/cli/cli/semantics/class.hxx
diff --git a/cli/semantics/doc.cxx b/cli/cli/semantics/doc.cxx
index c31260c..c31260c 100644
--- a/cli/semantics/doc.cxx
+++ b/cli/cli/semantics/doc.cxx
diff --git a/cli/semantics/doc.hxx b/cli/cli/semantics/doc.hxx
index 8dacb7a..8dacb7a 100644
--- a/cli/semantics/doc.hxx
+++ b/cli/cli/semantics/doc.hxx
diff --git a/cli/semantics/elements.cxx b/cli/cli/semantics/elements.cxx
index ed8eb7d..ed8eb7d 100644
--- a/cli/semantics/elements.cxx
+++ b/cli/cli/semantics/elements.cxx
diff --git a/cli/semantics/elements.hxx b/cli/cli/semantics/elements.hxx
index 6235a06..6235a06 100644
--- a/cli/semantics/elements.hxx
+++ b/cli/cli/semantics/elements.hxx
diff --git a/cli/semantics/expression.cxx b/cli/cli/semantics/expression.cxx
index 18d3312..18d3312 100644
--- a/cli/semantics/expression.cxx
+++ b/cli/cli/semantics/expression.cxx
diff --git a/cli/semantics/expression.hxx b/cli/cli/semantics/expression.hxx
index e36a0cb..e36a0cb 100644
--- a/cli/semantics/expression.hxx
+++ b/cli/cli/semantics/expression.hxx
diff --git a/cli/semantics/namespace.cxx b/cli/cli/semantics/namespace.cxx
index 3c2643c..3c2643c 100644
--- a/cli/semantics/namespace.cxx
+++ b/cli/cli/semantics/namespace.cxx
diff --git a/cli/semantics/namespace.hxx b/cli/cli/semantics/namespace.hxx
index 00c7bfc..00c7bfc 100644
--- a/cli/semantics/namespace.hxx
+++ b/cli/cli/semantics/namespace.hxx
diff --git a/cli/semantics/option.cxx b/cli/cli/semantics/option.cxx
index 8746a5e..8746a5e 100644
--- a/cli/semantics/option.cxx
+++ b/cli/cli/semantics/option.cxx
diff --git a/cli/semantics/option.hxx b/cli/cli/semantics/option.hxx
index a9bb963..a9bb963 100644
--- a/cli/semantics/option.hxx
+++ b/cli/cli/semantics/option.hxx
diff --git a/cli/semantics/unit.cxx b/cli/cli/semantics/unit.cxx
index 9c532ea..9c532ea 100644
--- a/cli/semantics/unit.cxx
+++ b/cli/cli/semantics/unit.cxx
diff --git a/cli/semantics/unit.hxx b/cli/cli/semantics/unit.hxx
index e37648a..e37648a 100644
--- a/cli/semantics/unit.hxx
+++ b/cli/cli/semantics/unit.hxx
diff --git a/cli/semantics/unit.txx b/cli/cli/semantics/unit.txx
index 99d178f..99d178f 100644
--- a/cli/semantics/unit.txx
+++ b/cli/cli/semantics/unit.txx
diff --git a/cli/source.cxx b/cli/cli/source.cxx
index 9cd2382..9cd2382 100644
--- a/cli/source.cxx
+++ b/cli/cli/source.cxx
diff --git a/cli/source.hxx b/cli/cli/source.hxx
index b27cf76..b27cf76 100644
--- a/cli/source.hxx
+++ b/cli/cli/source.hxx
diff --git a/cli/token.hxx b/cli/cli/token.hxx
index 7045826..7045826 100644
--- a/cli/token.hxx
+++ b/cli/cli/token.hxx
diff --git a/cli/token.ixx b/cli/cli/token.ixx
index 77ab225..77ab225 100644
--- a/cli/token.ixx
+++ b/cli/cli/token.ixx
diff --git a/cli/traversal.hxx b/cli/cli/traversal.hxx
index 1961f7b..1961f7b 100644
--- a/cli/traversal.hxx
+++ b/cli/cli/traversal.hxx
diff --git a/cli/traversal/class.cxx b/cli/cli/traversal/class.cxx
index b920f1f..b920f1f 100644
--- a/cli/traversal/class.cxx
+++ b/cli/cli/traversal/class.cxx
diff --git a/cli/traversal/class.hxx b/cli/cli/traversal/class.hxx
index 38cbefc..38cbefc 100644
--- a/cli/traversal/class.hxx
+++ b/cli/cli/traversal/class.hxx
diff --git a/cli/traversal/doc.hxx b/cli/cli/traversal/doc.hxx
index 70a6dfd..70a6dfd 100644
--- a/cli/traversal/doc.hxx
+++ b/cli/cli/traversal/doc.hxx
diff --git a/cli/traversal/elements.cxx b/cli/cli/traversal/elements.cxx
index f3353f2..f3353f2 100644
--- a/cli/traversal/elements.cxx
+++ b/cli/cli/traversal/elements.cxx
diff --git a/cli/traversal/elements.hxx b/cli/cli/traversal/elements.hxx
index a2ada23..a2ada23 100644
--- a/cli/traversal/elements.hxx
+++ b/cli/cli/traversal/elements.hxx
diff --git a/cli/traversal/expression.hxx b/cli/cli/traversal/expression.hxx
index 0888455..0888455 100644
--- a/cli/traversal/expression.hxx
+++ b/cli/cli/traversal/expression.hxx
diff --git a/cli/traversal/namespace.cxx b/cli/cli/traversal/namespace.cxx
index c938f77..c938f77 100644
--- a/cli/traversal/namespace.cxx
+++ b/cli/cli/traversal/namespace.cxx
diff --git a/cli/traversal/namespace.hxx b/cli/cli/traversal/namespace.hxx
index 5709f2a..5709f2a 100644
--- a/cli/traversal/namespace.hxx
+++ b/cli/cli/traversal/namespace.hxx
diff --git a/cli/traversal/option.cxx b/cli/cli/traversal/option.cxx
index ff5dcce..ff5dcce 100644
--- a/cli/traversal/option.cxx
+++ b/cli/cli/traversal/option.cxx
diff --git a/cli/traversal/option.hxx b/cli/cli/traversal/option.hxx
index e11fa21..e11fa21 100644
--- a/cli/traversal/option.hxx
+++ b/cli/cli/traversal/option.hxx
diff --git a/cli/traversal/unit.cxx b/cli/cli/traversal/unit.cxx
index cf10d1d..cf10d1d 100644
--- a/cli/traversal/unit.cxx
+++ b/cli/cli/traversal/unit.cxx
diff --git a/cli/traversal/unit.hxx b/cli/cli/traversal/unit.hxx
index eab42aa..eab42aa 100644
--- a/cli/traversal/unit.hxx
+++ b/cli/cli/traversal/unit.hxx
diff --git a/cli/txt.cxx b/cli/cli/txt.cxx
index 16de45a..16de45a 100644
--- a/cli/txt.cxx
+++ b/cli/cli/txt.cxx
diff --git a/cli/txt.hxx b/cli/cli/txt.hxx
index cde31c9..cde31c9 100644
--- a/cli/txt.hxx
+++ b/cli/cli/txt.hxx
diff --git a/cli/version.hxx.in b/cli/cli/version.hxx.in
index 90b649a..90b649a 100644
--- a/cli/version.hxx.in
+++ b/cli/cli/version.hxx.in
diff --git a/cli/doc/.gitignore b/cli/doc/.gitignore
new file mode 100644
index 0000000..562ecbd
--- /dev/null
+++ b/cli/doc/.gitignore
@@ -0,0 +1,2 @@
+cli.xhtml
+cli.1
diff --git a/cli/doc/buildfile b/cli/doc/buildfile
new file mode 100644
index 0000000..f47adad
--- /dev/null
+++ b/cli/doc/buildfile
@@ -0,0 +1,20 @@
+# file : doc/buildfile
+# license : MIT; see accompanying LICENSE file
+
+define css: doc
+css{*}: extension = css
+
+define xhtml: doc
+xhtml{*}: extension = xhtml
+
+./: {man1 xhtml}{cli} \
+ css{default} \
+ file{cli-*}
+
+./: guide/doc{cli-guide*} \
+ guide/xhtml{index} \
+ guide/file{*.html2ps}
+
+doc{*}: install.subdirs = true
+
+./: file{doc.sh}
diff --git a/cli/doc/cli-epilogue.1 b/cli/doc/cli-epilogue.1
new file mode 100644
index 0000000..5e2ffae
--- /dev/null
+++ b/cli/doc/cli-epilogue.1
@@ -0,0 +1,21 @@
+.\"
+.\" 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) $copyright$.
+
+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/cli-epilogue.xhtml b/cli/doc/cli-epilogue.xhtml
new file mode 100644
index 0000000..8a70d81
--- /dev/null
+++ b/cli/doc/cli-epilogue.xhtml
@@ -0,0 +1,24 @@
+ <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; $copyright$.
+
+ <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/doc/cli-prologue.1 b/cli/doc/cli-prologue.1
new file mode 100644
index 0000000..165cd1a
--- /dev/null
+++ b/cli/doc/cli-prologue.1
@@ -0,0 +1,59 @@
+.\" Process this file with
+.\" groff -man -Tascii cli.1
+.\"
+.TH CLI 1 "December 2009" "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
+.\"--------------------------------------------------------------------
diff --git a/cli/doc/cli-prologue.xhtml b/cli/doc/cli-prologue.xhtml
new file mode 100644
index 0000000..9a57f0e
--- /dev/null
+++ b/cli/doc/cli-prologue.xhtml
@@ -0,0 +1,72 @@
+<!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; $copyright$"/>
+ <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>
diff --git a/cli/doc/default.css b/cli/doc/default.css
new file mode 100644
index 0000000..c73bb8d
--- /dev/null
+++ b/cli/doc/default.css
@@ -0,0 +1,322 @@
+html {
+ margin : 0;
+ padding : 0;
+ background : white;
+}
+
+body {
+ font-family : "Lucida Grande", Verdana, "Bitstream Vera Sans", sans-serif;
+ font-weight : normal;
+ font-size : 13px;
+ line-height : 19px;
+
+ color : black;
+
+ margin : 0 2em 0 2em;
+ padding : 0;
+}
+
+
+body {
+ min-width: 40em;
+}
+
+#container {
+ max-width : 46em;
+ margin : 0 auto;
+ padding : 0 1em 0 1em;
+}
+
+
+
+/*
+ * Footer
+ *
+ */
+#footer {
+ color : #3a84a7;
+
+ padding : 1em 0 0.5em 0;
+
+ font-size : 10px;
+ line-height : 15px;
+
+ text-align: center;
+}
+
+#footer a:link, #footer a:visited {
+
+ color:#1d6699;
+ text-decoration: underline;
+}
+
+#footer a {
+ margin-left: 0.7em;
+ margin-right: 0.7em;
+}
+
+#footer p {
+ padding: 0;
+ margin: 0.3em 0 0 0;
+}
+
+/* Distribution terms. */
+#footer #terms {
+ text-align: justify;
+
+ font-size : 110%;
+ font-family : monospace;
+
+ padding : 1em 0 0.5em 0;
+}
+
+
+/*
+ * Content
+ *
+ */
+
+#content {
+ padding : 0em 0.1em 0 1.3em;
+ margin : 1.4em 0 0 0;
+}
+
+#content p,
+#content ol,
+#content ul,
+#content dl {
+ text-align: justify;
+}
+
+#content h1 {
+ margin-left: -0.89em;
+}
+
+a:link {
+ color:#0536d2;
+}
+
+
+/*
+ * Headings
+ *
+ */
+
+h1, h2, h3, h4, h5, h6 {
+ font-weight : 500;
+}
+
+h1 { font-size : 155%; }
+h2 { font-size : 130%; }
+h3 { font-size : 125%; }
+h4 { font-size : 110%; }
+h5 { font-size : 106%; }
+h6 { font-size : 100%; }
+
+h1 { margin : 1.8em 0 0.8em 0;}
+h2 { margin-top : 1.4em;}
+h3 { margin-top : 1em;}
+
+p.indent {
+ margin-left : 1.5em;
+}
+
+
+/*
+ * Fix for IE 5.5 table font problem
+ *
+ */
+
+table {
+ font-size : 13px;
+}
+
+
+/*
+ * table of content
+ *
+ */
+
+ul.toc li {
+ padding : .4em 0em 0em 0em;
+}
+
+
+/* Toc links don't need to show when they are visited. */
+.toc a:visited {
+ color:#0536d2;
+}
+
+
+/*
+ * lists
+ *
+ */
+
+
+/* list of links */
+ul.menu {
+ list-style-type : none;
+}
+
+ul.menu li {
+ padding-top : 0.3em;
+ padding-bottom : 0.3em;
+}
+
+
+
+/* @@ I should probably use child selector here */
+/* list with multiline list-elements */
+ul.multiline li, ol.multiline li, dl.multiline dd {
+ padding-top : 0.16em;
+ padding-bottom : 0.16em;
+
+ font-size : 11px;
+ line-height : 15px;
+}
+
+
+/* C++ code snippet */
+pre.cxx {
+ margin-top : 0em;
+ margin-bottom : 2em;
+
+ margin-left : 1em;
+}
+
+/* CLI code snippet */
+pre.cli {
+ margin-top : 0em;
+ margin-bottom : 2em;
+
+ margin-left : 1em;
+}
+
+/* make code snippet */
+pre.make {
+ margin-top : 0em;
+ margin-bottom : 2em;
+
+ margin-left : 1em;
+}
+
+/* terminal output */
+pre.term {
+ margin-top : 0em;
+ margin-bottom : 2em;
+
+ margin-left : 1em;
+}
+
+
+/* Images */
+div.center {
+ text-align: center;
+}
+
+/* Document info. */
+#docinfo {
+ margin-top: 4em;
+ border-top: 1px dashed #000000;
+ font-size: 70%;
+}
+
+
+/* Footnote */
+
+#footnote {
+ margin-top : 2.5em;
+}
+
+#footnote hr, hr.footnote {
+ margin-left: 0;
+ margin-bottom: 0.6em;
+ width: 8em;
+ border-top: 1px solid #000000;
+ border-right: none;
+ border-bottom: none;
+ border-left: none;
+
+}
+
+#footnote ol {
+ margin-left: 0;
+ padding-left: 1.45em;
+}
+
+#footnote li {
+ text-align : left;
+ font-size : 11px;
+ line-height : 15px;
+
+ padding : .4em 0 .4em 0;
+}
+
+
+/* Normal table with borders, etc. */
+
+table.std {
+ margin: 2em 0 2em 0;
+
+ border-collapse : collapse;
+ border : 1px solid;
+ border-color : #000000;
+
+ font-size : 11px;
+ line-height : 14px;
+}
+
+table.std th, table.std td {
+ border : 1px solid;
+ padding : 0.6em 0.8em 0.6em 0.8em;
+}
+
+table.std th {
+ background : #cde8f6;
+}
+
+table.std td {
+ text-align: left;
+}
+
+
+/*
+ * "item | description" table.
+ *
+ */
+
+table.description {
+ border-style : none;
+ border-collapse : separate;
+ border-spacing : 0;
+
+ font-size : 13px;
+
+ margin : 0.6em 0 0.6em 0;
+ padding : 0 0 0 0;
+}
+
+table.description tr {
+ padding : 0 0 0 0;
+ margin : 0 0 0 0;
+}
+
+table.description * td, table.description * th {
+ border-style : none;
+ margin : 0 0 0 0;
+ vertical-align : top;
+}
+
+table.description * th {
+ font-weight : normal;
+ padding : 0.4em 1em 0.4em 0;
+ text-align : left;
+ white-space : nowrap;
+ background : none;
+}
+
+table.description * td {
+ padding : 0.4em 0 0.4em 1em;
+ text-align : justify;
+}
diff --git a/cli/doc/doc.sh b/cli/doc/doc.sh
new file mode 100755
index 0000000..dde9aca
--- /dev/null
+++ b/cli/doc/doc.sh
@@ -0,0 +1,78 @@
+#! /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/.gitignore b/cli/doc/guide/.gitignore
new file mode 100644
index 0000000..239cc7f
--- /dev/null
+++ b/cli/doc/guide/.gitignore
@@ -0,0 +1,2 @@
+*.ps
+*.pdf
diff --git a/cli/doc/guide/guide.html2ps b/cli/doc/guide/guide.html2ps
new file mode 100644
index 0000000..a691002
--- /dev/null
+++ b/cli/doc/guide/guide.html2ps
@@ -0,0 +1,63 @@
+@html2ps {
+ option {
+ toc: hb;
+ colour: 1;
+ hyphenate: 1;
+ titlepage: 1;
+ }
+
+ datefmt: "%B %Y";
+
+ titlepage {
+ content: "
+<div align=center>
+ <h1><big>CLI Language</big></h1>
+ <h1><big>Getting Started Guide</big></h1>
+ <h1>&nbsp;</h1>
+ <h1>&nbsp;</h1>
+ <h1>&nbsp;</h1>
+ <h1>&nbsp;</h1>
+ <h1>&nbsp;</h1>
+ <h1>&nbsp;</h1>
+</div>
+ <p>Copyright &#169; 2009-2020 Code Synthesis Tools CC.</p>
+
+ <p>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>.
+ </p>
+
+ <p>This document is available in the following formats:
+ <a href='http://www.codesynthesis.com/projects/cli/doc/guide/index.xhtml'>XHTML</a>,
+ <a href='http://www.codesynthesis.com/projects/cli/doc/guide/cli-guide.pdf'>PDF</a>, and
+ <a href='http://www.codesynthesis.com/projects/cli/doc/guide/cli-guide.ps'>PostScript</a>.</p>";
+ }
+
+ toc {
+ indent: 2em;
+ }
+
+ header {
+ odd-right: $H;
+ even-left: $H;
+ }
+
+ footer {
+ odd-left: $D;
+ odd-center: $T;
+ odd-right: $N;
+
+ even-left: $N;
+ even-center: $T;
+ even-right: $D;
+ }
+}
+
+body {
+ font-size: 12pt;
+ text-align: justify;
+}
+
+pre {
+ font-size: 10pt;
+}
diff --git a/cli/doc/guide/index.xhtml b/cli/doc/guide/index.xhtml
new file mode 100644
index 0000000..675db03
--- /dev/null
+++ b/cli/doc/guide/index.xhtml
@@ -0,0 +1,1336 @@
+<!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 Language Getting Started Guide</title>
+
+ <meta name="copyright" content="&#169; 2009-2020 Code Synthesis Tools CC"/>
+ <meta name="keywords" content="cli,command,line,interface,language,c++"/>
+ <meta name="description" content="CLI Language Getting Started Guide"/>
+
+ <link rel="stylesheet" type="text/css" href="../default.css" />
+
+<style type="text/css">
+ pre {
+ padding : 0 0 0 0em;
+ margin : 0em 0em 0em 0;
+
+ font-size : 102%
+ }
+
+ body {
+ min-width: 48em;
+ }
+
+ h1 {
+ font-weight: bold;
+ font-size: 200%;
+ line-height: 1.2em;
+ }
+
+ h2 {
+ font-weight : bold;
+ font-size : 150%;
+
+ padding-top : 0.8em;
+ }
+
+ h3 {
+ font-size : 140%;
+ padding-top : 0.8em;
+ }
+
+ /* Adjust indentation for three levels. */
+ #container {
+ max-width: 48em;
+ }
+
+ #content {
+ padding: 0 0.1em 0 4em;
+ /*background-color: red;*/
+ }
+
+ #content h1 {
+ margin-left: -2.06em;
+ }
+
+ #content h2 {
+ margin-left: -1.33em;
+ }
+
+ /* Title page */
+
+ #titlepage {
+ padding: 2em 0 1em 0;
+ border-bottom: 1px solid black;
+ }
+
+ #titlepage .title {
+ font-weight: bold;
+ font-size: 200%;
+ text-align: center;
+ }
+
+ #titlepage #first-title {
+ padding: 1em 0 0.4em 0;
+ }
+
+ #titlepage #second-title {
+ padding: 0.4em 0 2em 0;
+ }
+
+ /* Lists */
+ ul.list li, ol.list li {
+ padding-top : 0.3em;
+ padding-bottom : 0.3em;
+ }
+
+ dl dt {
+ padding : 0.8em 0 0 0;
+ }
+
+ /* TOC */
+ table.toc {
+ border-style : none;
+ border-collapse : separate;
+ border-spacing : 0;
+
+ margin : 0.2em 0 0.2em 0;
+ padding : 0 0 0 0;
+ }
+
+ table.toc tr {
+ padding : 0 0 0 0;
+ margin : 0 0 0 0;
+ }
+
+ table.toc * td, table.toc * th {
+ border-style : none;
+ margin : 0 0 0 0;
+ vertical-align : top;
+ }
+
+ table.toc * th {
+ font-weight : normal;
+ padding : 0em 0.1em 0em 0;
+ text-align : left;
+ white-space : nowrap;
+ }
+
+ table.toc * table.toc th {
+ padding-left : 1em;
+ }
+
+ table.toc * td {
+ padding : 0em 0 0em 0.7em;
+ text-align : left;
+ }
+
+ /* Sample options documentation. */
+ .options dt {
+ padding-top : 0.4em;
+ }
+
+ .options dd {
+ padding-top : 0.1em;
+ padding-bottom : 0.4em;
+ padding-left : 1.4em;
+ }
+</style>
+
+
+</head>
+
+<body>
+<div id="container">
+ <div id="content">
+
+ <div class="noprint">
+
+ <div id="titlepage">
+ <div class="title" id="first-title">CLI Language</div>
+ <div class="title" id="second-title">Getting Started Guide</div>
+
+ <p>Copyright &#169; 2009-2020 Code Synthesis Tools CC.</p>
+
+ <p>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>.
+ </p>
+
+ <p>This document is available in the following formats:
+ <a href="http://www.codesynthesis.com/projects/cli/doc/guide/index.xhtml">XHTML</a>,
+ <a href="http://www.codesynthesis.com/projects/cli/doc/guide/cli-guide.pdf">PDF</a>, and
+ <a href="http://www.codesynthesis.com/projects/cli/doc/guide/cli-guide.ps">PostScript</a>.</p>
+
+ </div>
+
+<h1>Table of Contents</h1>
+
+ <table class="toc">
+ <tr>
+ <th>1</th><td><a href="#1">Introduction</a></td>
+ </tr>
+
+ <tr>
+ <th>2</th><td><a href="#2">Hello World Example</a>
+ <table class="toc">
+ <tr><th>2.1</th><td><a href="#2.1">Defining Command Line Interface</a></td></tr>
+ <tr><th>2.2</th><td><a href="#2.2">Translating CLI Definitions to C++</a></td></tr>
+ <tr><th>2.3</th><td><a href="#2.3">Implementing Application Logic</a></td></tr>
+ <tr><th>2.4</th><td><a href="#2.4">Compiling and Running</a></td></tr>
+ <tr><th>2.5</th><td><a href="#2.5">Adding Documentation</a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>3</th><td><a href="#3">CLI Language</a>
+ <table class="toc">
+ <tr><th>3.1</th><td><a href="#3.1">Options Class Definition</a></td></tr>
+ <tr><th>3.2</th><td><a href="#3.2">Option Definition</a></td></tr>
+ <tr><th>3.3</th><td><a href="#3.3">Option Documentation</a></td></tr>
+ <tr><th>3.4</th><td><a href="#3.4">Include Directive</a></td></tr>
+ <tr><th>3.5</th><td><a href="#3.5">Namespace Definition</a></td></tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </div>
+
+ <!-- Introduction -->
+
+ <h1><a name="1">1 Introduction</a></h1>
+
+ <p>Command Line Interface (CLI) definition language is a domain-specific
+ language (DSL) for defining command line interfaces of C++ programs.
+ CLI definitions are automatically translated to C++ classes using the
+ CLI compiler. These classes implement parsing of the command
+ line arguments and provide a convenient and type-safe interface
+ for accessing the extracted data.</p>
+
+ <p>Beyond this guide, you may also find the following sources of
+ information useful:</p>
+
+ <ul class="list">
+ <li><a href="http://www.codesynthesis.com/projects/cli/doc/cli.xhtml">CLI
+ Compiler Command Line Manual</a></li>
+
+ <li>The <code>INSTALL</code> file in the CLI distribution provides build
+ instructions for various platforms.</li>
+
+ <li>The <code>examples/</code> directory in the CLI distribution contains
+ a collection of examples and a README file with an overview of each
+ example.</li>
+
+ <li>The <a href="http://www.codesynthesis.com/mailman/listinfo/cli-users">cli-users</a>
+ mailing list is the place to ask technical questions about the CLI language
+ and compiler. Furthermore, the
+ <a href="http://www.codesynthesis.com/pipermail/cli-users/">cli-users mailing
+ list archives</a> may already have answers to some of your questions.</li>
+ </ul>
+
+
+ <!-- Hello World Example -->
+
+
+ <h1><a name="2">2 Hello World Example</a></h1>
+
+ <p>In this chapter we will examine how to define a very simple command
+ line interface in CLI, translate this interface to C++, and use the
+ result in an application. The code presented in this chapter is based
+ on the <code>hello</code> example which can be found in the
+ <code>examples/hello/</code> directory of the CLI distribution.</p>
+
+ <h2><a name="2.1">2.1 Defining Command Line Interface</a></h2>
+
+ <p>Our <code>hello</code> application is going to print a greeting
+ line for each name supplied on the command line. It will also
+ support two command line options, <code>--greeting</code>
+ and <code>--exclamations</code>, that can be used to
+ customize the greeting line. The <code>--greeting</code>
+ option allows us to specify the greeting phrase instead of the
+ default <code>"Hello"</code>. The <code>--exclamations</code>
+ option is used to specify how many exclamation marks should
+ be printed at the end of each greeting. We will also support
+ the <code>--help</code> option which triggers printing of the
+ usage information.</p>
+
+ <p>We can now write a description of the above command line interface
+ in the CLI language and save it into <code>hello.cli</code>:</p>
+
+ <pre class="cli">
+include &lt;string>;
+
+class options
+{
+ bool --help;
+ std::string --greeting = "Hello";
+ unsigned int --exclamations = 1;
+};
+ </pre>
+
+ <p>While some details in the above code fragment might not be completely
+ clear (the CLI language is covered in greater detail in the next
+ chapter), it should be easy to connect declarations in
+ <code>hello.cli</code> to the command line interface described in
+ the preceding paragraphs. The next step is to translate this
+ interface specification to C++.</p>
+
+ <h2><a name="2.2">2.2 Translating CLI Definitions to C++</a></h2>
+
+ <p>Now we are ready to translate <code>hello.cli</code> to C++.
+ To do this we invoke the CLI compiler from a terminal (UNIX) or
+ a command prompt (Windows):
+ </p>
+
+ <pre class="term">
+$ cli hello.cli
+ </pre>
+
+ <p>This invocation of the CLI compiler produces three C++ files:
+ <code>hello.hxx</code> <code>hello.ixx</code>, and
+ <code>hello.cxx</code>. You can change the file name extensions
+ for these files with the compiler command line options. See the
+ <a href="http://www.codesynthesis.com/projects/cli/doc/cli.xhtml">CLI
+ Compiler Command Line Manual</a> for more information.</p>
+
+ <p>The following code fragment is taken from <code>hello.hxx</code>; it
+ should give you an idea about what gets generated:</p>
+
+ <pre class="cxx">
+#include &lt;string>
+
+class options
+{
+public:
+ options (int argc, char** argv);
+ options (int argc, char** argv, int&amp; end);
+
+ // Option accessors.
+ //
+public:
+ bool
+ help () const;
+
+ const std::string&amp;
+ greeting () const;
+
+ unsigned int
+ exclamations () const;
+
+private:
+ ..
+};
+ </pre>
+
+ <p>The <code>options</code> C++ class corresponds to the <code>options</code>
+ CLI class. For each option in this CLI class an accessor function is
+ generated inside the C++ class. The <code>options</code> C++ class also
+ defines a number of overloaded constructs that we can use to parse the
+ <code>argc/argv</code> array. Let's now see how we can use this generated
+ class to implement option parsing in our <code>hello</code> application.</p>
+
+ <h2><a name="2.3">2.3 Implementing Application Logic</a></h2>
+
+ <p>At this point we have everything we need to implement our
+ application:</p>
+
+ <pre class="cxx">
+#include &lt;iostream>
+#include "hello.hxx"
+
+using namespace std;
+
+void
+usage (ostream&amp; os)
+{
+ os &lt;&lt; "usage: driver [options] &lt;names>" &lt;&lt; endl
+ &lt;&lt; "options:" &lt;&lt; endl;
+ options::print_usage (os);
+}
+
+int
+main (int argc, char* argv[])
+{
+ try
+ {
+ int end; // End of options.
+ options o (argc, argv, end);
+
+ if (o.help ())
+ {
+ usage (cout);
+ return 0;
+ }
+
+ if (end == argc)
+ {
+ cerr &lt;&lt; "no names provided" &lt;&lt; endl;
+ usage (cerr);
+ return 1;
+ }
+
+ // Print the greetings.
+ //
+ for (int i = end; i &lt; argc; i++)
+ {
+ cout &lt;&lt; o.greeting () &lt;&lt; ", " &lt;&lt; argv[i];
+
+ for (unsigned int j = 0; j &lt; o.exclamations (); j++)
+ cout &lt;&lt; '!';
+
+ cout &lt;&lt; endl;
+ }
+ }
+ catch (const cli::exception&amp; e)
+ {
+ cerr &lt;&lt; e &lt;&lt; endl;
+ usage (cerr);
+ return 1;
+ }
+}
+</pre>
+
+ <p>At the beginning of our application we create the <code>options</code>
+ object which parses the command line. The <code>end</code> variable
+ contains the index of the first non-option argument. We then access
+ the option values as needed during the application execution. We also
+ catch and print <code>cli::exception</code> in case something goes
+ wrong, for example, an unknown option is specified or an option value
+ is invalid.
+ </p>
+
+ <h2><a name="2.4">2.4 Compiling and Running</a></h2>
+
+ <p>After saving our application from the previous section in
+ <code>driver.cxx</code>, we are ready to build and run our program.
+ On UNIX this can be done with the following commands:</p>
+
+ <pre class="term">
+$ c++ -o driver driver.cxx hello.cxx
+
+$ ./driver world
+Hello, world!
+
+$ ./driver --greeting Hi --exclamations 3 John Jane
+Hi, John!!!
+Hi, Jane!!!
+ </pre>
+
+ <p>We can also test the error handling:</p>
+
+ <pre class="term">
+$ ./driver -n 3 Jane
+unknown option '-n'
+usage: driver [options] &lt;names>
+options:
+--help
+--greeting &lt;arg>
+--exclamations &lt;arg>
+
+$ ./driver --exclamations abc Jane
+invalid value 'abc' for option '--exclamations'
+usage: driver [options] &lt;names>
+options:
+--help
+--greeting &lt;arg>
+--exclamations &lt;arg>
+ </pre>
+
+ <h2><a name="2.5">2.5 Adding Documentation</a></h2>
+
+ <p>As we have seen in the previous sections, the <code>options</code>
+ C++ class provides the <code>print_usage()</code> function which we
+ can use to display the application usage information. Right now this
+ information is very basic and does not include any description of
+ the purpose of each option:</p>
+
+ <pre class="term">
+$ ./driver --help
+usage: driver [options] &lt;names>
+options:
+--help
+--greeting &lt;arg>
+--exclamations &lt;arg>
+ </pre>
+
+ <p>To make the usage information more descriptive we can document each
+ option in the command line interface definition. This information can
+ also be used to automatically generate program documentation in various
+ formats, such as HTML and man page. For example:</p>
+
+ <pre class="cli">
+include &lt;string>;
+
+class options
+{
+ bool --help {"Print usage information and exit."};
+
+ std::string --greeting = "Hello"
+ {
+ "&lt;text>",
+ "Use &lt;text> as a greeting phrase instead of the default \"Hello\"."
+ };
+
+ unsigned int --exclamations = 1
+ {
+ "&lt;num>",
+ "Print &lt;num> exclamation marks instead of 1 by default."
+ };
+};
+ </pre>
+
+ <p>If we now save this updated command line interface to
+ <code>hello.cli</code> and recompile our application, the usage
+ information printed by the program will look like this:</p>
+
+ <pre class="term">
+usage: driver [options] &lt;names>
+options:
+--help Print usage information and exit.
+--greeting &lt;text> Use &lt;text> as a greeting phrase instead of the
+ default "Hello".
+--exclamations &lt;num> Print &lt;num> exclamation marks instead of 1 by
+ default.
+ </pre>
+
+ <p>We can also generate the program documentation in the HTML
+ (<code>--generate-html</code> CLI option) and man page
+ (<code>--generate-man</code> CLI option) formats. For example:</p>
+
+ <pre class="term">
+$ cli --generate-html hello.cli
+ </pre>
+
+ <p>The resulting <code>hello.html</code> file contains the following
+ documentation:</p>
+
+<dl class="options">
+ <dt><code><b>--help</b></code></dt>
+ <dd>Print usage information and exit.</dd>
+
+ <dt><code><b>--greeting</b></code> <i>text</i></dt>
+ <dd>Use <i>text</i> as a greeting phrase instead of the default "Hello".</dd>
+
+ <dt><code><b>--exclamations</b></code> <i>num</i></dt>
+ <dd>Print <i>num</i> exclamation marks instead of 1 by default.</dd>
+
+</dl>
+
+ <p>This HTML fragment can be combined with custom prologue and epilogue
+ to create a complete program documentation
+ (<code>--html-prologue/--html-epilogue</code> options for the HTML
+ output, <code>--man-prologue/--man-epilogue</code> options for the
+ man page output). For an example of such complete documentation see
+ the <a href="http://www.codesynthesis.com/projects/cli/doc/cli.xhtml">CLI
+ Compiler Command Line Manual</a> and the <code>cli(1)</code> man
+ page. For more information on the option documentation syntax,
+ see <a href="#3.3">Section 3.3, Option Documentation</a>.</p>
+
+ <!-- CLI Language -->
+
+
+ <h1><a name="3">3 CLI Language</a></h1>
+
+ <p>This chapter describes the CLI language and its mapping to C++.
+ A CLI file consists of zero or more <a href="#3.4">Include
+ Directives</a> followed by one or more <a href="#3.5">Namespace Definitions</a>
+ or <a href="#3.1">Option Class Definitions</a>. C and C++-style comments
+ can be used anywhere in the CLI file except in character and
+ string literals.</p>
+
+ <h2><a name="3.1">3.1 Option Class Definition</a></h2>
+
+<p>The central part of the CLI language is <em>option class</em>. An
+ option class contains one or more <em>option</em> definitions, for
+ example:</p>
+
+ <pre class="cli">
+class options
+{
+ bool --help;
+ int --compression;
+};
+ </pre>
+
+ <p>If we translate the above CLI fragment to C++, we will get a C++
+ class with the following interface:</p>
+
+ <pre class="cli">
+class options
+{
+public:
+ options (int&amp; argc,
+ char** argv,
+ bool erase = false,
+ cli::unknown_mode opt_mode = cli::unknown_mode::fail,
+ cli::unknown_mode arg_mode = cli::unknown_mode::stop);
+
+ options (int start,
+ int&amp; argc,
+ char** argv,
+ bool erase = false,
+ cli::unknown_mode opt_mode = cli::unknown_mode::fail,
+ cli::unknown_mode arg_mode = cli::unknown_mode::stop);
+
+ options (int&amp; argc,
+ char** argv,
+ int&amp; end,
+ bool erase = false,
+ cli::unknown_mode opt_mode = cli::unknown_mode::fail,
+ cli::unknown_mode arg_mode = cli::unknown_mode::stop);
+
+ options (int start,
+ int&amp; argc,
+ char** argv,
+ int&amp; end,
+ bool erase = false,
+ cli::unknown_mode opt_mode = cli::unknown_mode::fail,
+ cli::unknown_mode arg_mode = cli::unknown_mode::stop);
+
+ options (cli::scanner&amp;,
+ cli::unknown_mode opt_mode = cli::unknown_mode::fail,
+ cli::unknown_mode arg_mode = cli::unknown_mode::stop);
+
+ options (const options&amp;);
+
+ options&amp;
+ operator= (const options&amp;);
+
+public:
+ static void
+ print_usage (std::ostream&amp;);
+
+public:
+ bool
+ help () const;
+
+ int
+ compression () const;
+};
+ </pre>
+
+
+ <p>An option class is mapped to a C++ class with the same name. The
+ C++ class defines a set of public overloaded constructors, a public
+ copy constructor and an assignment operator, as well as a set of public
+ accessor functions and, if the <code>--generate-modifier</code> CLI
+ compiler option is specified, modifier functions corresponding to option
+ definitions. It also defines a public static <code>print_usage()</code>
+ function that can be used to print the usage information for the options
+ defined by the class.</p>
+
+ <p>The <code>argc/argv</code> arguments in the overloaded constructors
+ are used to pass the command line arguments array, normally as passed
+ to <code>main()</code>. The <code>start</code> argument is used to
+ specify the position in the arguments array from which the parsing
+ should start. The constructors that don't have this argument, start
+ from position 1, skipping the executable name in <code>argv[0]</code>.
+ The <code>end</code> argument is used to return the position in
+ the arguments array where the parsing of options stopped. This is the
+ position of the first program argument, if any. If the <code>erase</code>
+ argument is <code>true</code>, then the recognized options and their
+ values are removed from the <code>argv</code> array and the
+ <code>argc</code> count is updated accordingly.</p>
+
+ <p>The <code>opt_mode</code> and <code>arg_mode</code> arguments
+ specify the parser behavior when it encounters an unknown option
+ and argument, respectively. The <code>unknown_mode</code> type
+ is part of the generated CLI runtime support code. It has the
+ following interface:</p>
+
+ <pre class="cxx">
+namespace cli
+{
+ class unknown_mode
+ {
+ public:
+ enum value
+ {
+ skip,
+ stop,
+ fail
+ };
+
+ unknown_mode (value v);
+ operator value () const;
+ };
+}
+ </pre>
+
+ <p>If the mode is <code>skip</code>, the parser skips an unknown
+ option or argument and continue parsing. If the mode is
+ <code>stop</code>, the parser stops the parsing process. The
+ position of the unknown entity is stored in the <code>end</code>
+ argument. If the mode is <code>fail</code>, the parser throws the
+ <code>cli::unknown_option</code> or <code>cli::unknown_argument</code>
+ exception (described blow) on encountering an unknown option or argument,
+ respectively.</p>
+
+ <p>Instead of the <code>argc/argv</code> arguments, the last overloaded
+ constructor accepts the <code>cli::scanner</code> object. It is part
+ of the generated CLI runtime support code and has the following
+ abstract interface:</p>
+
+ <pre class="cxx">
+namespace cli
+{
+ class scanner
+ {
+ public:
+ virtual bool
+ more () = 0;
+
+ virtual const char*
+ peek () = 0;
+
+ virtual const char*
+ next () = 0;
+
+ virtual void
+ skip () = 0;
+ };
+}
+ </pre>
+
+ <p>The CLI runtime also provides two implementations of this interface:
+ <code>cli::argv_scanner</code> and <code>cli::argv_file_scanner</code>.
+ The first implementation is a simple scanner for the <code>argv</code>
+ array (it is used internally by all the other constructors) and has the
+ following interface:</p>
+
+ <pre class="cxx">
+namespace cli
+{
+ class argv_scanner
+ {
+ public:
+ argv_scanner (int&amp; argc, char** argv, bool erase = false);
+ argv_scanner (int start, int&amp; argc, char** argv, bool erase = false);
+
+ int
+ end () const;
+
+ ...
+ };
+}
+ </pre>
+
+ <p>The <code>cli::argv_file_scanner</code> implementation provides
+ support for reading command line arguments from the <code>argv</code>
+ array as well as files specified with command line options. It is
+ generated only if explicitly requested with the
+ <code>--generate-file-scanner</code> CLI compiler option and has
+ the following interface:</p>
+
+ <pre class="cxx">
+namespace cli
+{
+ class argv_file_scanner
+ {
+ public:
+ argv_file_scanner (int&amp; argc,
+ char** argv,
+ const std::string&amp; option,
+ bool erase = false);
+
+ argv_file_scanner (int start,
+ int&amp; argc,
+ char** argv,
+ const std::string&amp; option,
+ bool erase = false);
+
+ struct option_info
+ {
+ // If search_func is not NULL, it is called, with the arg
+ // value as the second argument, to locate the options file.
+ // If it returns an empty string, then the file is ignored.
+ //
+ const char* option;
+ std::string (*search_func) (const char*, void* arg);
+ void* arg;
+ };
+
+ argv_file_scanner (int&amp; argc,
+ char** argv,
+ const option_info* options,
+ std::size_t options_count,
+ bool erase = false);
+
+ argv_file_scanner (int start,
+ int&amp; argc,
+ char** argv,
+ const option_info* options,
+ std::size_t options_count,
+ bool erase = false);
+ ...
+ };
+}
+ </pre>
+
+ <p>The <code>option</code> argument in the first two constructors and
+ the <code>options</code> and <code>options_count</code> arguments
+ in the last two are used to pass the option name(s) that should be
+ recognized as specifying the file containing additional options.
+ Such a file contains a set of options, each appearing on a
+ separate line optionally followed by space and an option value. Empty lines
+ and lines starting with <code>#</code> are ignored. Option values can
+ be enclosed in double (<code>"</code>) or single (<code>'</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>'"x"'</code>. Non-leading and non-trailing quotes are interpreted
+ as being part of the option value.</p>
+
+ <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 options file is specified, except that the shell escaping
+ and quoting is not required. Multiple files can be specified by including
+ several file options on the command line or inside other files.</p>
+
+ <p>The parsing constructor (those with the <code>argc/argv</code> or
+ <code>cli::scanner</code> arguments) can throw the following exceptions: <code>cli::unknown_option</code>,
+ <code>cli::unknown_argument</code>, <code>cli::missing_value</code>, and
+ <code>cli::invalid_value</code>. The first two exceptions are thrown
+ on encountering unknown options and arguments, respectively, as
+ described above. The <code>missing_value</code> exception is thrown when
+ an option value is missing. The <code>invalid_value</code> exception is
+ thrown when an option value is invalid, for example, a non-integer value
+ is specified for an option of type <code>int</code>.</p>
+
+ <p>Furthermore, all scanners (and thus the parsing constructors that
+ call them) can throw the <code>cli::eos_reached</code> exception
+ which indicates that one of the <code>peek()</code>, <code>next()</code>,
+ or <code>skip()</code> functions were called while <code>more()</code>
+ returns <code>false</code>. Catching this exception normally indicates an
+ error in an option parser implementation. The <code>argv_file_scanner</code>
+ class can also throw the <code>cli::file_io_failure</code> exception
+ which indicates that a file could not be opened or there was a reading
+ error as well as the <code>cli::unmatched_quote</code> exception
+ which indicates that an unmatched leading or trailing quote was
+ found in an option value.</p>
+
+ <p>All CLI exceptions are derived from the common <code>cli::exception</code>
+ class which implements the polymorphic <code>std::ostream</code> insertion.
+ For example, if you catch the <code>cli::unknown_option</code>
+ exception as <code>cli::exception</code> and print it to
+ <code>std::cerr</code>, you will get the error message corresponding
+ to the <code>unknown_option</code> exception.</p>
+
+ <p>The exceptions described above are part of the generated CLI runtime
+ support code and have the following interfaces:</p>
+
+ <pre class="cxx">
+#include &lt;exception>
+
+namespace cli
+{
+ class exception: public std::exception
+ {
+ public:
+ virtual void
+ print (std::ostream&amp;) const = 0;
+ };
+
+ inline std::ostream&amp;
+ operator&lt;&lt; (std::ostream&amp; os, const exception&amp; e)
+ {
+ e.print (os);
+ return os;
+ }
+
+ class unknown_option: public exception
+ {
+ public:
+ unknown_option (const std::string&amp; option);
+
+ const std::string&amp;
+ option () const;
+
+ virtual void
+ print (std::ostream&amp;) const;
+
+ virtual const char*
+ what () const throw ();
+ };
+
+ class unknown_argument: public exception
+ {
+ public:
+ unknown_argument (const std::string&amp; argument);
+
+ const std::string&amp;
+ argument () const;
+
+ virtual void
+ print (std::ostream&amp;) const;
+
+ virtual const char*
+ what () const throw ();
+ };
+
+ class missing_value: public exception
+ {
+ public:
+ missing_value (const std::string&amp; option);
+
+ const std::string&amp;
+ option () const;
+
+ virtual void
+ print (std::ostream&amp;) const;
+
+ virtual const char*
+ what () const throw ();
+ };
+
+ class invalid_value: public exception
+ {
+ public:
+ invalid_value (const std::string&amp; option,
+ const std::string&amp; value);
+
+ const std::string&amp;
+ option () const;
+
+ const std::string&amp;
+ value () const;
+
+ virtual void
+ print (std::ostream&amp;) const;
+
+ virtual const char*
+ what () const throw ();
+ };
+
+ class eos_reached: public exception
+ {
+ public:
+ virtual void
+ print (std::ostream&amp;) const;
+
+ virtual const char*
+ what () const throw ();
+ };
+
+ class file_io_failure: public exception
+ {
+ public:
+ file_io_failure (const std::string&amp; file);
+
+ const std::string&amp;
+ file () const;
+
+ virtual void
+ print (std::ostream&amp;) const;
+
+ virtual const char*
+ what () const throw ();
+ };
+
+ class unmatched_quote: public exception
+ {
+ public:
+ unmatched_quote (const std::string&amp; argument);
+
+ const std::string&amp;
+ argument () const;
+
+ virtual void
+ print (std::ostream&amp;) const;
+
+ virtual const char*
+ what () const throw ();
+ };
+}
+ </pre>
+
+
+ <h2><a name="3.2">3.2 Option Definition</a></h2>
+
+<p>An option definition consists of four components: <em>type</em>,
+ <em>name</em>, <em>default value</em>, and <em>documentation</em>.
+ An option type can be any C++ type as long as its string representation
+ can be parsed using the <code>std::istream</code> interface. If the option
+ type is user-defined then you will need to include its declaration using
+ the <a href="#3.4">Include Directive</a>.</p>
+
+<p>An option of a type other than <code>bool</code> is expected to
+ have a value. An option of type <code>bool</code> is treated as
+ a flag and does not have a value. That is, a mere presence of such
+ an option on the command line sets this option's value to
+ <code>true</code>.</p>
+
+<p>The name component specifies the option name as it will be entered
+ in the command line. A name can contain any number of aliases separated
+ by <code>|</code>. The C++ accessor and modifier function names are
+ derived from the first name by removing any leading special characters,
+ such as <code>-</code>, <code>/</code>, etc., and replacing special
+ characters in other places with underscores. For example, the following
+ option definition:</p>
+
+ <pre class="cli">
+class options
+{
+ int --compression-level | --comp | -c;
+};
+ </pre>
+
+ <p>Will result in the following accessor function:</p>
+
+ <pre class="cli">
+class options
+{
+ int
+ compression_level () const;
+};
+ </pre>
+
+ <p>While any option alias can be used on the command line to specify
+ this option's value.</p>
+
+ <p>If the option name conflicts with one of the CLI language keywords,
+ it can be specified as a string literal:</p>
+
+ <pre class="cli">
+class options
+{
+ bool "int";
+};
+ </pre>
+
+ <p>The following component of the option definition is the optional default
+ value. If the default value is not specified, then the option is
+ initialized with the default constructor. In particular, this means
+ that a <code>bool</code> option will be initialized to <code>false</code>,
+ an <code>int</code> option will be initialized to <code>0</code>, etc.</p>
+
+ <p>Similar to C++ variable initialization, the default option value
+ can be specified using two syntactic forms: an assignment initialization
+ and constructor initialization. The two forms are equivalent except
+ that the constructor initialization can be used with multiple arguments,
+ for example:</p>
+
+ <pre class="cli">
+include &lt;string>;
+
+class options
+{
+ int -i1 = 5;
+ int -i2 (5);
+
+ std::string -s1 = "John";
+ std::string -s2 ("Mr John Doe", 8, 3);
+};
+ </pre>
+
+ <p>The assignment initialization supports character, string, boolean, and
+ simple integer literals (including negative integers) as well
+ as identifiers. For more complex expressions use the constructor
+ initialization or wrap the expressions in parenthesis, for example:</p>
+
+ <pre class="cli">
+include "constants.hxx"; // Defines default_value.
+
+class options
+{
+ int -a = default_value;
+ int -b (25 * 4);
+ int -c = (25 / default_value + 3);
+};
+ </pre>
+
+ <p>By default, when an option is specified two or more times on the command
+ line, the last value overrides all the previous ones. However, a number
+ of standard C++ containers are handled differently to allow collecting
+ multiple option values or building key-value maps. These
+ containers are <code>std::vector</code>, <code>std::set</code>, and
+ <code>std::map</code>.</p>
+
+ <p>When <code>std::vector</code> or <code>std::set</code> is specified
+ as an option type, all the values for this option are inserted into the
+ container in the order they are encountered. As a result,
+ <code>std::vector</code> will contain all the values, including
+ duplicates while <code>std::set</code> will contain all the unique
+ values. For example:</p>
+
+ <pre class="cli">
+include &lt;set>;
+include &lt;vector>;
+
+class options
+{
+ std::vector&lt;int> --vector | -v;
+ std::set&lt;int> --set | -s;
+};
+ </pre>
+
+ <p>If we have a command line like this:
+ <code>-v 1 -v 2 -v 1 -s 1 -s 2 -s 1</code>, then the vector returned
+ by the <code>vector()</code> accessor function will contain three
+ elements: <code>1</code>, <code>2</code>, and <code>1</code> while
+ the set returned by the <code>set()</code> accessor will contain
+ two elements: <code>1</code> and <code>2</code>.</p>
+
+ <p>When <code>std::map</code> is specified as an option type, the option
+ value is expected to have two parts: the key and the value, separated
+ by <code>=</code>. All the option values are then parsed into key/value
+ pairs and inserted into the map. For example:</p>
+
+ <pre class="cli">
+include &lt;map>;
+include &lt;string>;
+
+class options
+{
+ std::map&lt;std::string, std::string> --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
+ 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.
+ It is discussed in the next section.</p>
+
+ <h2><a name="3.3">3.3 Option Documentation</a></h2>
+
+ <p>Option documentation mimics C++ string array initialization:
+ it is enclosed in <code>{}</code> and consists of one or more
+ documentation strings separated by a comma, for example:</p>
+
+ <pre class="cli">
+class options
+{
+ int --compression = 5
+ {
+ "&lt;level>",
+ "Set compression to &lt;level> instead of 5 by default.
+
+ With the higher compression levels the program may produce a
+ smaller output but may also take longer and use more memory."
+ };
+};
+ </pre>
+
+ <p>The option documentation consists of a maximum of three documentation
+ strings. The first string is the value documentation string.
+ It describes the option value and is only applicable to options
+ with types other than <code>bool</code> (options of type
+ <code>bool</code> are flags and don't have an explicit value).
+ The second string (or the first string for options of type
+ <code>bool</code>) is the short documentation string. It
+ provides a brief description of the option. The last entry
+ in the option documentation is the long documentation string.
+ It provides a detailed description of the option. The short
+ documentation string is optional. If only two strings are
+ present in the option documentation (one string for options
+ of type <code>bool</code>), then the second (first) string is
+ assumed to be the long documentation string.</p>
+
+ <p>Option documentation is used to print the usage information
+ as well as to generate program documentation in the HTML and
+ man page formats. For usage information the short documentation
+ string is used if provided. If only the long string is available,
+ then, by default, only the first sentence from the long string
+ is used. You can override this behavior and include the complete
+ long string in the usage information by specifying the
+ <code>--long-usage</code> CLI compiler option. When generating
+ the program documentation, the long documentation strings are
+ always used.</p>
+
+ <p>The value documentation string can contain text enclosed in
+ <code>&lt;></code> which is automatically recognized by the CLI
+ compiler and typeset according to the selected output in all three
+ documentation strings. For example, in usage the <code>level</code>
+ value for the <code>--compression</code> option presented above
+ will be displayed as <code>&lt;level></code> while in the HTML and
+ man page output it will be typeset in italic as
+ <code><i>level</i></code>. Here is another example using the
+ <code>std::map</code> type:</p>
+
+ <pre class="cli">
+include &lt;map>;
+include &lt;string>;
+
+class options
+{
+ std::map&lt;std::string, std::string> --map
+ {
+ "&lt;key>=&lt;value>",
+ "Add the &lt;key>, &lt;value> pair to the map."
+ };
+};
+ </pre>
+
+ <p>The resulting HTML output for this option would look like this:</p>
+
+<dl class="options">
+ <dt><code><b>--map</b></code> <i>key</i>=<i>value</i></dt>
+ <dd>Add the <i>key</i>, <i>value</i> pair to the map.</dd>
+</dl>
+
+ <p>As you might have noticed from the examples presented so far, the
+ documentation strings can span multiple lines which is not possible
+ in C++. Also, all three documentation strings support the following
+ basic formatting mechanisms. The start of a new paragraph is indicated
+ by a blank line. A fragment of text can be typeset in monospace font
+ (normally used for code fragments) by enclosing it in the
+ <code>\c{}</code> block. Similarly, text can be typeset in bold or
+ italic fonts using the <code>\b{}</code> and <code>\i{}</code> blocks,
+ respectively. You can also combine several font properties in a single
+ block, for example, <code>\cb{bold code}</code>. If you need to include
+ literal <code>}</code> in a formatting block, you can use the
+ <code>\}</code> escape sequence, for example,
+ <code>\c{int a[] = {1, 2\}}</code>. The following example shows how we
+ can use these mechanisms:</p>
+
+ <pre class="cli">
+class options
+{
+ int --compression = 5
+ {
+ "&lt;level>",
+ "Set compression to &lt;level> instead of 5 by default.
+
+ With the higher compression levels the program \i{may}
+ produce a smaller output but may also \b{take longer}
+ and \b{use more memory}."
+ };
+};
+ </pre>
+
+ <p>The resulting HTML output for this option would look like this:</p>
+
+<dl class="options">
+ <dt><code><b>--compression</b></code> <i>level</i></dt>
+ <dd>Set compression to <i>level</i> instead of 5 by default.
+
+ <p>With the higher compression levels the program <i>may</i> produce a
+ smaller output but may also <b>take longer</b> and <b>use more memory</b>.</p></dd>
+</dl>
+
+ <h2><a name="3.4">3.4 Include Directive</a></h2>
+
+ <p>If you are using user-defined types in your option definitions,
+ you will need to include their declarations with the include
+ directive. Include directives can use <code>&lt; ></code> or
+ <code>" "</code>-enclosed paths. The CLI compiler does not
+ actually open or read these files. Instead, the include directives
+ are translated to C++ preprocessor <code>#include</code> directives
+ in the generated C++ header file. For example, the following CLI
+ definition:</p>
+
+ <pre class="cli">
+include &lt;string>;
+include "types.hxx"; // Defines the name_type class.
+
+class options
+{
+ std::string --string;
+ name_type --name;
+};
+ </pre>
+
+ <p>Will result in the following C++ header file:</p>
+
+ <pre class="cli">
+#include &lt;string>
+#include "types.hxx"
+
+class options
+{
+ ...
+
+ const std::string&amp;
+ string () const;
+
+ const name_type&amp;
+ name () const;
+
+ ...
+};
+ </pre>
+
+ <p>Without the <code>#include</code> directives the <code>std::string</code>
+ and <code>name_type</code> types in the <code>options</code> class would
+ be undeclared and result in compilation errors.</p>
+
+ <h2><a name="3.5">3.5 Namespace Definition</a></h2>
+
+ <p>Option classes can be placed into namespaces which are translated
+ directly to C++ namespaces. For example:</p>
+
+ <pre class="cli">
+namespace compiler
+{
+ namespace lexer
+ {
+ class options
+ {
+ int --warning-level = 0;
+ };
+ }
+
+ namespace parser
+ {
+ class options
+ {
+ int --warning-level = 0;
+ };
+ }
+
+ namespace generator
+ {
+ class options
+ {
+ int --target-width = 32;
+ };
+ }
+}
+ </pre>
+
+ <p>The above CLI namespace structure would result in the equivalent C++
+ namespaces structure:</p>
+
+ <pre class="cxx">
+namespace compiler
+{
+ namespace lexer
+ {
+ class options
+ {
+ int
+ warning_level () const;
+ };
+ }
+
+ namespace parser
+ {
+ class options
+ {
+ int
+ warning_level () const;
+ };
+ }
+
+ namespace generator
+ {
+ class options
+ {
+ int
+ target_width () const;
+ };
+ }
+}
+ </pre>
+
+
+ </div>
+</div>
+
+
+</body>
+</html>
diff --git a/cli/doc/language.txt b/cli/doc/language.txt
new file mode 100644
index 0000000..e6c9161
--- /dev/null
+++ b/cli/doc/language.txt
@@ -0,0 +1,128 @@
+Token types:
+ keyword
+ identifier
+ punctuation (";" "{" "}" "(" ")" "," "|" "=" ":")
+ cxx-path-literal ("c++:path", <c++:path>, "path", <path>)
+ cli-path-literal ("cli:path", <cli:path>, "path.cli", <path.cli>)
+ char-literal
+ string-literal
+ bool-literal
+ int-literal
+ float-literal
+ call-expr (e.g., (a, 2))
+ template-expr (e.g., <a, 2>)
+ end-of-stream
+
+def-unit:
+ include-decl-seq(opt) decl-seq(opt)
+
+include-decl-seq:
+ source-decl
+ include-decl
+ include-decl-seq include-decl
+
+source-decl:
+ "source" cli-path-literal ";"
+
+include-decl:
+ "include" include-path ";"
+
+include-path:
+ cxx-path-literal
+ cli-path-literal
+
+decl-seq:
+ decl
+ decl-seq decl
+
+decl:
+ source-decl
+ scope-doc
+ namespace-def
+ class-def
+
+scope-doc:
+ string-literal
+ "{" doc-string-seq "}"
+
+namespace-def:
+ "namespace" identifier "{" namespace-body "}"
+
+namespace-body:
+ decl-seq(opt)
+
+class-def:
+ "class" identifier inheritance-spec(opt) abstract-spec(opt) "{" class-decl-seq(opt) "};"
+
+inheritance-spec:
+ ":" base-seq
+
+base-seq:
+ qualified-name
+ base-seq "," qualified-name
+
+abstract-spec:
+ "=" "0"
+
+class-decl-seq:
+ class-decl
+ class-decl-seq class-decl
+
+class-decl
+ scope-doc
+ option-def
+
+option-def:
+ type-spec option-name-seq initializer(opt) option-def-trailer
+
+type-spec:
+ fundamental-type-spec
+ qualified-name
+
+option-name-seq:
+ option-name
+ option-name-seq "|" option-name
+
+option-name:
+ option-identifier
+ string-literal
+
+initializer:
+ "=" initializer-expr
+ call-expr
+
+initializer-expr:
+ bool-literal
+ int-literal
+ float-literal
+ char-literal
+ string-literal
+ qualified-name
+ call-expr
+
+option-def-trailer:
+ ";"
+ option-doc
+
+option-doc:
+ "{" doc-string-seq "}"
+
+doc-string-seq:
+ string-literal
+ doc-string-seq "," string-literal
+
+qualified-name:
+ "::" qualified-name-trailer
+ qualified-name-trailer
+
+qualified-name-trailer:
+ template-id
+ qualified-name "::" template-id
+
+template-id:
+ identifier template-expr(opt)
+
+fundamental-type-spec:
+ "bool"
+ ...
+ "long double"
diff --git a/cli/manifest b/cli/manifest
new file mode 100644
index 0000000..69c113b
--- /dev/null
+++ b/cli/manifest
@@ -0,0 +1,21 @@
+: 1
+name: cli
+version: 1.2.0-b.6.z
+summary: Command line interface (CLI) compiler for C++
+license: MIT
+topics: C++, command line interface, source code generation, \
+ documentation generation
+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
+email: cli-users@codesynthesis.com ; Mailing list
+build-email: builds@codesynthesis.com
+builds: all
+requires: c++14
+depends: * build2 >= 0.13.0-
+depends: * bpkg >= 0.13.0-
+depends: libcutl ^1.11.0-
+tests: cli-tests == $
+examples: cli-examples == $