ROSE 0.11.145.147
Classes | Functions | Variables
Rose::CommandLine Namespace Reference

Description

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.

User perspective

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:

Note
As you can see, single-character switches are not very self-documenting and can be confusing to users. It is best for tools to use mostly multi-character switches, reserving single-letter switches for extremely common and often used purposes like "-h" for "--help" or "-V" for "--version".

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".

Programmer perspective

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.

Note
Here's an example demonstrating how a parser stage can be unsound. If "-log" is a defined switch that takes one argument, and "-yaxis" is undefined but takes as an argument a sign ("+" or "-") followed by the word "linear" or "log", then the command "a.out -yaxis -log foo bar" will be parsed as having an undefined switch "-yaxis" followed by the switch "-log" whose argument is "foo", followed by one positional argument "bar". The correct parsing, had yaxis been defined, would have been the switch "-yaxis" whose argument is "-log" followed by two positional arguments "foo" and "bar".

To meet the goals from a programmer's perspective, the following design should be used for ROSE-based tools and ROSE library components:

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:

// Given a command-line switch parser (parser) and a command-line (argc, argv):
// + try to parse the command-line without any side effects
// + if successful, try to push the switch arguments to their defined storage locations
// and also execute any defined actions (for things like "--help")
// + if successful, return the positional arguments that follow the switches
// + if an error occurs at any step, print an error message and fail
std::vector<std::string> args = parser.parse(argc, argv).apply().unreachedArgs();

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::PtrselfTests
 Collection of self tests to be run by –self-tests switch.
 
ROSE_DLL_API std::string versionString
 Global location for version string.
 

Function Documentation

◆ durationParser() [1/2]

DurationParser::Ptr Rose::CommandLine::durationParser ( uint64_t &  storage)

Constructs a DurationParser.

When the parser runs, it stores the parsed result in storage.

◆ durationParser() [2/2]

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() [1/4]

template<class Interval >
IntervalParser< Interval >::Ptr Rose::CommandLine::intervalParser ( Interval &  storage)

Definition at line 231 of file IntervalParser.h.

◆ intervalParser() [2/4]

template<class Interval >
IntervalParser< Interval >::Ptr Rose::CommandLine::intervalParser ( std::vector< Interval > &  storage)

Definition at line 236 of file IntervalParser.h.

◆ intervalParser() [3/4]

template<class Interval >
IntervalParser< Interval >::Ptr Rose::CommandLine::intervalParser ( Sawyer::Container::IntervalSet< Interval > &  storage)

Definition at line 241 of file IntervalParser.h.

◆ intervalParser() [4/4]

template<class Interval >
IntervalParser< Interval >::Ptr Rose::CommandLine::intervalParser ( )

Definition at line 247 of file IntervalParser.h.

◆ createEmptyParser()

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.

◆ 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.

◆ 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:

  • Actions: switches that cause some special action to be performed such as showing the documentation or version number, or running self-tests. If such a switch is specified, its action is performed instead of the tools normal action.
  • Adjustments: switches that cause a tool-wide adjustment in behavior, such as how internal program logic errors are handled or what diagnostic facilities are enabled.
  • Defaults: switches that provide default values for multiple software components, such as the maximum number of threads that a parallel analysis can use, or the name of the default SMT solver connection. These defaults are generic in the sense that they don't prescribe requirements for all components–they only provide defaults for those components that don't otherwise have a command-line setting.

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:

parseCommandLine(int argc, char *argv[]) {
return parser
.with(Rose::CommandLine::genericSwitches()) // these generic switches
.with(mySwitches) // my own switches, etc.
.parse(argc, argv) // parse without side effects
.apply(); // apply parser results
}
The result from parsing a command line.
const ParserResult & apply() const
Saves parsed values in switch-specified locations.
The parser for a program command line.
Parser & with(const SwitchGroup &sg)
Add switch declarations.
ParserResult parse(int argc, char *argv[])
Parse program arguments.
ROSE_DLL_API Sawyer::CommandLine::Parser createEmptyParser(const std::string &purpose, const std::string &description)
Empty command-line parser.
ROSE_DLL_API Sawyer::CommandLine::SwitchGroup genericSwitches()
Generic command-line components.

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:

Sawyer::CommandLine::Parser p = createParser(purpose, description).with(genericSwitches());
p.removeMatchingSwitch("--threads=1"); // must parse
Sawyer::Optional< Switch > removeMatchingSwitch(const std::string &arg)
Remove the switch by matching parse sentence.

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.

◆ insertBooleanSwitch()

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.

◆ runSelfTestsAndExit()

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.

◆ insertSelfTest()

template<class SelfTest >
void Rose::CommandLine::insertSelfTest ( )

Convenient way to add a command-line self test.

Definition at line 49 of file SelfTest.h.

References selfTests.

◆ suffixMultiplierParser() [1/3]

template<class T >
SuffixMultiplierParser< T >::Ptr Rose::CommandLine::suffixMultiplierParser ( T &  storage)

Definition at line 321 of file SuffixMultiplierParser.h.

◆ suffixMultiplierParser() [2/3]

template<class T >
SuffixMultiplierParser< T >::Ptr Rose::CommandLine::suffixMultiplierParser ( std::vector< T > &  storage)

Definition at line 326 of file SuffixMultiplierParser.h.

◆ suffixMultiplierParser() [3/3]

template<class T >
SuffixMultiplierParser< T >::Ptr Rose::CommandLine::suffixMultiplierParser ( )

Definition at line 331 of file SuffixMultiplierParser.h.

Variable Documentation

◆ licenseText

const char* Rose::CommandLine::licenseText
extern

Text of the ROSE software license.

This text comes directly from the LicenseInformation/ROSE_BSD_License.txt file in the source code.

◆ genericSwitchArgs

ROSE_DLL_API GenericSwitchArgs Rose::CommandLine::genericSwitchArgs
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.

◆ selfTests

ROSE_DLL_API std::vector<SelfTest::Ptr> Rose::CommandLine::selfTests
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().

◆ versionString

ROSE_DLL_API std::string Rose::CommandLine::versionString
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.