From 2181ec73117f2e18cc622ead6256c8104b631214 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Sat, 6 Jun 2020 22:42:16 +0300 Subject: Use ad hoc recipe for parsing code and documentation generating The overall approach is to store pre-generated bootstrap options.?xx and cli.{1,xhtml} and automatically update them in the development build (config.cli.develop=true). See README.md in the root of the repository for details. --- cli/doc/.gitignore | 7 +- cli/doc/bootstrap/cli.1 | 416 ++++++++++++++ cli/doc/bootstrap/cli.xhtml | 573 +++++++++++++++++++ cli/doc/buildfile | 117 +++- cli/doc/cli-guide.xhtml | 1336 +++++++++++++++++++++++++++++++++++++++++++ cli/doc/cli-prologue.1 | 2 +- cli/doc/cli-prologue.xhtml | 2 +- cli/doc/doc.sh | 78 --- cli/doc/guide.html2ps | 63 ++ cli/doc/guide/.gitignore | 2 - cli/doc/guide/guide.html2ps | 63 -- cli/doc/guide/index.xhtml | 1336 ------------------------------------------- 12 files changed, 2504 insertions(+), 1491 deletions(-) create mode 100644 cli/doc/bootstrap/cli.1 create mode 100644 cli/doc/bootstrap/cli.xhtml create mode 100644 cli/doc/cli-guide.xhtml delete mode 100755 cli/doc/doc.sh create mode 100644 cli/doc/guide.html2ps delete mode 100644 cli/doc/guide/.gitignore delete mode 100644 cli/doc/guide/guide.html2ps delete mode 100644 cli/doc/guide/index.xhtml (limited to 'cli/doc') diff --git a/cli/doc/.gitignore b/cli/doc/.gitignore index 562ecbd..93bbd2d 100644 --- a/cli/doc/.gitignore +++ b/cli/doc/.gitignore @@ -1,2 +1,5 @@ -cli.xhtml -cli.1 +*.ps +*.pdf + +/cli.xhtml +/cli.1 diff --git a/cli/doc/bootstrap/cli.1 b/cli/doc/bootstrap/cli.1 new file mode 100644 index 0000000..dae4474 --- /dev/null +++ b/cli/doc/bootstrap/cli.1 @@ -0,0 +1,416 @@ +.\" Process this file with +.\" groff -man -Tascii cli.1 +.\" +.TH CLI 1 "January 2021" "CLI 1.2.0-b.7" +.SH NAME +cli \- command line interface compiler for C++ +.\" +.\" +.\" +.\"-------------------------------------------------------------------- +.SH SYNOPSIS +.\"-------------------------------------------------------------------- +.B cli +.B [ +.I options +.B ] +.I file +.\" +.\" +.\" +.\"-------------------------------------------------------------------- +.SH DESCRIPTION +.\"-------------------------------------------------------------------- +.B cli +generates C++ implementation and documentation in various formats for a +command line interface defined in the CLI language. For an input file in +the form +.B name.cli +the following is generated. By default or if the +.B --generate-cxx +option is specified, the following C++ files are generated: +.B name.hxx +(header file), +.B name.ixx +(inline file, generated unless the +.B --suppress-inline +option is specified), and +.B name.cxx (source file). +If the +.B --generate-html +option is specified, then the +.B name.html +HTML documentation file is generated. If the +.B --generate-man +option is specified, then the +.B name.1 +man page file is generated. When +.B --generate-html +or +.B --generate-man +is specified, the +.B --stdout +option can be used to redirect the output to STDOUT instead of a file. +.\" +.\" +.\" +.\"-------------------------------------------------------------------- +.SH OPTIONS +.\"-------------------------------------------------------------------- +.IP "\fB--help\fR" +Print usage information and exit\. +.IP "\fB--version\fR" +Print version and exit\. +.IP "\fB--include-path\fR|\fB-I\fR \fIdir\fR" +Search \fIdir\fR for bracket-included (\fB<>\fR) options files\. +.IP "\fB--output-dir\fR|\fB-o\fR \fIdir\fR" +Write the generated files to \fIdir\fR instead of the current directory\. +.IP "\fB--std\fR \fIversion\fR" +Specify the C++ standard that should be used during compilation\. Valid values +are \fBc++98\fR (default), \fBc++11\fR, and \fBc++14\fR\. +.IP "\fB--generate-modifier\fR" +Generate option value modifiers in addition to accessors\. +.IP "\fB--generate-specifier\fR" +Generate functions for determining whether the option was specified on the +command line\. +.IP "\fB--generate-parse\fR" +Generate \fBparse()\fR functions instead of parsing constructors\. This is +primarily useful for being able to parse into an already initialized options +class instance, for example, to implement option appending/overriding\. +.IP "\fB--generate-merge\fR" +Generate \fBmerge()\fR functions\. This is primarily useful for being able to +merge several already parsed options class instances, for example, to +implement option appending/overriding\. Note that this option forces +\fB--generate-specifier\fR\. +.IP "\fB--generate-description\fR" +Generate the option description list that can be examined at runtime\. +.IP "\fB--generate-file-scanner\fR" +Generate the \fBargv_file_scanner\fR implementation\. This scanner is capable +of reading command line arguments from the \fBargv\fR array as well as files +specified with command line options\. +.IP "\fB--generate-vector-scanner\fR" +Generate the \fBvector_scanner\fR implementation\. This scanner is capable of +reading command line arguments from \fBvector\fR\. +.IP "\fB--generate-group-scanner\fR" +Generate the \fBgroup_scanner\fR implementation\. This scanner supports +grouping of arguments (usually options) to apply only to a certain argument\. + +Groups can be specified before (leading) and/or after (trailing) the argument +they apply to\. A leading group starts with '\fB{\fR' and ends with '\fB}+\fR' +while a trailing group starts with '\fB+{\fR' and ends with '\fB}\fR'\. For +example: + +.nf +{ --foo --bar }+ arg # 'arg' with '--foo' '--bar' +arg +{ fox=1 baz=2 } # 'arg' with 'fox=1' 'baz=2' +.fi + +Multiple leading and/or trailing groups can be specified for the same +argument\. For example: + +.nf +{ -f }+ { -b }+ arg +{ f=1 } +{ b=2 } # 'arg' with '-f' 'b' 'f=1' 'b=2' +.fi + +The group applies to a single argument only unless multiple arguments are +themselves grouped with '\fB{\fR' and '\fB}\fR'\. For example: + +.nf +{ --foo }+ arg1 arg2 +{ --bar } # 'arg1' with '--foo' + # 'arg2' with '--bar' + +{ --foo }+ { arg1 arg2 } +{ --bar } # 'arg1' with '--foo' '--bar' + # 'arg2' with '--foo' '--bar' +.fi + +The group separators ('\fB{\fR', '\fB}+'\fR, etc) must be separate command +line arguments\. In particular, they must not be adjacent either to the +arguments inside the group nor to the argument they apply to\. All such cases +will be treated as ordinary arguments\. For example: + +.nf +{--foo}+ arg # '{--foo}+' \.\.\. +arg+{ --foo } # 'arg+{' \.\.\. +.fi + +If one of the group separators needs to be specified as an argument verbatim, +then it must be escaped with '\fB\e\fR'\. For example: + +.nf +} # error: unexpected group separator +}x # '}x' +\\} # '}' +{ \\}+ }+ arg # 'arg' with '}+' +.fi +.IP "\fB--suppress-inline\fR" +Generate all functions non-inline\. By default simple functions are made +inline\. This option suppresses creation of the inline file\. +.IP "\fB--suppress-cli\fR" +Do not generate the CLI support types (scanners, parser, etc)\. Normally, the +support types are generated unless another \fB\.cli\fR was included, in which +case the support types are expected to be provided by its generated code\. +.IP "\fB--cli-namespace\fR \fIns\fR" +Generate the CLI support types in the \fIns\fR namespace (\fBcli\fR by +default)\. The namespace can be nested, for example \fBdetails::cli\fR\. If +the namespace is empty, then the support types are generated in the global +namespace\. +.IP "\fB--ostream-type\fR \fItype\fR" +Output stream type instead of the default \fBstd::ostream\fR that should be +used to print usage and exception information\. +.IP "\fB--generate-cxx\fR" +Generate C++ code\. If neither \fB--generate-man\fR, \fB--generate-html\fR, +nor \fB--generate-txt\fR is specified, this mode is assumed by default\. +.IP "\fB--generate-man\fR" +Generate documentation in the man page format\. +.IP "\fB--generate-html\fR" +Generate documentation in the HTML format\. +.IP "\fB--generate-txt\fR" +Generate documentation in the plain text format, similar to usage\. +.IP "\fB--stdout\fR" +Write output to STDOUT instead of a file\. This option is not valid when +generating C++ code and is normally used to combine generated documentation +for several option classes in a single file\. +.IP "\fB--suppress-undocumented\fR" +Suppress the generation of documentation entries for undocumented options\. +.IP "\fB--suppress-usage\fR" +Suppress the generation of the usage printing code\. +.IP "\fB--long-usage\fR" +If no short documentation string is provided, use the complete long +documentation string in usage\. By default, in this situation only the first +sentence from the long string is used\. +.IP "\fB--short-usage\fR" +If specified together with \fB--long-usage\fR, generate both short and long +usage versions\. In this mode, the long usage printing function is called +\fBprint_long_usage()\fR and in its implementation the long documentation +string is always used, even if the short version is provided\. +.IP "\fB--page-usage\fR \fIname\fR" +Generate the combined usage printing code for the entire page\. Specifically, +this will include all the namespace-level documentation as well as usage for +all the options classes printed in the order they are defined in the main +translation unit (documentation/classes from included units are ignored except +for base classes)\. + +The \fIname\fR argument is used as a prefix to form the name of the usage +printing function\. It can include the namespace qualification as well as +documentation variable expansion, for example: + +.nf +--page-usage print_ # print_usage() in global namespace +--page-usage app::print_ # print_usage() in app namespace +--page-usage print_$name$_ # print_foo_usage() if name is foo +.fi + +If both \fB--long-usage\fR and \fB--short-usage\fR options are specified, then +the long usage function has the \fB*long_usage()\fR suffix\. +.IP "\fB--option-length\fR \fIlen\fR" +Indent option descriptions \fIlen\fR characters when printing usage\. This is +useful when you have multiple options classes, potentially in separate files, +and would like their usage to have the same indentation level\. +.IP "\fB--ansi-color\fR" +Use ANSI color escape sequences when printing usage\. By "color" we really +only mean the bold and underline modifiers\. Note that Windows console does +not recognize ANSI escape sequences and will display them as garbage\. +However, if you pipe such output through \fBless(1)\fR, it will display them +correctly\. +.IP "\fB--exclude-base\fR" +Exclude base class information from usage and documentation\. +.IP "\fB--include-base-last\fR" +Include base class information after derived for usage and documentation\. By +default, base classes are included first\. +.IP "\fB--class-doc\fR \fIname\fR=\fIkind\fR" +Specify the documentation \fIkind\fR that should be used for the options class +\fIname\fR\. The \fIname\fR value should be a fully-qualified class name, for +example, \fBapp::options\fR\. The \fIkind\fR value can be \fBshort\fR, +\fBlong\fR, \fBexclude\fR, or \fBexclude-base\fR\. If the value is +\fBexclude\fR, then the class documentation is excluded from usage and +man/HTML/text output\. If it is \fBexclude-base\fR, then it is only excluded +when used as a base\. For usage, the \fBshort\fR and \fBlong\fR values +determine which usage function will be called when the class is used as base +or as part of the page usage (see \fB--page-usage\fR)\. For man/HTML/text, +these values determine which documentation strings are used in the output\. +.IP "\fB--class\fR \fIname\fR" +Generate the man page, HTML, or text documentation only for the options class +\fIname\fR\. The \fIname\fR value should be a fully-qualified options class +name, for example, \fBapp::options\fR\. To generate documentation for multiple +classes, repeat this option and the documentation will be produced in the +order specified\. This functionality is useful if you need to assemble +documentation from multiple classes in a specific order or to insert custom +documentation between options belonging to different classes\. +.IP "\fB--docvar\fR|\fB-v\fR \fIname\fR=\fIval\fR" +Set documentation variable \fIname\fR to the value \fIval\fR\. Documentation +variables can be substituted in prologues and epilogues (see +\fB--*-prologue*\fR and \fB--*-epilogue*\fR options) using the +\fB$\fR\fIname\fR\fB$\fR expansion syntax (use \fB$$\fR to escape expansion)\. +They can also be defined in \fB\.cli\fR files using the +\&"\e\fIname\fR=\fIval\fR"\fR syntax\. +.IP "\fB--link-regex\fR \fIregex\fR" +Add \fIregex\fR to the list of regular expressions used to transform link +targets in the generated documentation\. The argument to this option is a +Perl-like regular expression in the form +\fB/\fR\fIpattern\fR\fB/\fR\fIreplacement\fR\fB/\fR\fR\. Any character can be +used as a delimiter instead of '\fB/\fR' and the delimiter can be escaped +inside \fIpattern\fR and \fIreplacement\fR with a backslash (\fB\e\fR)\. You +can specify multiple regular expressions by repeating this option\. All the +regular expressions are tried in the order specified and the first expression +that matches is used\. Use the \fB--link-regex-trace\fR option to debug link +transformation\. +.IP "\fB--link-regex-trace\fR" +Trace the process of applying regular expressions specified with the +\fB--link-regex\fR option\. Use this option to find out why your regular +expressions don't do what you expected them to do\. +.IP "\fB--html-heading-map\fR \fIc\fR=\fIh\fR" +Map CLI heading \fIc\fR (valid values: '\fBH\fR', '\fB0\fR', '\fB1\fR', +\&'\fBh\fR', and '\fB2\fR') to HTML heading \fIh\fR (for example, '\fBh1\fR', +\&'\fBh2\fR', etc)\. +.IP "\fB--omit-link-check\fR" +Don't check that local fragment link references (\el{#ref \.\.\.}) resolve to +ids\. +.IP "\fB--hxx-prologue\fR \fItext\fR" +Insert \fItext\fR at the beginning of the generated C++ header file\. +.IP "\fB--ixx-prologue\fR \fItext\fR" +Insert \fItext\fR at the beginning of the generated C++ inline file\. +.IP "\fB--cxx-prologue\fR \fItext\fR" +Insert \fItext\fR at the beginning of the generated C++ source file\. +.IP "\fB--man-prologue\fR \fItext\fR" +Insert \fItext\fR at the beginning of the generated man page file\. +.IP "\fB--html-prologue\fR \fItext\fR" +Insert \fItext\fR at the beginning of the generated HTML file\. +.IP "\fB--txt-prologue\fR \fItext\fR" +Insert \fItext\fR at the beginning of the generated text file\. +.IP "\fB--hxx-epilogue\fR \fItext\fR" +Insert \fItext\fR at the end of the generated C++ header file\. +.IP "\fB--ixx-epilogue\fR \fItext\fR" +Insert \fItext\fR at the end of the generated C++ inline file\. +.IP "\fB--cxx-epilogue\fR \fItext\fR" +Insert \fItext\fR at the end of the generated C++ source file\. +.IP "\fB--man-epilogue\fR \fItext\fR" +Insert \fItext\fR at the end of the generated man page file\. +.IP "\fB--html-epilogue\fR \fItext\fR" +Insert \fItext\fR at the end of the generated HTML file\. +.IP "\fB--txt-epilogue\fR \fItext\fR" +Insert \fItext\fR at the end of the generated text file\. +.IP "\fB--hxx-prologue-file\fR \fIfile\fR" +Insert the content of \fIfile\fR at the beginning of the generated C++ header +file\. +.IP "\fB--ixx-prologue-file\fR \fIfile\fR" +Insert the content of \fIfile\fR at the beginning of the generated C++ inline +file\. +.IP "\fB--cxx-prologue-file\fR \fIfile\fR" +Insert the content of \fIfile\fR at the beginning of the generated C++ source +file\. +.IP "\fB--man-prologue-file\fR \fIfile\fR" +Insert the content of \fIfile\fR at the beginning of the generated man page +file\. +.IP "\fB--html-prologue-file\fR \fIfile\fR" +Insert the content of \fIfile\fR at the beginning of the generated HTML file\. +.IP "\fB--txt-prologue-file\fR \fIfile\fR" +Insert the content of \fIfile\fR at the beginning of the generated text file\. +.IP "\fB--hxx-epilogue-file\fR \fIfile\fR" +Insert the content of \fIfile\fR at the end of the generated C++ header file\. +.IP "\fB--ixx-epilogue-file\fR \fIfile\fR" +Insert the content of \fIfile\fR at the end of the generated C++ inline file\. +.IP "\fB--cxx-epilogue-file\fR \fIfile\fR" +Insert the content of \fIfile\fR at the end of the generated C++ source file\. +.IP "\fB--man-epilogue-file\fR \fIfile\fR" +Insert the content of \fIfile\fR at the end of the generated man page file\. +.IP "\fB--html-epilogue-file\fR \fIfile\fR" +Insert the content of \fIfile\fR at the end of the generated HTML file\. +.IP "\fB--txt-epilogue-file\fR \fIfile\fR" +Insert the content of \fIfile\fR at the end of the generated text file\. +.IP "\fB--output-prefix\fR \fIprefix\fR" +Add \fIprefix\fR at the beginning of the generated output file name(s)\. +.IP "\fB--output-suffix\fR \fIsuffix\fR" +Add \fIsuffix\fR at the end of the generated output file name(s)\. Note that +it is added before any file type-specific suffixes; see \fB--*-suffix\fR +below\. +.IP "\fB--hxx-suffix\fR \fIsuffix\fR" +Use \fIsuffix\fR instead of the default \fB\.hxx\fR to construct the name of +the generated header file\. +.IP "\fB--ixx-suffix\fR \fIsuffix\fR" +Use \fIsuffix\fR instead of the default \fB\.ixx\fR to construct the name of +the generated inline file\. +.IP "\fB--cxx-suffix\fR \fIsuffix\fR" +Use \fIsuffix\fR instead of the default \fB\.cxx\fR to construct the name of +the generated source file\. +.IP "\fB--man-suffix\fR \fIsuffix\fR" +Use \fIsuffix\fR instead of the default \fB\.1\fR to construct the name of the +generated man page file\. +.IP "\fB--html-suffix\fR \fIsuffix\fR" +Use \fIsuffix\fR instead of the default \fB\.html\fR to construct the name of +the generated HTML file\. +.IP "\fB--txt-suffix\fR \fIsuffix\fR" +Use \fIsuffix\fR instead of the default \fB\.txt\fR to construct the name of +the generated text file\. +.IP "\fB--option-prefix\fR \fIprefix\fR" +Use \fIprefix\fR instead of the default '\fB-\fR' as an option prefix\. +Unknown command line arguments that start with this prefix are treated as +unknown options\. If you set the option prefix to the empty value, then all +the unknown command line arguments will be treated as program arguments\. +.IP "\fB--option-separator\fR \fIsep\fR" +Use \fIsep\fR instead of the default '\fB--\fR' as an optional separator +between options and arguments\. All the command line arguments that are parsed +after this separator are treated as program arguments\. Set the option +separator to the empty value if you don't want this functionality\. +.IP "\fB--keep-separator\fR" +Leave the option separator in the scanner\. This is primarily useful for +incremental option parsing\. +.IP "\fB--no-combined-flags\fR" +Disable support for combining multiple single-character flags into a single +argument (the \fB-xyz\fR form that is equivalent to \fB-x\fR \fB-y\fR +\fB-z\fR)\. An argument is considered a combination of flags if it starts with +a single option prefix (\fB--option-prefix\fR) and only contains letters and +digits\. Note that an option with a value may not be part of such a +combination, not even if it is specified last\. +.IP "\fB--no-combined-values\fR" +Disable support for combining an option and its value into a single argument +with the assignment sign (the \fIoption\fR\fB=\fR\fIvalue\fR\fR form)\. This +functionality requires a non-empty option prefix (\fB--option-prefix\fR)\. +.IP "\fB--include-with-brackets\fR" +Use angle brackets (\fB<>\fR) instead of quotes (\fB""\fR) in the generated +\fB#include\fR directives\. +.IP "\fB--include-prefix\fR \fIprefix\fR" +Add \fIprefix\fR to the generated \fB#include\fR directive paths\. +.IP "\fB--guard-prefix\fR \fIprefix\fR" +Add \fIprefix\fR to the generated header inclusion guards\. The prefix is +transformed to upper case and characters that are illegal in a preprocessor +macro name are replaced with underscores\. +.IP "\fB--reserved-name\fR \fIname\fR=\fIrep\fR" +Add \fIname\fR with an optional \fIrep\fR replacement to the list of names +that should not be used as identifiers\. If provided, the replacement name is +used instead\. All C++ keywords are already in this list\. +.IP "\fB--options-file\fR \fIfile\fR" +Read additional options from \fIfile\fR\. Each option should appear on a +separate line optionally followed by space or equal sign (\fB=\fR) and an +option value\. Empty lines and lines starting with \fB#\fR are ignored\. +Option values can be enclosed in double (\fB"\fR) or single (\fB'\fR) quotes +to preserve leading and trailing whitespaces as well as to specify empty +values\. If the value itself contains trailing or leading quotes, enclose it +with an extra pair of quotes, for example \fB'"x"'\fR\. Non-leading and +non-trailing quotes are interpreted as being part of the option value\. + +The semantics of providing options in a file is equivalent to providing the +same set of options in the same order on the command line at the point where +the \fB--options-file\fR option is specified except that the shell escaping +and quoting is not required\. Repeat this option to specify more than one +options file\. +.\" +.\" DIAGNOSTICS +.\" +.SH DIAGNOSTICS +If the input file is not a valid CLI definition, +.B cli +will issue diagnostic messages to STDERR and exit with non-zero exit code. +.\" +.\" BUGS +.\" +.SH BUGS +Send bug reports to the cli-users@codesynthesis.com mailing list. +.\" +.\" COPYRIGHT +.\" +.SH COPYRIGHT +Copyright (c) 2009-2021 Code Synthesis Tools CC. + +Permission is granted to copy, distribute and/or modify this document under +the terms of the MIT License. Copy of this license can be obtained from +http://www.codesynthesis.com/licenses/mit.txt diff --git a/cli/doc/bootstrap/cli.xhtml b/cli/doc/bootstrap/cli.xhtml new file mode 100644 index 0000000..38b1bc8 --- /dev/null +++ b/cli/doc/bootstrap/cli.xhtml @@ -0,0 +1,573 @@ + + + + + CLI 1.2.0-b.7 Compiler Command Line Manual + + + + + + + + + + + +
+
+ +

NAME

+ +

cli - command line interface compiler for C++

+ +

SYNOPSIS

+ +
+
cli [options] file
+
+ +

DESCRIPTION

+ +

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 + name.cli the following is generated. By + default or if the --generate-cxx option is + specified, the following C++ files are generated: + name.hxx (header file), name.ixx + (inline file, generated unless the --suppress-inline + option is specified), and name.cxx (source file). + If the --generate-html option is specified, then + the name.html HTML documentation file is generated. + If the --generate-man option is specified, then + the name.1 man page file is generated. When + --generate-html or --generate-man + is specified, the --stdout option can be used to + redirect the output to STDOUT instead of a file.

+ +

OPTIONS

+
+
--help
+
Print usage information and exit.
+ +
--version
+
Print version and exit.
+ +
--include-path|-I dir
+
Search dir for bracket-included + (<>) options files.
+ +
--output-dir|-o dir
+
Write the generated files to dir instead of the + current directory.
+ +
--std version
+
Specify the C++ standard that should be used during compilation. Valid + values are c++98 (default), c++11, + and c++14.
+ +
--generate-modifier
+
Generate option value modifiers in addition to accessors.
+ +
--generate-specifier
+
Generate functions for determining whether the option was specified on + the command line.
+ +
--generate-parse
+
Generate parse() functions instead of parsing + constructors. This is primarily useful for being able to parse into an + already initialized options class instance, for example, to implement + option appending/overriding.
+ +
--generate-merge
+
Generate merge() functions. This is primarily + useful for being able to merge several already parsed options class + instances, for example, to implement option appending/overriding. Note + that this option forces --generate-specifier.
+ +
--generate-description
+
Generate the option description list that can be examined at + runtime.
+ +
--generate-file-scanner
+
Generate the argv_file_scanner implementation. + This scanner is capable of reading command line arguments from the + argv array as well as files specified with command + line options.
+ +
--generate-vector-scanner
+
Generate the vector_scanner implementation. This + scanner is capable of reading command line arguments from + vector<string>.
+ +
--generate-group-scanner
+
Generate the group_scanner implementation. This + scanner supports grouping of arguments (usually options) to apply only to + a certain argument. + +

Groups can be specified before (leading) and/or after (trailing) the + argument they apply to. A leading group starts with + '{' and ends with '}+' while a + trailing group starts with '+{' and ends with + '}'. For example:

+ +
{ --foo --bar }+ arg   # 'arg' with '--foo' '--bar'
+arg +{ fox=1 baz=2 }   # 'arg' with 'fox=1' 'baz=2'
+ +

Multiple leading and/or trailing groups can be specified for the same + argument. For example:

+ +
{ -f }+ { -b }+ arg +{ f=1 } +{ b=2 } # 'arg' with '-f' 'b' 'f=1' 'b=2'
+ +

The group applies to a single argument only unless multiple arguments + are themselves grouped with '{' and + '}'. For example:

+ +
{ --foo }+ arg1  arg2 +{ --bar }      # 'arg1' with '--foo'
+                                      # 'arg2' with '--bar'
+
+{ --foo }+ { arg1  arg2 } +{ --bar }  # 'arg1' with '--foo' '--bar'
+                                      # 'arg2' with '--foo' '--bar'
+ +

The group separators ('{', + '}+', etc) must be separate command line arguments. In + particular, they must not be adjacent either to the arguments inside the + group nor to the argument they apply to. All such cases will be treated as + ordinary arguments. For example:

+ +
{--foo}+ arg   # '{--foo}+' ...
+arg+{ --foo }  # 'arg+{' ...
+ +

If one of the group separators needs to be specified as an argument + verbatim, then it must be escaped with '\'. For + example:

+ +
}             # error: unexpected group separator
+}x            # '}x'
+\}            # '}'
+{ \}+ }+ arg  # 'arg' with '}+'
+ +
--suppress-inline
+
Generate all functions non-inline. By default simple functions are + made inline. This option suppresses creation of the inline file.
+ +
--suppress-cli
+
Do not generate the CLI support types (scanners, parser, etc). + Normally, the support types are generated unless another + .cli was included, in which case the support types are + expected to be provided by its generated code.
+ +
--cli-namespace ns
+
Generate the CLI support types in the ns namespace + (cli by default). The namespace can be nested, for + example details::cli. If the namespace is empty, then + the support types are generated in the global namespace.
+ +
--ostream-type type
+
Output stream type instead of the default + std::ostream that should be used to print usage and + exception information.
+ +
--generate-cxx
+
Generate C++ code. If neither --generate-man, + --generate-html, nor + --generate-txt is specified, this mode is assumed by + default.
+ +
--generate-man
+
Generate documentation in the man page format.
+ +
--generate-html
+
Generate documentation in the HTML format.
+ +
--generate-txt
+
Generate documentation in the plain text format, similar to + usage.
+ +
--stdout
+
Write output to STDOUT instead of a file. This option is not valid + when generating C++ code and is normally used to combine generated + documentation for several option classes in a single file.
+ +
--suppress-undocumented
+
Suppress the generation of documentation entries for undocumented + options.
+ +
--suppress-usage
+
Suppress the generation of the usage printing code.
+ +
--long-usage
+
If no short documentation string is provided, use the complete long + documentation string in usage. By default, in this situation only the + first sentence from the long string is used.
+ +
--short-usage
+
If specified together with --long-usage, generate + both short and long usage versions. In this mode, the long usage printing + function is called print_long_usage() and in its + implementation the long documentation string is always used, even if the + short version is provided.
+ +
--page-usage name
+
Generate the combined usage printing code for the entire page. + Specifically, this will include all the namespace-level documentation as + well as usage for all the options classes printed in the order they are + defined in the main translation unit (documentation/classes from included + units are ignored except for base classes). + +

The name argument is used as a prefix to form the + name of the usage printing function. It can include the namespace + qualification as well as documentation variable expansion, for + example:

+ +
--page-usage print_         # print_usage() in global namespace
+--page-usage app::print_    # print_usage() in app namespace
+--page-usage print_$name$_  # print_foo_usage() if name is foo
+ +

If both --long-usage and + --short-usage options are specified, then the long + usage function has the *long_usage() suffix.

+ +
--option-length len
+
Indent option descriptions len characters when + printing usage. This is useful when you have multiple options classes, + potentially in separate files, and would like their usage to have the same + indentation level.
+ +
--ansi-color
+
Use ANSI color escape sequences when printing usage. By "color" we + really only mean the bold and underline modifiers. Note that Windows + console does not recognize ANSI escape sequences and will display them as + garbage. However, if you pipe such output through + less(1), it will display them correctly.
+ +
--exclude-base
+
Exclude base class information from usage and documentation.
+ +
--include-base-last
+
Include base class information after derived for usage and + documentation. By default, base classes are included first.
+ +
--class-doc name=kind
+
Specify the documentation kind that should be used + for the options class name. The + name value should be a fully-qualified class name, for + example, app::options. The kind + value can be short, long, + exclude, or exclude-base. If the + value is exclude, then the class documentation is + excluded from usage and man/HTML/text output. If it is + exclude-base, then it is only excluded when used as a + base. For usage, the short and + long values determine which usage function will be + called when the class is used as base or as part of the page usage (see + --page-usage). For man/HTML/text, these values + determine which documentation strings are used in the output.
+ +
--class name
+
Generate the man page, HTML, or text documentation only for the + options class name. The name value + should be a fully-qualified options class name, for example, + app::options. To generate documentation for multiple + classes, repeat this option and the documentation will be produced in the + order specified. This functionality is useful if you need to assemble + documentation from multiple classes in a specific order or to insert + custom documentation between options belonging to different classes.
+ +
--docvar|-v name=val
+
Set documentation variable name to the value + val. Documentation variables can be substituted in + prologues and epilogues (see --*-prologue* and + --*-epilogue* options) using the + $name$ + expansion syntax (use $$ to escape expansion). They + can also be defined in .cli files using the + "\name=val" + syntax.
+ +
--link-regex regex
+
Add regex to the list of regular expressions used + to transform link targets in the generated documentation. The argument to + this option is a Perl-like regular expression in the form + /pattern/replacement/. Any + character can be used as a delimiter instead of '/' + and the delimiter can be escaped inside pattern and + replacement with a backslash (\). + You can specify multiple regular expressions by repeating this option. All + the regular expressions are tried in the order specified and the first + expression that matches is used. Use the + --link-regex-trace option to debug link + transformation.
+ +
--link-regex-trace
+
Trace the process of applying regular expressions specified with the + --link-regex option. Use this option to find out why + your regular expressions don't do what you expected them to do.
+ +
--html-heading-map c=h
+
Map CLI heading c (valid values: + 'H', '0', '1', + 'h', and '2') to HTML heading + h (for example, 'h1', + 'h2', etc).
+ +
--omit-link-check
+
Don't check that local fragment link references (\l{#ref ...}) resolve + to ids.
+ +
--hxx-prologue text
+
Insert text at the beginning of the generated C++ + header file.
+ +
--ixx-prologue text
+
Insert text at the beginning of the generated C++ + inline file.
+ +
--cxx-prologue text
+
Insert text at the beginning of the generated C++ + source file.
+ +
--man-prologue text
+
Insert text at the beginning of the generated man + page file.
+ +
--html-prologue text
+
Insert text at the beginning of the generated HTML + file.
+ +
--txt-prologue text
+
Insert text at the beginning of the generated text + file.
+ +
--hxx-epilogue text
+
Insert text at the end of the generated C++ header + file.
+ +
--ixx-epilogue text
+
Insert text at the end of the generated C++ inline + file.
+ +
--cxx-epilogue text
+
Insert text at the end of the generated C++ source + file.
+ +
--man-epilogue text
+
Insert text at the end of the generated man page + file.
+ +
--html-epilogue text
+
Insert text at the end of the generated HTML + file.
+ +
--txt-epilogue text
+
Insert text at the end of the generated text + file.
+ +
--hxx-prologue-file file
+
Insert the content of file at the beginning of the + generated C++ header file.
+ +
--ixx-prologue-file file
+
Insert the content of file at the beginning of the + generated C++ inline file.
+ +
--cxx-prologue-file file
+
Insert the content of file at the beginning of the + generated C++ source file.
+ +
--man-prologue-file file
+
Insert the content of file at the beginning of the + generated man page file.
+ +
--html-prologue-file file
+
Insert the content of file at the beginning of the + generated HTML file.
+ +
--txt-prologue-file file
+
Insert the content of file at the beginning of the + generated text file.
+ +
--hxx-epilogue-file file
+
Insert the content of file at the end of the + generated C++ header file.
+ +
--ixx-epilogue-file file
+
Insert the content of file at the end of the + generated C++ inline file.
+ +
--cxx-epilogue-file file
+
Insert the content of file at the end of the + generated C++ source file.
+ +
--man-epilogue-file file
+
Insert the content of file at the end of the + generated man page file.
+ +
--html-epilogue-file file
+
Insert the content of file at the end of the + generated HTML file.
+ +
--txt-epilogue-file file
+
Insert the content of file at the end of the + generated text file.
+ +
--output-prefix prefix
+
Add prefix at the beginning of the generated + output file name(s).
+ +
--output-suffix suffix
+
Add suffix at the end of the generated output file + name(s). Note that it is added before any file type-specific suffixes; see + --*-suffix below.
+ +
--hxx-suffix suffix
+
Use suffix instead of the default + .hxx to construct the name of the generated header + file.
+ +
--ixx-suffix suffix
+
Use suffix instead of the default + .ixx to construct the name of the generated inline + file.
+ +
--cxx-suffix suffix
+
Use suffix instead of the default + .cxx to construct the name of the generated source + file.
+ +
--man-suffix suffix
+
Use suffix instead of the default + .1 to construct the name of the generated man page + file.
+ +
--html-suffix suffix
+
Use suffix instead of the default + .html to construct the name of the generated HTML + file.
+ +
--txt-suffix suffix
+
Use suffix instead of the default + .txt to construct the name of the generated text + file.
+ +
--option-prefix prefix
+
Use prefix instead of the default + '-' as an option prefix. Unknown command line + arguments that start with this prefix are treated as unknown options. If + you set the option prefix to the empty value, then all the unknown command + line arguments will be treated as program arguments.
+ +
--option-separator sep
+
Use sep instead of the default + '--' as an optional separator between options and + arguments. All the command line arguments that are parsed after this + separator are treated as program arguments. Set the option separator to + the empty value if you don't want this functionality.
+ +
--keep-separator
+
Leave the option separator in the scanner. This is primarily useful + for incremental option parsing.
+ +
--no-combined-flags
+
Disable support for combining multiple single-character flags into a + single argument (the -xyz form that is equivalent to + -x -y -z). An + argument is considered a combination of flags if it starts with a single + option prefix (--option-prefix) and only contains + letters and digits. Note that an option with a value may not be part of + such a combination, not even if it is specified last.
+ +
--no-combined-values
+
Disable support for combining an option and its value into a single + argument with the assignment sign (the + option=value form). This functionality + requires a non-empty option prefix + (--option-prefix).
+ +
--include-with-brackets
+
Use angle brackets (<>) instead of quotes + ("") in the generated #include + directives.
+ +
--include-prefix prefix
+
Add prefix to the generated + #include directive paths.
+ +
--guard-prefix prefix
+
Add prefix to the generated header inclusion + guards. The prefix is transformed to upper case and characters that are + illegal in a preprocessor macro name are replaced with underscores.
+ +
--reserved-name name=rep
+
Add name with an optional rep + replacement to the list of names that should not be used as identifiers. + If provided, the replacement name is used instead. All C++ keywords are + already in this list.
+ +
--options-file file
+
Read additional options from file. Each option + should appear on a separate line optionally followed by space or equal + sign (=) and an option value. Empty lines and lines + starting with # are ignored. Option values can be + enclosed in double (") or single + (') 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 '"x"'. Non-leading and + non-trailing quotes are interpreted as being part of the option value. + +

The semantics of providing options in a file is equivalent to providing + the same set of options in the same order on the command line at the point + where the --options-file option is specified except + that the shell escaping and quoting is not required. Repeat this option to + specify more than one options file.

+
+ +

DIAGNOSTICS

+ +

If the input file is not a valid CLI definition, cli + will issue diagnostic messages to STDERR and exit with non-zero exit + code.

+ +

BUGS

+ +

Send bug reports to the + cli-users@codesynthesis.com mailing list.

+ +
+ +
+ + diff --git a/cli/doc/buildfile b/cli/doc/buildfile index f47adad..d56c7f5 100644 --- a/cli/doc/buildfile +++ b/cli/doc/buildfile @@ -7,14 +7,115 @@ css{*}: extension = css define xhtml: doc xhtml{*}: extension = xhtml -./: {man1 xhtml}{cli} \ - css{default} \ - file{cli-*} +define ps: doc +ps{*}: extension = ps -./: guide/doc{cli-guide*} \ - guide/xhtml{index} \ - guide/file{*.html2ps} +define pdf: doc +pdf{*}: extension = pdf -doc{*}: install.subdirs = true +define html2ps: file +html2ps{*}: extension = html2ps -./: file{doc.sh} +./: css{default} xhtml{cli-guide} bootstrap/{man1 xhtml}{cli} + +if $config.cli.develop +{ + doc_version = [string] "$version.major\.$version.minor\.$version.patch" + if $version.pre_release + doc_version += "-$version.pre_release_string" + + # Let's take the last for-digit number to cover 2000-2021,2022. + # + doc_year = $regex.replace($copyright, '.+[-, ]([0-9][0-9][0-9][0-9]) .+', '\1') + + man_options = -v project="CLI" -v version="$doc_version" \ + -v copyright="$copyright" --suppress-undocumented + + # We use the cli version we've built to generate the documentation. + # + # Note: avoid cleaning it through this dependency. + # + include ../cli/ + + {xhtml man1}{cli}: ../cli/exe{cli}: clean = false + + ./: man1{cli}: ../cli/cli{options} file{cli-prologue.1 cli-epilogue.1} + {{ + diag cli --man ($<[1]) + + # Use the copyright year to approximate the last authoring date. + # + date +"%B %Y" | set date + + ($<[0]) --generate-man $man_options \ + -v date="January $doc_year" \ + --man-prologue-file $path($<[2]) \ + --man-epilogue-file $path($<[3]) \ + --stdout $path($<[1]) >$path($>) + + # If the result differs from the bootstrap version, copy it over. Unlike + # the bootstrap cli case, here we don't need to cause a build restart. + # + if! diff $src_base/bootstrap/cli.1 $path($>) >- + cp $path($>) $src_base/bootstrap/cli.1 + end + }} + + ./: xhtml{cli}: $src_root/cli/cli{options} \ + file{cli-prologue.xhtml cli-epilogue.xhtml} + {{ + diag cli --html ($<[1]) + + ($<[0]) --generate-html $man_options \ + --html-prologue-file $path($<[2]) \ + --html-epilogue-file $path($<[3]) \ + --stdout $path($<[1]) >$path($>) + + if! diff $src_base/bootstrap/cli.xhtml $path($>) >- + cp $path($>) $src_base/bootstrap/cli.xhtml + end + }} + + # Import the html2ps and ps2pdf programs from the system, if available. + # + import? html2ps = html2ps%exe{html2ps} + import? ps2pdf = ps2pdf14%exe{ps2pdf14} + + if ($html2ps != [null] && $ps2pdf != [null]) + { + # Note that we include these generated files into the distribution and + # don't remove them when cleaning in src (so that clean results in a state + # identical to distributed). + # + ./: ps{cli-guide}: xhtml{cli-guide} html2ps{guide} $html2ps + { + options = + + dist = true + clean = ($src_root != $out_root) + } + {{ + diag html2ps ($<[0]) + $html2ps $options -f $path($<[1]) -o $path($>) $path($<[0]) + }} + + ./: pdf{cli-guide}: ps{cli-guide} $ps2pdf + { + options = -dOptimize=true -dEmbedAllFonts=true + + dist = true + clean = ($src_root != $out_root) + } + {{ + diag ps2pdf ($<[0]) + $ps2pdf $options $path($<[0]) $path($>) + }} + } + else + { + warn "html2ps and/or ps2pdf14 are not available, not generating .ps and .pdf documentation" + ./: html2ps{guide} # Note: not keeping ps/pdf (could be outdated). + } +} +else + ./: file{cli-prologue* cli-epilogue*} html2ps{guide} {ps pdf}{+cli-guide} diff --git a/cli/doc/cli-guide.xhtml b/cli/doc/cli-guide.xhtml new file mode 100644 index 0000000..675db03 --- /dev/null +++ b/cli/doc/cli-guide.xhtml @@ -0,0 +1,1336 @@ + + + + + CLI Language Getting Started Guide + + + + + + + + + + + + + +
+
+ +
+ +
+
CLI Language
+
Getting Started Guide
+ +

Copyright © 2009-2020 Code Synthesis Tools CC.

+ +

Permission is granted to copy, distribute, and/or modify this document + under the terms of the + MIT License. +

+ +

This document is available in the following formats: + XHTML, + PDF, and + PostScript.

+ +
+ +

Table of Contents

+ + + + + + + + + + + + + +
1Introduction
2Hello World Example + + + + + + +
2.1Defining Command Line Interface
2.2Translating CLI Definitions to C++
2.3Implementing Application Logic
2.4Compiling and Running
2.5Adding Documentation
+
3CLI Language + + + + + + +
3.1Options Class Definition
3.2Option Definition
3.3Option Documentation
3.4Include Directive
3.5Namespace Definition
+
+
+ + + +

1 Introduction

+ +

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.

+ +

Beyond this guide, you may also find the following sources of + information useful:

+ +
    +
  • CLI + Compiler Command Line Manual
  • + +
  • The INSTALL file in the CLI distribution provides build + instructions for various platforms.
  • + +
  • The examples/ directory in the CLI distribution contains + a collection of examples and a README file with an overview of each + example.
  • + +
  • The cli-users + mailing list is the place to ask technical questions about the CLI language + and compiler. Furthermore, the + cli-users mailing + list archives may already have answers to some of your questions.
  • +
+ + + + + +

2 Hello World Example

+ +

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 hello example which can be found in the + examples/hello/ directory of the CLI distribution.

+ +

2.1 Defining Command Line Interface

+ +

Our hello application is going to print a greeting + line for each name supplied on the command line. It will also + support two command line options, --greeting + and --exclamations, that can be used to + customize the greeting line. The --greeting + option allows us to specify the greeting phrase instead of the + default "Hello". The --exclamations + option is used to specify how many exclamation marks should + be printed at the end of each greeting. We will also support + the --help option which triggers printing of the + usage information.

+ +

We can now write a description of the above command line interface + in the CLI language and save it into hello.cli:

+ +
+include <string>;
+
+class options
+{
+  bool --help;
+  std::string --greeting = "Hello";
+  unsigned int --exclamations = 1;
+};
+  
+ +

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 + hello.cli to the command line interface described in + the preceding paragraphs. The next step is to translate this + interface specification to C++.

+ +

2.2 Translating CLI Definitions to C++

+ +

Now we are ready to translate hello.cli to C++. + To do this we invoke the CLI compiler from a terminal (UNIX) or + a command prompt (Windows): +

+ +
+$ cli hello.cli
+  
+ +

This invocation of the CLI compiler produces three C++ files: + hello.hxx hello.ixx, and + hello.cxx. You can change the file name extensions + for these files with the compiler command line options. See the + CLI + Compiler Command Line Manual for more information.

+ +

The following code fragment is taken from hello.hxx; it + should give you an idea about what gets generated:

+ +
+#include <string>
+
+class options
+{
+public:
+  options (int argc, char** argv);
+  options (int argc, char** argv, int& end);
+
+  // Option accessors.
+  //
+public:
+  bool
+  help () const;
+
+  const std::string&
+  greeting () const;
+
+  unsigned int
+  exclamations () const;
+
+private:
+  ..
+};
+  
+ +

The options C++ class corresponds to the options + CLI class. For each option in this CLI class an accessor function is + generated inside the C++ class. The options C++ class also + defines a number of overloaded constructs that we can use to parse the + argc/argv array. Let's now see how we can use this generated + class to implement option parsing in our hello application.

+ +

2.3 Implementing Application Logic

+ +

At this point we have everything we need to implement our + application:

+ +
+#include <iostream>
+#include "hello.hxx"
+
+using namespace std;
+
+void
+usage (ostream& os)
+{
+  os << "usage: driver [options] <names>" << endl
+     << "options:" << 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 << "no names provided" << endl;
+      usage (cerr);
+      return 1;
+    }
+
+    // Print the greetings.
+    //
+    for (int i = end; i < argc; i++)
+    {
+      cout << o.greeting () << ", " << argv[i];
+
+      for (unsigned int j = 0; j < o.exclamations (); j++)
+        cout << '!';
+
+      cout << endl;
+    }
+  }
+  catch (const cli::exception& e)
+  {
+    cerr << e << endl;
+    usage (cerr);
+    return 1;
+  }
+}
+
+ +

At the beginning of our application we create the options + object which parses the command line. The end 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 cli::exception in case something goes + wrong, for example, an unknown option is specified or an option value + is invalid. +

+ +

2.4 Compiling and Running

+ +

After saving our application from the previous section in + driver.cxx, we are ready to build and run our program. + On UNIX this can be done with the following commands:

+ +
+$ c++ -o driver driver.cxx hello.cxx
+
+$ ./driver world
+Hello, world!
+
+$ ./driver --greeting Hi --exclamations 3 John Jane
+Hi, John!!!
+Hi, Jane!!!
+  
+ +

We can also test the error handling:

+ +
+$ ./driver -n 3 Jane
+unknown option '-n'
+usage: driver [options] <names>
+options:
+--help
+--greeting <arg>
+--exclamations <arg>
+
+$ ./driver --exclamations abc Jane
+invalid value 'abc' for option '--exclamations'
+usage: driver [options] <names>
+options:
+--help
+--greeting <arg>
+--exclamations <arg>
+  
+ +

2.5 Adding Documentation

+ +

As we have seen in the previous sections, the options + C++ class provides the print_usage() 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:

+ +
+$ ./driver --help
+usage: driver [options] <names>
+options:
+--help
+--greeting <arg>
+--exclamations <arg>
+  
+ +

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:

+ +
+include <string>;
+
+class options
+{
+  bool --help {"Print usage information and exit."};
+
+  std::string --greeting = "Hello"
+  {
+    "<text>",
+    "Use <text> as a greeting phrase instead of the default \"Hello\"."
+  };
+
+  unsigned int --exclamations = 1
+  {
+    "<num>",
+    "Print <num> exclamation marks instead of 1 by default."
+  };
+};
+  
+ +

If we now save this updated command line interface to + hello.cli and recompile our application, the usage + information printed by the program will look like this:

+ +
+usage: driver [options] <names>
+options:
+--help               Print usage information and exit.
+--greeting <text>    Use <text> as a greeting phrase instead of the
+                     default "Hello".
+--exclamations <num> Print <num> exclamation marks instead of 1 by
+                     default.
+  
+ +

We can also generate the program documentation in the HTML + (--generate-html CLI option) and man page + (--generate-man CLI option) formats. For example:

+ +
+$ cli --generate-html hello.cli
+  
+ +

The resulting hello.html file contains the following + documentation:

+ +
+
--help
+
Print usage information and exit.
+ +
--greeting text
+
Use text as a greeting phrase instead of the default "Hello".
+ +
--exclamations num
+
Print num exclamation marks instead of 1 by default.
+ +
+ +

This HTML fragment can be combined with custom prologue and epilogue + to create a complete program documentation + (--html-prologue/--html-epilogue options for the HTML + output, --man-prologue/--man-epilogue options for the + man page output). For an example of such complete documentation see + the CLI + Compiler Command Line Manual and the cli(1) man + page. For more information on the option documentation syntax, + see Section 3.3, Option Documentation.

+ + + + +

3 CLI Language

+ +

This chapter describes the CLI language and its mapping to C++. + A CLI file consists of zero or more Include + Directives followed by one or more Namespace Definitions + or Option Class Definitions. C and C++-style comments + can be used anywhere in the CLI file except in character and + string literals.

+ +

3.1 Option Class Definition

+ +

The central part of the CLI language is option class. An + option class contains one or more option definitions, for + example:

+ +
+class options
+{
+  bool --help;
+  int --compression;
+};
+  
+ +

If we translate the above CLI fragment to C++, we will get a C++ + class with the following interface:

+ +
+class options
+{
+public:
+  options (int& 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& 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& argc,
+           char** argv,
+           int& 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& argc,
+           char** argv,
+           int& 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&,
+           cli::unknown_mode opt_mode = cli::unknown_mode::fail,
+           cli::unknown_mode arg_mode = cli::unknown_mode::stop);
+
+  options (const options&);
+
+  options&
+  operator= (const options&);
+
+public:
+  static void
+  print_usage (std::ostream&);
+
+public:
+  bool
+  help () const;
+
+  int
+  compression () const;
+};
+  
+ + +

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 --generate-modifier CLI + compiler option is specified, modifier functions corresponding to option + definitions. It also defines a public static print_usage() + function that can be used to print the usage information for the options + defined by the class.

+ +

The argc/argv arguments in the overloaded constructors + are used to pass the command line arguments array, normally as passed + to main(). The start 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 argv[0]. + The end 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 erase + argument is true, then the recognized options and their + values are removed from the argv array and the + argc count is updated accordingly.

+ +

The opt_mode and arg_mode arguments + specify the parser behavior when it encounters an unknown option + and argument, respectively. The unknown_mode type + is part of the generated CLI runtime support code. It has the + following interface:

+ +
+namespace cli
+{
+  class unknown_mode
+  {
+  public:
+    enum value
+    {
+      skip,
+      stop,
+      fail
+    };
+
+    unknown_mode (value v);
+    operator value () const;
+  };
+}
+  
+ +

If the mode is skip, the parser skips an unknown + option or argument and continue parsing. If the mode is + stop, the parser stops the parsing process. The + position of the unknown entity is stored in the end + argument. If the mode is fail, the parser throws the + cli::unknown_option or cli::unknown_argument + exception (described blow) on encountering an unknown option or argument, + respectively.

+ +

Instead of the argc/argv arguments, the last overloaded + constructor accepts the cli::scanner object. It is part + of the generated CLI runtime support code and has the following + abstract interface:

+ +
+namespace cli
+{
+  class scanner
+  {
+  public:
+    virtual bool
+    more () = 0;
+
+    virtual const char*
+    peek () = 0;
+
+    virtual const char*
+    next () = 0;
+
+    virtual void
+    skip () = 0;
+  };
+}
+  
+ +

The CLI runtime also provides two implementations of this interface: + cli::argv_scanner and cli::argv_file_scanner. + The first implementation is a simple scanner for the argv + array (it is used internally by all the other constructors) and has the + following interface:

+ +
+namespace cli
+{
+  class argv_scanner
+  {
+  public:
+    argv_scanner (int& argc, char** argv, bool erase = false);
+    argv_scanner (int start, int& argc, char** argv, bool erase = false);
+
+    int
+    end () const;
+
+    ...
+  };
+}
+  
+ +

The cli::argv_file_scanner implementation provides + support for reading command line arguments from the argv + array as well as files specified with command line options. It is + generated only if explicitly requested with the + --generate-file-scanner CLI compiler option and has + the following interface:

+ +
+namespace cli
+{
+  class argv_file_scanner
+  {
+  public:
+    argv_file_scanner (int& argc,
+                       char** argv,
+                       const std::string& option,
+                       bool erase = false);
+
+    argv_file_scanner (int start,
+                       int& argc,
+                       char** argv,
+                       const std::string& 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& argc,
+                       char** argv,
+                       const option_info* options,
+                       std::size_t options_count,
+                       bool erase = false);
+
+    argv_file_scanner (int start,
+                       int& argc,
+                       char** argv,
+                       const option_info* options,
+                       std::size_t options_count,
+                       bool erase = false);
+    ...
+  };
+}
+  
+ +

The option argument in the first two constructors and + the options and options_count 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 # are ignored. Option values can + be enclosed in double (") or single (') + 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 + '"x"'. Non-leading and non-trailing quotes are interpreted + as being part of the option value.

+ +

The semantics of providing options in a file is equivalent to providing + the same set of options in the same order on the command line at the + point where the 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.

+ +

The parsing constructor (those with the argc/argv or + cli::scanner arguments) can throw the following exceptions: cli::unknown_option, + cli::unknown_argument, cli::missing_value, and + cli::invalid_value. The first two exceptions are thrown + on encountering unknown options and arguments, respectively, as + described above. The missing_value exception is thrown when + an option value is missing. The invalid_value exception is + thrown when an option value is invalid, for example, a non-integer value + is specified for an option of type int.

+ +

Furthermore, all scanners (and thus the parsing constructors that + call them) can throw the cli::eos_reached exception + which indicates that one of the peek(), next(), + or skip() functions were called while more() + returns false. Catching this exception normally indicates an + error in an option parser implementation. The argv_file_scanner + class can also throw the cli::file_io_failure exception + which indicates that a file could not be opened or there was a reading + error as well as the cli::unmatched_quote exception + which indicates that an unmatched leading or trailing quote was + found in an option value.

+ +

All CLI exceptions are derived from the common cli::exception + class which implements the polymorphic std::ostream insertion. + For example, if you catch the cli::unknown_option + exception as cli::exception and print it to + std::cerr, you will get the error message corresponding + to the unknown_option exception.

+ +

The exceptions described above are part of the generated CLI runtime + support code and have the following interfaces:

+ +
+#include <exception>
+
+namespace cli
+{
+  class exception: public std::exception
+  {
+  public:
+    virtual void
+    print (std::ostream&) const = 0;
+  };
+
+  inline std::ostream&
+  operator<< (std::ostream& os, const exception& e)
+  {
+    e.print (os);
+    return os;
+  }
+
+  class unknown_option: public exception
+  {
+  public:
+    unknown_option (const std::string& option);
+
+    const std::string&
+    option () const;
+
+    virtual void
+    print (std::ostream&) const;
+
+    virtual const char*
+    what () const throw ();
+  };
+
+  class unknown_argument: public exception
+  {
+  public:
+    unknown_argument (const std::string& argument);
+
+    const std::string&
+    argument () const;
+
+    virtual void
+    print (std::ostream&) const;
+
+    virtual const char*
+    what () const throw ();
+  };
+
+  class missing_value: public exception
+  {
+  public:
+    missing_value (const std::string& option);
+
+    const std::string&
+    option () const;
+
+    virtual void
+    print (std::ostream&) const;
+
+    virtual const char*
+    what () const throw ();
+  };
+
+  class invalid_value: public exception
+  {
+  public:
+    invalid_value (const std::string& option,
+                   const std::string& value);
+
+    const std::string&
+    option () const;
+
+    const std::string&
+    value () const;
+
+    virtual void
+    print (std::ostream&) const;
+
+    virtual const char*
+    what () const throw ();
+  };
+
+  class eos_reached: public exception
+  {
+  public:
+    virtual void
+    print (std::ostream&) const;
+
+    virtual const char*
+    what () const throw ();
+  };
+
+  class file_io_failure: public exception
+  {
+  public:
+    file_io_failure (const std::string& file);
+
+    const std::string&
+    file () const;
+
+    virtual void
+    print (std::ostream&) const;
+
+    virtual const char*
+    what () const throw ();
+  };
+
+  class unmatched_quote: public exception
+  {
+  public:
+    unmatched_quote (const std::string& argument);
+
+    const std::string&
+    argument () const;
+
+    virtual void
+    print (std::ostream&) const;
+
+    virtual const char*
+    what () const throw ();
+  };
+}
+  
+ + +

3.2 Option Definition

+ +

An option definition consists of four components: type, + name, default value, and documentation. + An option type can be any C++ type as long as its string representation + can be parsed using the std::istream interface. If the option + type is user-defined then you will need to include its declaration using + the Include Directive.

+ +

An option of a type other than bool is expected to + have a value. An option of type bool 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 + true.

+ +

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 |. The C++ accessor and modifier function names are + derived from the first name by removing any leading special characters, + such as -, /, etc., and replacing special + characters in other places with underscores. For example, the following + option definition:

+ +
+class options
+{
+  int --compression-level | --comp | -c;
+};
+  
+ +

Will result in the following accessor function:

+ +
+class options
+{
+  int
+  compression_level () const;
+};
+  
+ +

While any option alias can be used on the command line to specify + this option's value.

+ +

If the option name conflicts with one of the CLI language keywords, + it can be specified as a string literal:

+ +
+class options
+{
+  bool "int";
+};
+  
+ +

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 bool option will be initialized to false, + an int option will be initialized to 0, etc.

+ +

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:

+ +
+include <string>;
+
+class options
+{
+  int -i1 = 5;
+  int -i2 (5);
+
+  std::string -s1 = "John";
+  std::string -s2 ("Mr John Doe", 8, 3);
+};
+  
+ +

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:

+ +
+include "constants.hxx"; // Defines default_value.
+
+class options
+{
+  int -a = default_value;
+  int -b (25 * 4);
+  int -c = (25 / default_value + 3);
+};
+  
+ +

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 std::vector, std::set, and + std::map.

+ +

When std::vector or std::set 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, + std::vector will contain all the values, including + duplicates while std::set will contain all the unique + values. For example:

+ +
+include <set>;
+include <vector>;
+
+class options
+{
+  std::vector<int> --vector | -v;
+  std::set<int> --set | -s;
+};
+  
+ +

If we have a command line like this: + -v 1 -v 2 -v 1 -s 1 -s 2 -s 1, then the vector returned + by the vector() accessor function will contain three + elements: 1, 2, and 1 while + the set returned by the set() accessor will contain + two elements: 1 and 2.

+ +

When std::map is specified as an option type, the option + value is expected to have two parts: the key and the value, separated + by =. All the option values are then parsed into key/value + pairs and inserted into the map. For example:

+ +
+include <map>;
+include <string>;
+
+class options
+{
+  std::map<std::string, std::string> --map | -m;
+};
+  
+ +

The possible option values for this interface are: -m a=A, + -m =B (key is an empty string), -m c= (value + is an empty string), or -m d (same as -m d=).

+ +

The last component in the option definition is optional documentation. + It is discussed in the next section.

+ +

3.3 Option Documentation

+ +

Option documentation mimics C++ string array initialization: + it is enclosed in {} and consists of one or more + documentation strings separated by a comma, for example:

+ +
+class options
+{
+  int --compression = 5
+  {
+    "<level>",
+    "Set compression to <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."
+  };
+};
+  
+ +

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 bool (options of type + bool are flags and don't have an explicit value). + The second string (or the first string for options of type + bool) 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 bool), then the second (first) string is + assumed to be the long documentation string.

+ +

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 + --long-usage CLI compiler option. When generating + the program documentation, the long documentation strings are + always used.

+ +

The value documentation string can contain text enclosed in + <> 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 level + value for the --compression option presented above + will be displayed as <level> while in the HTML and + man page output it will be typeset in italic as + level. Here is another example using the + std::map type:

+ +
+include <map>;
+include <string>;
+
+class options
+{
+  std::map<std::string, std::string> --map
+  {
+    "<key>=<value>",
+    "Add the <key>, <value> pair to the map."
+  };
+};
+  
+ +

The resulting HTML output for this option would look like this:

+ +
+
--map key=value
+
Add the key, value pair to the map.
+
+ +

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 + \c{} block. Similarly, text can be typeset in bold or + italic fonts using the \b{} and \i{} blocks, + respectively. You can also combine several font properties in a single + block, for example, \cb{bold code}. If you need to include + literal } in a formatting block, you can use the + \} escape sequence, for example, + \c{int a[] = {1, 2\}}. The following example shows how we + can use these mechanisms:

+ +
+class options
+{
+  int --compression = 5
+  {
+    "<level>",
+    "Set compression to <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}."
+  };
+};
+  
+ +

The resulting HTML output for this option would look like this:

+ +
+
--compression level
+
Set compression to 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.

+
+ +

3.4 Include Directive

+ +

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 < > or + " "-enclosed paths. The CLI compiler does not + actually open or read these files. Instead, the include directives + are translated to C++ preprocessor #include directives + in the generated C++ header file. For example, the following CLI + definition:

+ +
+include <string>;
+include "types.hxx"; // Defines the name_type class.
+
+class options
+{
+  std::string --string;
+  name_type --name;
+};
+  
+ +

Will result in the following C++ header file:

+ +
+#include <string>
+#include "types.hxx"
+
+class options
+{
+  ...
+
+  const std::string&
+  string () const;
+
+  const name_type&
+  name () const;
+
+  ...
+};
+  
+ +

Without the #include directives the std::string + and name_type types in the options class would + be undeclared and result in compilation errors.

+ +

3.5 Namespace Definition

+ +

Option classes can be placed into namespaces which are translated + directly to C++ namespaces. For example:

+ +
+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;
+    };
+  }
+}
+  
+ +

The above CLI namespace structure would result in the equivalent C++ + namespaces structure:

+ +
+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;
+    };
+  }
+}
+  
+ + +
+
+ + + + diff --git a/cli/doc/cli-prologue.1 b/cli/doc/cli-prologue.1 index 165cd1a..2b34fee 100644 --- a/cli/doc/cli-prologue.1 +++ b/cli/doc/cli-prologue.1 @@ -1,7 +1,7 @@ .\" Process this file with .\" groff -man -Tascii cli.1 .\" -.TH CLI 1 "December 2009" "CLI 1.2.0" +.TH CLI 1 "$date$" "$project$ $version$" .SH NAME cli \- command line interface compiler for C++ .\" diff --git a/cli/doc/cli-prologue.xhtml b/cli/doc/cli-prologue.xhtml index 9a57f0e..386c4f0 100644 --- a/cli/doc/cli-prologue.xhtml +++ b/cli/doc/cli-prologue.xhtml @@ -2,7 +2,7 @@ - CLI 1.2.0 Compiler Command Line Manual + $project$ $version$ Compiler Command Line Manual diff --git a/cli/doc/doc.sh b/cli/doc/doc.sh deleted file mode 100755 index dde9aca..0000000 --- a/cli/doc/doc.sh +++ /dev/null @@ -1,78 +0,0 @@ -#! /usr/bin/env bash - -version=1.2.0-b.6 - -trap 'exit 1' ERR -set -o errtrace # Trap in functions. - -function info () { echo "$*" 1>&2; } -function error () { info "$*"; exit 1; } - -date="$(date +"%B %Y")" -copyright="$(sed -n -re 's%^Copyright \(c\) (.+)\.$%\1%p' ../LICENSE)" - -while [ $# -gt 0 ]; do - case $1 in - --clean) - rm -f cli.xhtml cli.1 - rm -f guide/cli-guide.ps guide/cli-guide.pdf - exit 0 - ;; - *) - error "unexpected $1" - ;; - esac -done - -function compile () # -{ - 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.html2ps b/cli/doc/guide.html2ps new file mode 100644 index 0000000..a691002 --- /dev/null +++ b/cli/doc/guide.html2ps @@ -0,0 +1,63 @@ +@html2ps { + option { + toc: hb; + colour: 1; + hyphenate: 1; + titlepage: 1; + } + + datefmt: "%B %Y"; + + titlepage { + content: " +
+

CLI Language

+

Getting Started Guide

+

 

+

 

+

 

+

 

+

 

+

 

+
+

Copyright © 2009-2020 Code Synthesis Tools CC.

+ +

Permission is granted to copy, distribute, and/or modify this document + under the terms of the + MIT License. +

+ +

This document is available in the following formats: + XHTML, + PDF, and + PostScript.

"; + } + + 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/.gitignore b/cli/doc/guide/.gitignore deleted file mode 100644 index 239cc7f..0000000 --- a/cli/doc/guide/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.ps -*.pdf diff --git a/cli/doc/guide/guide.html2ps b/cli/doc/guide/guide.html2ps deleted file mode 100644 index a691002..0000000 --- a/cli/doc/guide/guide.html2ps +++ /dev/null @@ -1,63 +0,0 @@ -@html2ps { - option { - toc: hb; - colour: 1; - hyphenate: 1; - titlepage: 1; - } - - datefmt: "%B %Y"; - - titlepage { - content: " -
-

CLI Language

-

Getting Started Guide

-

 

-

 

-

 

-

 

-

 

-

 

-
-

Copyright © 2009-2020 Code Synthesis Tools CC.

- -

Permission is granted to copy, distribute, and/or modify this document - under the terms of the - MIT License. -

- -

This document is available in the following formats: - XHTML, - PDF, and - PostScript.

"; - } - - 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 deleted file mode 100644 index 675db03..0000000 --- a/cli/doc/guide/index.xhtml +++ /dev/null @@ -1,1336 +0,0 @@ - - - - - CLI Language Getting Started Guide - - - - - - - - - - - - - -
-
- -
- -
-
CLI Language
-
Getting Started Guide
- -

Copyright © 2009-2020 Code Synthesis Tools CC.

- -

Permission is granted to copy, distribute, and/or modify this document - under the terms of the - MIT License. -

- -

This document is available in the following formats: - XHTML, - PDF, and - PostScript.

- -
- -

Table of Contents

- - - - - - - - - - - - - -
1Introduction
2Hello World Example - - - - - - -
2.1Defining Command Line Interface
2.2Translating CLI Definitions to C++
2.3Implementing Application Logic
2.4Compiling and Running
2.5Adding Documentation
-
3CLI Language - - - - - - -
3.1Options Class Definition
3.2Option Definition
3.3Option Documentation
3.4Include Directive
3.5Namespace Definition
-
-
- - - -

1 Introduction

- -

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.

- -

Beyond this guide, you may also find the following sources of - information useful:

- -
    -
  • CLI - Compiler Command Line Manual
  • - -
  • The INSTALL file in the CLI distribution provides build - instructions for various platforms.
  • - -
  • The examples/ directory in the CLI distribution contains - a collection of examples and a README file with an overview of each - example.
  • - -
  • The cli-users - mailing list is the place to ask technical questions about the CLI language - and compiler. Furthermore, the - cli-users mailing - list archives may already have answers to some of your questions.
  • -
- - - - - -

2 Hello World Example

- -

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 hello example which can be found in the - examples/hello/ directory of the CLI distribution.

- -

2.1 Defining Command Line Interface

- -

Our hello application is going to print a greeting - line for each name supplied on the command line. It will also - support two command line options, --greeting - and --exclamations, that can be used to - customize the greeting line. The --greeting - option allows us to specify the greeting phrase instead of the - default "Hello". The --exclamations - option is used to specify how many exclamation marks should - be printed at the end of each greeting. We will also support - the --help option which triggers printing of the - usage information.

- -

We can now write a description of the above command line interface - in the CLI language and save it into hello.cli:

- -
-include <string>;
-
-class options
-{
-  bool --help;
-  std::string --greeting = "Hello";
-  unsigned int --exclamations = 1;
-};
-  
- -

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 - hello.cli to the command line interface described in - the preceding paragraphs. The next step is to translate this - interface specification to C++.

- -

2.2 Translating CLI Definitions to C++

- -

Now we are ready to translate hello.cli to C++. - To do this we invoke the CLI compiler from a terminal (UNIX) or - a command prompt (Windows): -

- -
-$ cli hello.cli
-  
- -

This invocation of the CLI compiler produces three C++ files: - hello.hxx hello.ixx, and - hello.cxx. You can change the file name extensions - for these files with the compiler command line options. See the - CLI - Compiler Command Line Manual for more information.

- -

The following code fragment is taken from hello.hxx; it - should give you an idea about what gets generated:

- -
-#include <string>
-
-class options
-{
-public:
-  options (int argc, char** argv);
-  options (int argc, char** argv, int& end);
-
-  // Option accessors.
-  //
-public:
-  bool
-  help () const;
-
-  const std::string&
-  greeting () const;
-
-  unsigned int
-  exclamations () const;
-
-private:
-  ..
-};
-  
- -

The options C++ class corresponds to the options - CLI class. For each option in this CLI class an accessor function is - generated inside the C++ class. The options C++ class also - defines a number of overloaded constructs that we can use to parse the - argc/argv array. Let's now see how we can use this generated - class to implement option parsing in our hello application.

- -

2.3 Implementing Application Logic

- -

At this point we have everything we need to implement our - application:

- -
-#include <iostream>
-#include "hello.hxx"
-
-using namespace std;
-
-void
-usage (ostream& os)
-{
-  os << "usage: driver [options] <names>" << endl
-     << "options:" << 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 << "no names provided" << endl;
-      usage (cerr);
-      return 1;
-    }
-
-    // Print the greetings.
-    //
-    for (int i = end; i < argc; i++)
-    {
-      cout << o.greeting () << ", " << argv[i];
-
-      for (unsigned int j = 0; j < o.exclamations (); j++)
-        cout << '!';
-
-      cout << endl;
-    }
-  }
-  catch (const cli::exception& e)
-  {
-    cerr << e << endl;
-    usage (cerr);
-    return 1;
-  }
-}
-
- -

At the beginning of our application we create the options - object which parses the command line. The end 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 cli::exception in case something goes - wrong, for example, an unknown option is specified or an option value - is invalid. -

- -

2.4 Compiling and Running

- -

After saving our application from the previous section in - driver.cxx, we are ready to build and run our program. - On UNIX this can be done with the following commands:

- -
-$ c++ -o driver driver.cxx hello.cxx
-
-$ ./driver world
-Hello, world!
-
-$ ./driver --greeting Hi --exclamations 3 John Jane
-Hi, John!!!
-Hi, Jane!!!
-  
- -

We can also test the error handling:

- -
-$ ./driver -n 3 Jane
-unknown option '-n'
-usage: driver [options] <names>
-options:
---help
---greeting <arg>
---exclamations <arg>
-
-$ ./driver --exclamations abc Jane
-invalid value 'abc' for option '--exclamations'
-usage: driver [options] <names>
-options:
---help
---greeting <arg>
---exclamations <arg>
-  
- -

2.5 Adding Documentation

- -

As we have seen in the previous sections, the options - C++ class provides the print_usage() 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:

- -
-$ ./driver --help
-usage: driver [options] <names>
-options:
---help
---greeting <arg>
---exclamations <arg>
-  
- -

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:

- -
-include <string>;
-
-class options
-{
-  bool --help {"Print usage information and exit."};
-
-  std::string --greeting = "Hello"
-  {
-    "<text>",
-    "Use <text> as a greeting phrase instead of the default \"Hello\"."
-  };
-
-  unsigned int --exclamations = 1
-  {
-    "<num>",
-    "Print <num> exclamation marks instead of 1 by default."
-  };
-};
-  
- -

If we now save this updated command line interface to - hello.cli and recompile our application, the usage - information printed by the program will look like this:

- -
-usage: driver [options] <names>
-options:
---help               Print usage information and exit.
---greeting <text>    Use <text> as a greeting phrase instead of the
-                     default "Hello".
---exclamations <num> Print <num> exclamation marks instead of 1 by
-                     default.
-  
- -

We can also generate the program documentation in the HTML - (--generate-html CLI option) and man page - (--generate-man CLI option) formats. For example:

- -
-$ cli --generate-html hello.cli
-  
- -

The resulting hello.html file contains the following - documentation:

- -
-
--help
-
Print usage information and exit.
- -
--greeting text
-
Use text as a greeting phrase instead of the default "Hello".
- -
--exclamations num
-
Print num exclamation marks instead of 1 by default.
- -
- -

This HTML fragment can be combined with custom prologue and epilogue - to create a complete program documentation - (--html-prologue/--html-epilogue options for the HTML - output, --man-prologue/--man-epilogue options for the - man page output). For an example of such complete documentation see - the CLI - Compiler Command Line Manual and the cli(1) man - page. For more information on the option documentation syntax, - see Section 3.3, Option Documentation.

- - - - -

3 CLI Language

- -

This chapter describes the CLI language and its mapping to C++. - A CLI file consists of zero or more Include - Directives followed by one or more Namespace Definitions - or Option Class Definitions. C and C++-style comments - can be used anywhere in the CLI file except in character and - string literals.

- -

3.1 Option Class Definition

- -

The central part of the CLI language is option class. An - option class contains one or more option definitions, for - example:

- -
-class options
-{
-  bool --help;
-  int --compression;
-};
-  
- -

If we translate the above CLI fragment to C++, we will get a C++ - class with the following interface:

- -
-class options
-{
-public:
-  options (int& 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& 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& argc,
-           char** argv,
-           int& 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& argc,
-           char** argv,
-           int& 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&,
-           cli::unknown_mode opt_mode = cli::unknown_mode::fail,
-           cli::unknown_mode arg_mode = cli::unknown_mode::stop);
-
-  options (const options&);
-
-  options&
-  operator= (const options&);
-
-public:
-  static void
-  print_usage (std::ostream&);
-
-public:
-  bool
-  help () const;
-
-  int
-  compression () const;
-};
-  
- - -

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 --generate-modifier CLI - compiler option is specified, modifier functions corresponding to option - definitions. It also defines a public static print_usage() - function that can be used to print the usage information for the options - defined by the class.

- -

The argc/argv arguments in the overloaded constructors - are used to pass the command line arguments array, normally as passed - to main(). The start 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 argv[0]. - The end 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 erase - argument is true, then the recognized options and their - values are removed from the argv array and the - argc count is updated accordingly.

- -

The opt_mode and arg_mode arguments - specify the parser behavior when it encounters an unknown option - and argument, respectively. The unknown_mode type - is part of the generated CLI runtime support code. It has the - following interface:

- -
-namespace cli
-{
-  class unknown_mode
-  {
-  public:
-    enum value
-    {
-      skip,
-      stop,
-      fail
-    };
-
-    unknown_mode (value v);
-    operator value () const;
-  };
-}
-  
- -

If the mode is skip, the parser skips an unknown - option or argument and continue parsing. If the mode is - stop, the parser stops the parsing process. The - position of the unknown entity is stored in the end - argument. If the mode is fail, the parser throws the - cli::unknown_option or cli::unknown_argument - exception (described blow) on encountering an unknown option or argument, - respectively.

- -

Instead of the argc/argv arguments, the last overloaded - constructor accepts the cli::scanner object. It is part - of the generated CLI runtime support code and has the following - abstract interface:

- -
-namespace cli
-{
-  class scanner
-  {
-  public:
-    virtual bool
-    more () = 0;
-
-    virtual const char*
-    peek () = 0;
-
-    virtual const char*
-    next () = 0;
-
-    virtual void
-    skip () = 0;
-  };
-}
-  
- -

The CLI runtime also provides two implementations of this interface: - cli::argv_scanner and cli::argv_file_scanner. - The first implementation is a simple scanner for the argv - array (it is used internally by all the other constructors) and has the - following interface:

- -
-namespace cli
-{
-  class argv_scanner
-  {
-  public:
-    argv_scanner (int& argc, char** argv, bool erase = false);
-    argv_scanner (int start, int& argc, char** argv, bool erase = false);
-
-    int
-    end () const;
-
-    ...
-  };
-}
-  
- -

The cli::argv_file_scanner implementation provides - support for reading command line arguments from the argv - array as well as files specified with command line options. It is - generated only if explicitly requested with the - --generate-file-scanner CLI compiler option and has - the following interface:

- -
-namespace cli
-{
-  class argv_file_scanner
-  {
-  public:
-    argv_file_scanner (int& argc,
-                       char** argv,
-                       const std::string& option,
-                       bool erase = false);
-
-    argv_file_scanner (int start,
-                       int& argc,
-                       char** argv,
-                       const std::string& 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& argc,
-                       char** argv,
-                       const option_info* options,
-                       std::size_t options_count,
-                       bool erase = false);
-
-    argv_file_scanner (int start,
-                       int& argc,
-                       char** argv,
-                       const option_info* options,
-                       std::size_t options_count,
-                       bool erase = false);
-    ...
-  };
-}
-  
- -

The option argument in the first two constructors and - the options and options_count 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 # are ignored. Option values can - be enclosed in double (") or single (') - 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 - '"x"'. Non-leading and non-trailing quotes are interpreted - as being part of the option value.

- -

The semantics of providing options in a file is equivalent to providing - the same set of options in the same order on the command line at the - point where the 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.

- -

The parsing constructor (those with the argc/argv or - cli::scanner arguments) can throw the following exceptions: cli::unknown_option, - cli::unknown_argument, cli::missing_value, and - cli::invalid_value. The first two exceptions are thrown - on encountering unknown options and arguments, respectively, as - described above. The missing_value exception is thrown when - an option value is missing. The invalid_value exception is - thrown when an option value is invalid, for example, a non-integer value - is specified for an option of type int.

- -

Furthermore, all scanners (and thus the parsing constructors that - call them) can throw the cli::eos_reached exception - which indicates that one of the peek(), next(), - or skip() functions were called while more() - returns false. Catching this exception normally indicates an - error in an option parser implementation. The argv_file_scanner - class can also throw the cli::file_io_failure exception - which indicates that a file could not be opened or there was a reading - error as well as the cli::unmatched_quote exception - which indicates that an unmatched leading or trailing quote was - found in an option value.

- -

All CLI exceptions are derived from the common cli::exception - class which implements the polymorphic std::ostream insertion. - For example, if you catch the cli::unknown_option - exception as cli::exception and print it to - std::cerr, you will get the error message corresponding - to the unknown_option exception.

- -

The exceptions described above are part of the generated CLI runtime - support code and have the following interfaces:

- -
-#include <exception>
-
-namespace cli
-{
-  class exception: public std::exception
-  {
-  public:
-    virtual void
-    print (std::ostream&) const = 0;
-  };
-
-  inline std::ostream&
-  operator<< (std::ostream& os, const exception& e)
-  {
-    e.print (os);
-    return os;
-  }
-
-  class unknown_option: public exception
-  {
-  public:
-    unknown_option (const std::string& option);
-
-    const std::string&
-    option () const;
-
-    virtual void
-    print (std::ostream&) const;
-
-    virtual const char*
-    what () const throw ();
-  };
-
-  class unknown_argument: public exception
-  {
-  public:
-    unknown_argument (const std::string& argument);
-
-    const std::string&
-    argument () const;
-
-    virtual void
-    print (std::ostream&) const;
-
-    virtual const char*
-    what () const throw ();
-  };
-
-  class missing_value: public exception
-  {
-  public:
-    missing_value (const std::string& option);
-
-    const std::string&
-    option () const;
-
-    virtual void
-    print (std::ostream&) const;
-
-    virtual const char*
-    what () const throw ();
-  };
-
-  class invalid_value: public exception
-  {
-  public:
-    invalid_value (const std::string& option,
-                   const std::string& value);
-
-    const std::string&
-    option () const;
-
-    const std::string&
-    value () const;
-
-    virtual void
-    print (std::ostream&) const;
-
-    virtual const char*
-    what () const throw ();
-  };
-
-  class eos_reached: public exception
-  {
-  public:
-    virtual void
-    print (std::ostream&) const;
-
-    virtual const char*
-    what () const throw ();
-  };
-
-  class file_io_failure: public exception
-  {
-  public:
-    file_io_failure (const std::string& file);
-
-    const std::string&
-    file () const;
-
-    virtual void
-    print (std::ostream&) const;
-
-    virtual const char*
-    what () const throw ();
-  };
-
-  class unmatched_quote: public exception
-  {
-  public:
-    unmatched_quote (const std::string& argument);
-
-    const std::string&
-    argument () const;
-
-    virtual void
-    print (std::ostream&) const;
-
-    virtual const char*
-    what () const throw ();
-  };
-}
-  
- - -

3.2 Option Definition

- -

An option definition consists of four components: type, - name, default value, and documentation. - An option type can be any C++ type as long as its string representation - can be parsed using the std::istream interface. If the option - type is user-defined then you will need to include its declaration using - the Include Directive.

- -

An option of a type other than bool is expected to - have a value. An option of type bool 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 - true.

- -

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 |. The C++ accessor and modifier function names are - derived from the first name by removing any leading special characters, - such as -, /, etc., and replacing special - characters in other places with underscores. For example, the following - option definition:

- -
-class options
-{
-  int --compression-level | --comp | -c;
-};
-  
- -

Will result in the following accessor function:

- -
-class options
-{
-  int
-  compression_level () const;
-};
-  
- -

While any option alias can be used on the command line to specify - this option's value.

- -

If the option name conflicts with one of the CLI language keywords, - it can be specified as a string literal:

- -
-class options
-{
-  bool "int";
-};
-  
- -

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 bool option will be initialized to false, - an int option will be initialized to 0, etc.

- -

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:

- -
-include <string>;
-
-class options
-{
-  int -i1 = 5;
-  int -i2 (5);
-
-  std::string -s1 = "John";
-  std::string -s2 ("Mr John Doe", 8, 3);
-};
-  
- -

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:

- -
-include "constants.hxx"; // Defines default_value.
-
-class options
-{
-  int -a = default_value;
-  int -b (25 * 4);
-  int -c = (25 / default_value + 3);
-};
-  
- -

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 std::vector, std::set, and - std::map.

- -

When std::vector or std::set 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, - std::vector will contain all the values, including - duplicates while std::set will contain all the unique - values. For example:

- -
-include <set>;
-include <vector>;
-
-class options
-{
-  std::vector<int> --vector | -v;
-  std::set<int> --set | -s;
-};
-  
- -

If we have a command line like this: - -v 1 -v 2 -v 1 -s 1 -s 2 -s 1, then the vector returned - by the vector() accessor function will contain three - elements: 1, 2, and 1 while - the set returned by the set() accessor will contain - two elements: 1 and 2.

- -

When std::map is specified as an option type, the option - value is expected to have two parts: the key and the value, separated - by =. All the option values are then parsed into key/value - pairs and inserted into the map. For example:

- -
-include <map>;
-include <string>;
-
-class options
-{
-  std::map<std::string, std::string> --map | -m;
-};
-  
- -

The possible option values for this interface are: -m a=A, - -m =B (key is an empty string), -m c= (value - is an empty string), or -m d (same as -m d=).

- -

The last component in the option definition is optional documentation. - It is discussed in the next section.

- -

3.3 Option Documentation

- -

Option documentation mimics C++ string array initialization: - it is enclosed in {} and consists of one or more - documentation strings separated by a comma, for example:

- -
-class options
-{
-  int --compression = 5
-  {
-    "<level>",
-    "Set compression to <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."
-  };
-};
-  
- -

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 bool (options of type - bool are flags and don't have an explicit value). - The second string (or the first string for options of type - bool) 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 bool), then the second (first) string is - assumed to be the long documentation string.

- -

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 - --long-usage CLI compiler option. When generating - the program documentation, the long documentation strings are - always used.

- -

The value documentation string can contain text enclosed in - <> 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 level - value for the --compression option presented above - will be displayed as <level> while in the HTML and - man page output it will be typeset in italic as - level. Here is another example using the - std::map type:

- -
-include <map>;
-include <string>;
-
-class options
-{
-  std::map<std::string, std::string> --map
-  {
-    "<key>=<value>",
-    "Add the <key>, <value> pair to the map."
-  };
-};
-  
- -

The resulting HTML output for this option would look like this:

- -
-
--map key=value
-
Add the key, value pair to the map.
-
- -

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 - \c{} block. Similarly, text can be typeset in bold or - italic fonts using the \b{} and \i{} blocks, - respectively. You can also combine several font properties in a single - block, for example, \cb{bold code}. If you need to include - literal } in a formatting block, you can use the - \} escape sequence, for example, - \c{int a[] = {1, 2\}}. The following example shows how we - can use these mechanisms:

- -
-class options
-{
-  int --compression = 5
-  {
-    "<level>",
-    "Set compression to <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}."
-  };
-};
-  
- -

The resulting HTML output for this option would look like this:

- -
-
--compression level
-
Set compression to 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.

-
- -

3.4 Include Directive

- -

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 < > or - " "-enclosed paths. The CLI compiler does not - actually open or read these files. Instead, the include directives - are translated to C++ preprocessor #include directives - in the generated C++ header file. For example, the following CLI - definition:

- -
-include <string>;
-include "types.hxx"; // Defines the name_type class.
-
-class options
-{
-  std::string --string;
-  name_type --name;
-};
-  
- -

Will result in the following C++ header file:

- -
-#include <string>
-#include "types.hxx"
-
-class options
-{
-  ...
-
-  const std::string&
-  string () const;
-
-  const name_type&
-  name () const;
-
-  ...
-};
-  
- -

Without the #include directives the std::string - and name_type types in the options class would - be undeclared and result in compilation errors.

- -

3.5 Namespace Definition

- -

Option classes can be placed into namespaces which are translated - directly to C++ namespaces. For example:

- -
-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;
-    };
-  }
-}
-  
- -

The above CLI namespace structure would result in the equivalent C++ - namespaces structure:

- -
-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;
-    };
-  }
-}
-  
- - -
-
- - - - -- cgit v1.1