ROSE 0.11.145.147
|
Command line parsing.
This namespace encapsulates those things necessary for parsing the command-line for a ROSE-based tool. Command-lines consist of switches and their arguments, and positional arguments. The command-line parsers in this class are mainly for parsing the switches and their arguments, while the remaining non-switch, positional arguments can be retreived for parsing in a per-tool specific manner.
This API is built on Sawyer::CommandLine, and more documentation and examples can be found there.
The user's perspective of a command-line parser is the ability to specify command-line switches and arguments when running a ROSE tool, and to be able to obtain detailed documentation about the tool and its command-line. The goals of this API are therefore
This API concentrates primarily on the parsing of command-line switches and their arguments, and not much on the parsing of non-switch, positional arguments.
A command-line switch consists of an introductory sequence of characters (usually a hyphen or two) followed by the switch name. If the switch takes an argument, the switch argument can be separated from the switch name with an equal sign or appear as its own command-line argument.
Examples of command-line switches from the user's perspective:
argv[i]
contains "--max" and argv[i+1]
contains "5".The arguments for switches have their own sub-parsers. Predefined parsers exist for integers, non-negative integers, floating-point, colors, ranges, time durations, arbitrary strings, lists, enumerated strings, and more. If a switch doesn't have an explicit argument, it might have an implicit argument such as a Boolean to indicate whether it was specified. Implicit Boolean arguments are also often used for pairs of switches like "--verbose" vs. "--quiet", or "--optimize" vs. "--no-optimize".
Related switches (such as those for a single analysis in a tool having multiple analyses) are collected into switch groups which also have names. For instance, if a tool has a stack-delta analysis and a tainted-flow analysis then it may wisely place all the stack-delta switches into a group named "stack" and all the tainted-flow switches into a group named "taint". Since both analyses are a kind of data-flow, they likely both have a "--maximum-iterations" switch that takes a non-negative integer argument to limit the search space. If the user invokes the tool with "--maximum-iterations=10" then an error will be emitted to indicate that the switch is ambiguous. Instead, the user should qualify the switch names as "--stack:maximum-iterations=10" and "--taint:maximum-iterations=20".
From a programming perspective, this API's goals are:
The Rose::CommandLine API builds upon Sawyer::CommandLine, which should be consulted for its API documentation and examples. The ROSE switch prefixes, argument separators, group delimiters, nestling behavior, etc. have been chosen in such a way as to give users a consistent experience across all ROSE tools using a grammer whose parsing is sound. Although these defaults can be changed through the Sawyer::CommandLine API, doing so for ROSE tools is discouraged.
The Sawyer::CommandLine has two main modes of operation called "pull" and "push". In "pull" mode, one parses a command-line and then queries a result object to obtain information about the switches and their arguments. This is how many non-Sawyer command-line parsers work, but is not the preferred mechanism in ROSE tools. Instead, ROSE tools should use the "push" mode, in which the command-line switches and their arguments are parsed and then programmer-supplied C++ variables are automatically updated with the results. The "push" mode of operation is what we describe below.
Parsers also come in two flavors. The first flavor, "normal parsers" (see createEmptyParser), are suitable for programs that are able to define all their legal switches. They parse command-line switches until they get to the first positional argument, or they can be configured to collect and skip over the positional arguments if desired. These parsers can be sound when they're able to distinguish between command-line switches and non-switch (positional) arguments and therefore this is the flavor your tools should strive to use. The other flavor, a "parser stage" (see createEmptyParserStage), is for programs that are unable or unwilling to define all their switches, in which case the parser will skip over (and save for later) things that it doesn't understand. A parser stage is generally unsound since it's essentially parsing two languages at once while knowing the syntax for only one of them.
To meet the goals from a programmer's perspective, the following design should be used for ROSE-based tools and ROSE library components:
Settings
struct that holds the settings that control how that component operates. These settings should all have reasonable default values. For instance, a data-flow analysis might have a data member size_t maxIterations = 1000;
Each of these data members will also have a command-line switch.commandLineSwitches
function that generates and returns a SwitchGroup that defines and documents all of the command-line switches for that component. The switch group should also document the component in general (besides describing each switch). If this is a static member function, then its argument should be a Settings
reference, otherwise it should adjust the settings in the object on which it was invoked. The switch documentation should indicate what the default values are for the various switch arguments, and it can obtain those values from the settings (passed by argument or part of this
component). The switch group should arrange to push parsed switched arguments to that same settings object.Settings
structs, it is permissible for a tool to adjust the defaults before generating the command-line switch parser. For instance, the default SMT solver (GenericSwitchArgs::smtSolver) is "none", but a tool might change the default to "best" before generating its command-line parser. Then, if the user doesn't specify an SMT solver with the "--smt-solver" switch, its value will still be "best" after parsing and the "--help" output may indicate that the default is "best".commandLineSwitches
function(s) mentioned above.Once a tool creates a command-line switch parser, there are a few steps to use it. In particular, parsing a command-line is a separate operation from storing/pushing the results of the parse to the various settings data members. This allows one to test whether a command-line is valid without having any side effects that might be difficult to undo. Parsing a command-line happens with the parse method, which returns a ParserResult object. The ParserResult object is not normally used directly in the "push" mode of operation, except that the results are pushed to C++ variables with its apply function. Finally, the tool needs to obtain the non-switch, positional arguments that appear after the switches. These steps are usually done in one statement like this:
Classes | |
class | DurationParser |
Command-line parser for durations. More... | |
struct | GenericSwitchArgs |
Type for storing generic switch arguments. More... | |
class | IntervalParser |
Parse an interval. More... | |
class | SelfTest |
Base class for self tests. More... | |
class | SelfTests |
Run self tests from the command-line, then exit. More... | |
class | ShowLicenseAndExit |
Show license text and exit. More... | |
class | SuffixMultiplierParser |
Parse values followed by unit names. More... | |
Functions | |
DurationParser::Ptr | durationParser () |
Constructs a DurationParser. | |
template<class Interval > | |
IntervalParser< Interval >::Ptr | intervalParser (Interval &storage) |
template<class Interval > | |
IntervalParser< Interval >::Ptr | intervalParser (std::vector< Interval > &storage) |
template<class Interval > | |
IntervalParser< Interval >::Ptr | intervalParser (Sawyer::Container::IntervalSet< Interval > &storage) |
template<class Interval > | |
IntervalParser< Interval >::Ptr | intervalParser () |
ROSE_DLL_API Sawyer::CommandLine::Parser | createEmptyParser (const std::string &purpose, const std::string &description) |
Empty command-line parser. | |
ROSE_DLL_API Sawyer::CommandLine::Parser | createEmptyParserStage (const std::string &purpose, const std::string &description) |
Empty command-line parser suitable for use with other parsers. | |
ROSE_DLL_API Sawyer::CommandLine::SwitchGroup | genericSwitches () |
Generic command-line components. | |
ROSE_DLL_API void | insertBooleanSwitch (Sawyer::CommandLine::SwitchGroup &, const std::string &switchName, bool &storageLocation, const std::string &documentation) |
Convenience for for adding Boolean switches. | |
ROSE_DLL_API void | runSelfTestsAndExit () |
Runs the self tests and then exits the program. | |
template<class SelfTest > | |
void | insertSelfTest () |
Convenient way to add a command-line self test. | |
template<class T > | |
SuffixMultiplierParser< T >::Ptr | suffixMultiplierParser (T &storage) |
template<class T > | |
SuffixMultiplierParser< T >::Ptr | suffixMultiplierParser (std::vector< T > &storage) |
template<class T > | |
SuffixMultiplierParser< T >::Ptr | suffixMultiplierParser () |
DurationParser::Ptr | durationParser (uint64_t &storage) |
Constructs a DurationParser. | |
DurationParser::Ptr | durationParser (Sawyer::Optional< uint64_t > &storage) |
Constructs a DurationParser. | |
Variables | |
const char * | licenseText |
Text of the ROSE software license. | |
ROSE_DLL_API GenericSwitchArgs | genericSwitchArgs |
Global location for parsed generic command-line switches. | |
ROSE_DLL_API std::vector< SelfTest::Ptr > | selfTests |
Collection of self tests to be run by –self-tests switch. | |
ROSE_DLL_API std::string | versionString |
Global location for version string. | |
DurationParser::Ptr Rose::CommandLine::durationParser | ( | uint64_t & | storage | ) |
Constructs a DurationParser.
When the parser runs, it stores the parsed result in storage
.
DurationParser::Ptr Rose::CommandLine::durationParser | ( | Sawyer::Optional< uint64_t > & | storage | ) |
Constructs a DurationParser.
When the parser runs, it stores the parsed result in storage
.
IntervalParser< Interval >::Ptr Rose::CommandLine::intervalParser | ( | Interval & | storage | ) |
Definition at line 231 of file IntervalParser.h.
IntervalParser< Interval >::Ptr Rose::CommandLine::intervalParser | ( | std::vector< Interval > & | storage | ) |
Definition at line 236 of file IntervalParser.h.
IntervalParser< Interval >::Ptr Rose::CommandLine::intervalParser | ( | Sawyer::Container::IntervalSet< Interval > & | storage | ) |
Definition at line 241 of file IntervalParser.h.
IntervalParser< Interval >::Ptr Rose::CommandLine::intervalParser | ( | ) |
Definition at line 247 of file IntervalParser.h.
ROSE_DLL_API Sawyer::CommandLine::Parser Rose::CommandLine::createEmptyParser | ( | const std::string & | purpose, |
const std::string & | description | ||
) |
Empty command-line parser.
Returns a command-line parser that has no switch declarations, but is set up consistently for ROSE tools. The purpose
should be an uncapitalized, short, single-line string that appears near the top of the man page. The description
can be much longer, multiple paragraphs, free-format, with Sawyer markup. It will appear under the heading "Description" in the man page.
See also, createEmptyParserStage.
ROSE_DLL_API Sawyer::CommandLine::Parser Rose::CommandLine::createEmptyParserStage | ( | const std::string & | purpose, |
const std::string & | description | ||
) |
Empty command-line parser suitable for use with other parsers.
Returns a command-line parser that has no switch declarations, but is set up consistently for ROSE tools. The parser is configured to skip over any program arguments it doesn't recognize, with the assumption that those arguments will be passed to another parser. This also means that this parser cannot report errors for misspelled or misused switches because it cannot tell whether the switch is misspelled or simply intended for the next parser.
The purpose
should be an uncapitalized, short, single-line string that appears near the top of the man page. The description
can be much longer, multiple paragraphs, free-format, with Sawyer markup. It will appear under the heading "Description" in the man page.
See also, createEmptyParser, genericSwitches.
ROSE_DLL_API Sawyer::CommandLine::SwitchGroup Rose::CommandLine::genericSwitches | ( | ) |
Generic command-line components.
Returns a description of the switches that should be available for all ROSE tools. For consistency's sake, most tools will want to have at least this set of switches which is intended to be common across all tools. These switches fall into some categories:
To make a command-line parser that recognizes these switches, add the switches to the parser using its with
method. For example, here's how to construct a parser that recognizes only these switches:
In general, we want all tools to have all these switches. At a minimum, a tool developer should be aware that the switches in this group are in some sense reserved across all tools and should not be circumvented for other purposes. However, if a tool doesn't use a switch, the developer can remove that switch from the parser and its documentation in order to prevent user confusion. Here's an example of removing the "--threads" switch from a parser for a tool that doesn't support multiple threads:
If you encounter strange errors near this call, make sure you're using -pthread consistently in your compile and link commands. Its presence or absence should be the same as however the ROSE library itself was compiled and linked. Mixing up the -pthread switch creates ABI incompatibilities that manifest themselves in various ways that usually look like a problem with a function that's called from a program that uses librose: often a segmentation fault, but can also be hangs, incorrect results, etc. Note that -pthread is both a compile and a link switch.
See any recent tool for more examples.
See also, createEmptyParser, createEmptyParserStage.
ROSE_DLL_API void Rose::CommandLine::insertBooleanSwitch | ( | Sawyer::CommandLine::SwitchGroup & | , |
const std::string & | switchName, | ||
bool & | storageLocation, | ||
const std::string & | documentation | ||
) |
Convenience for for adding Boolean switches.
Adds "--foo" (if switchName
is "foo") and "--no-foo" to the specified switch group. The storage location's lifetime must extend to the point where the command-line is parsed. This function adds additional documentation describing how to disable the switch using "--no-foo" and what the default is (current value of storage location).
An alternative is to use a switch that takes a Boolean argument (e.g., "--foo=yes" or "--foo=no"), but this is more difficult for users to remember and type than just "--foo" and "--no-foo".
See also, createEmptyParser, createEmptyParserStage.
ROSE_DLL_API void Rose::CommandLine::runSelfTestsAndExit | ( | ) |
Runs the self tests and then exits the program.
Sequentially runs the self tests in selfTests
and then exits. Exit status is success if and only if no test returns false. Tests that are null pointers are ignored.
void Rose::CommandLine::insertSelfTest | ( | ) |
Convenient way to add a command-line self test.
Definition at line 49 of file SelfTest.h.
References selfTests.
SuffixMultiplierParser< T >::Ptr Rose::CommandLine::suffixMultiplierParser | ( | T & | storage | ) |
Definition at line 321 of file SuffixMultiplierParser.h.
SuffixMultiplierParser< T >::Ptr Rose::CommandLine::suffixMultiplierParser | ( | std::vector< T > & | storage | ) |
Definition at line 326 of file SuffixMultiplierParser.h.
SuffixMultiplierParser< T >::Ptr Rose::CommandLine::suffixMultiplierParser | ( | ) |
Definition at line 331 of file SuffixMultiplierParser.h.
|
extern |
Text of the ROSE software license.
This text comes directly from the LicenseInformation/ROSE_BSD_License.txt file in the source code.
|
extern |
Global location for parsed generic command-line switches.
This global variable holds the results of command-line parsing using genericSwitches. Normally these settings are passed per command-line parsing request, but the interface in ROSE doesn't have that ability yet, so we use a global variable.
See also, genericSwitches.
|
extern |
Collection of self tests to be run by –self-tests switch.
The unit tests are run sequentially from first to last, optionally stopping at the first test that fails. Null pointers are ignored without causing any failure.
Referenced by insertSelfTest().
|
extern |
Global location for version string.
This is the string that's printed by the –version switch (usually). It defaults to the ROSE library version number, but can be overridden by tools. When overriding, the tool should change this version string before constructing the command-line parser.
See also, genericSwitches.