ROSE  0.11.96.11
Namespaces | Classes | Typedefs | Enumerations | Functions | Variables
Sawyer::CommandLine Namespace Reference

Description

Parses program command line switches and arguments.

Definitions

The major parts of the API

Program command-line parsing consists of the following major components:

Description

The library is used in three phases: first, the command line is described in terms of switches and their arguments; then a parser is constructed and applied to the command line to obtain a result; and finally, the result is used by querying or pushing results into variables.

Some of our goals in designing this library were influenced by other libraries. We wanted to take the good ideas of others but avoid the same pitfalls. Our goals are:

An example

Here's an example to give the basic flavor of the library. The description of the command-line and the parsing of the command-line are combined in a single function, parseCommandLine:

parseCommandLine(int argc, char *argv[], Settings &settings) {
using namespace Sawyer::CommandLine;

We'll divide the command-line into two groups of switches: switches that are common to all our tools, and switches that are specific to this particular tool. In real life, the common switches would be returned from some other function defined in a library that all the tools share. Each switch group may have its own documentation, which causes its switches to be grouped together in the manual page. Documentation is free-flowing and automatically wrapped to the width of the terminal window in which the command runs, so there is no need to have line feeds within the source code string literals, although they are allowed. A double line feed in the documentation string is a paragraph separator.

SwitchGroup standard;
standard.doc("The following switches are recognized by all tools in this package.");

Now we can declare a couple switches inside our standard switch group. We'll declare one that will show the manual page, and another that shows the version number. The man page is shown with –help, -h, or -?, and the version is shown with –version or -V. Switch actions occur only when switch parsing is all done (i.e., the man page won't be emitted unless the command-line is parsable).

standard.insert(Switch("help", 'h')
.shortName('?')
.action(showHelpAndExit(0))
.doc("Show this documentation."));
standard.insert(Switch("version", 'V')
.action(showVersionAndExit("1.2.3", 0))
.doc("Show version number."));

We place all the tool-specific switches in another switch group we call tool. The –isa switch will accept an argument that can be anything and is stored in std::string settings.isaName. If the argument is the word "list" then the function that eventually parses it will generate a list (this function is part of the tool source code and is not part of Sawyer).

SwitchGroup tool;
tool.doc("The following switches are specific to this command.");
tool.insert(Switch("isa")
.argument("architecture", anyParser(settings.isaName))
.doc("Instruction set architecture. Specify \"list\" to see "
"a list of possible ISAs."));

The next two switches are similar except they expect arguments that are non-negative integers. The argument will be parsed by Sawyer, which accepts decimal, octal, and hexadecimal using C syntax, and eventually assigned to the specified settings data member, both of which are of type unsigned long. The parser function, nonNegativeIntegerParser, is overloaded to accept a variety of integer types and a parsing exception will be thrown if the argument string parses to a value which doesn't fit in the specified variable.

tool.insert(Switch("at")
.argument("virtual-address", nonNegativeIntegerParser(settings.startVa))
.doc("The first byte of the file is mapped at the specified "
"@v{virtual-address}, which defaults to " +
boost::lexical_cast<std::string>(settings.startVa) + "."));
tool.insert(Switch("alignment")
.argument("align", nonNegativeIntegerParser(settings.alignment))
.doc("Alignment for instructions. The default is 1 (no alignment). Values "
"larger than one will cause each candidate address to be rounded up to "
"the next multiple of @v{align}. If this rounding up causes addresses "
"after a valid instruction to be skipped then a warning is printed. "
"No warning is printed if the alignment skips addresses after a "
"disassembly failure."));

Now that the command-line switches are described, we can create a parser. The parser also controls the non-switch aspects of the manual page, such as the heading and footer, purpose, synopsis, and other sections.

Parser parser;
parser
.purpose("disassembles files one address at a time")
.doc("synopsis",
"@prop{programName} [@v{switches}] @v{specimen_name}")
.doc("description",
"This program is a very simple disassembler that tries to disassemble an "
"instruction at each address of the specimen file.");

Finally we can do the actual parsing. We could split this statement into multiple statements, but one of Sawyer's idioms is to chain things together in a functional programming style. The with method inserts our switch declarations from above into the parser; the parse method, of which there are multiple overloaded varieties, does the real work; and the apply method applies the results of a successful parse by copying values into the variabiables we specified, and running switch actions (e.g., "help" and "version") if necessary.

return parser.with(standard).with(tool).parse(argc, argv).apply();
}

Here's the whole example in one shot (the docs/examples/commandLineEx1.C file):

1 #include <Sawyer/CommandLine.h>
2 #include <iostream>
3 
4 struct Disassembler {};
5 struct DisassemblerArm: Disassembler {};
6 struct DisassemblerPowerpc: Disassembler {};
7 struct DisassemblerMips: Disassembler {};
8 struct DisassemblerI386: Disassembler {};
9 struct DisassemblerAmd64: Disassembler {};
10 struct DisassemblerM68k: Disassembler {};
11 struct DisassemblerColdFire: Disassembler {};
12 
13 // Convenient struct to hold settings from the command-line all in one place.
14 struct Settings {
15  std::string isaName;
16  unsigned long startVa;
17  unsigned long alignment;
18  Settings(): startVa(0), alignment(1) {}
19 };
20 
21 static Disassembler *
22 getDisassembler(const std::string &name)
23 {
24  if (0==name.compare("list")) {
25  std::cout <<"The following ISAs are supported:\n"
26  <<" amd64\n"
27  <<" arm\n"
28  <<" coldfire\n"
29  <<" i386\n"
30  <<" m68040\n"
31  <<" mips\n"
32  <<" ppc\n";
33  exit(0);
34  } else if (0==name.compare("arm")) {
35  return new DisassemblerArm();
36  } else if (0==name.compare("ppc")) {
37  return new DisassemblerPowerpc();
38  } else if (0==name.compare("mips")) {
39  return new DisassemblerMips();
40  } else if (0==name.compare("i386")) {
41  return new DisassemblerI386();
42  } else if (0==name.compare("amd64")) {
43  return new DisassemblerAmd64();
44  } else if (0==name.compare("m68040")) {
45  return new DisassemblerM68k();
46  } else if (0==name.compare("coldfire")) {
47  return new DisassemblerColdFire();
48  } else {
49  throw std::runtime_error("invalid ISA name \""+name+"\"; use --isa=list");
50  }
51 }
52 
55 parseCommandLine(int argc, char *argv[], Settings &settings) {
56  using namespace Sawyer::CommandLine;
58 
60  SwitchGroup standard;
61  standard.doc("The following switches are recognized by all tools in this package.");
63 
65  standard.insert(Switch("help", 'h')
66  .shortName('?')
67  .action(showHelpAndExit(0))
68  .doc("Show this documentation."));
69 
70  standard.insert(Switch("version", 'V')
71  .action(showVersionAndExit("1.2.3", 0))
72  .doc("Show version number."));
74 
75 
77  SwitchGroup tool;
78  tool.doc("The following switches are specific to this command.");
79 
80  tool.insert(Switch("isa")
81  .argument("architecture", anyParser(settings.isaName))
82  .doc("Instruction set architecture. Specify \"list\" to see "
83  "a list of possible ISAs."));
85 
87  tool.insert(Switch("at")
88  .argument("virtual-address", nonNegativeIntegerParser(settings.startVa))
89  .doc("The first byte of the file is mapped at the specified "
90  "@v{virtual-address}, which defaults to " +
91  boost::lexical_cast<std::string>(settings.startVa) + "."));
92 
93  tool.insert(Switch("alignment")
94  .argument("align", nonNegativeIntegerParser(settings.alignment))
95  .doc("Alignment for instructions. The default is 1 (no alignment). Values "
96  "larger than one will cause each candidate address to be rounded up to "
97  "the next multiple of @v{align}. If this rounding up causes addresses "
98  "after a valid instruction to be skipped then a warning is printed. "
99  "No warning is printed if the alignment skips addresses after a "
100  "disassembly failure."));
102 
104  Parser parser;
105  parser
106  .purpose("disassembles files one address at a time")
107  .doc("synopsis",
108  "@prop{programName} [@v{switches}] @v{specimen_name}")
109  .doc("description",
110  "This program is a very simple disassembler that tries to disassemble an "
111  "instruction at each address of the specimen file.");
113 
115  return parser.with(standard).with(tool).parse(argc, argv).apply();
116 }
118 
119 int main(int argc, char *argv[])
120 {
121  // Parse the command-line
122  Settings settings;
123  Sawyer::CommandLine::ParserResult cmdline = parseCommandLine(argc, argv, settings);
124  std::vector<std::string> positionalArgs = cmdline.unreachedArgs();
125 
126  // Obtain a disassembler (do this before opening the specimen so "--isa=list" has a chance to run)
127  Disassembler *disassembler = getDisassembler(settings.isaName);
128  ASSERT_always_not_null(disassembler);
129 
130  // Open the file that needs to be disassembled
131  if (positionalArgs.empty())
132  throw std::runtime_error("no file name specified; see --help");
133  if (positionalArgs.size()>1)
134  throw std::runtime_error("too many files specified; see --help");
135  std::string specimenName = positionalArgs[0];
136 
137  return 0;
138 }

And here's the output from the –help switch:

COMMANDLINEEX1(1)                User Commands               COMMANDLINEEX1(1)



Name
       commandLineEx1 - disassembles files one address at a time

Synopsis
       commandLineEx1 [switches] specimen_name

Description
       This program is a very simple disassembler that tries to disassemble an
       instruction at each address of the specimen file.

Options
       The following switches are recognized by all tools in this package.

       --help; -h; -?
           Show this documentation.

       --version; -V
           Show version number.

       The following switches are specific to this command.

       --alignment align
           Alignment for instructions.  The default is 1 (no alignment).
           Values larger than one will cause each candidate address to be
           rounded up to the next multiple of align.  If this rounding up
           causes addresses after a valid instruction to be skipped then a
           warning is printed. No warning is printed if the alignment skips
           addresses after a disassembly failure.

       --at virtual-address
           The first byte of the file is mapped at the specified virtual-
           address, which defaults to 0.

       --isa architecture
           Instruction set architecture. Specify "list" to see a list of
           possible ISAs.



alpha                              July 2014                 COMMANDLINEEX1(1)

Namespaces

 Boost
 Drop-in replacement to help boost users.
 

Classes

class  AnyParser
 Parses any argument as plain text. More...
 
class  BooleanParser
 Parses a boolean value and converts it to numeric type T. More...
 
class  ConfigureDiagnostics
 Functor to configure diagnostics. More...
 
class  ConfigureDiagnosticsQuiet
 Function to configure diagnostics to quiet mode. More...
 
class  Cursor
 Input stream for command line arguments. More...
 
class  EnumParser
 Parses an enumerated constant. More...
 
class  ExcursionGuard
 Guards a cursor and restores it when the guard is destroyed. More...
 
class  IntegerParser
 Parses an integer and converts it to numeric type T. More...
 
struct  LexicalCast
 
struct  LexicalCast< boost::any >
 
struct  LexicalCast< boost::filesystem::path >
 
struct  LexicalCast< boost::regex >
 
struct  LexicalCast< Optional< T > >
 
struct  LexicalCast< Sawyer::Container::Map< std::string, T > >
 
struct  LexicalCast< Sawyer::Container::Set< T > >
 
struct  LexicalCast< std::list< T > >
 
struct  LexicalCast< std::map< std::string, T > >
 
struct  LexicalCast< std::regex >
 
struct  LexicalCast< std::set< T > >
 
struct  LexicalCast< std::vector< T > >
 
class  ListParser
 Parses a list of values. More...
 
struct  Location
 Position within a command-line. More...
 
class  NonNegativeIntegerParser
 Parses a non-negative integer and converts it to numeric type T. More...
 
struct  NumericCast
 
struct  NumericCast< Optional< Target >, Source >
 
struct  NumericCast< Sawyer::Container::Map< std::string, Target >, Source >
 
struct  NumericCast< Sawyer::Container::Set< Target >, Source >
 
struct  NumericCast< std::list< Target >, Source >
 
struct  NumericCast< std::map< std::string, Target >, Source >
 
struct  NumericCast< std::set< Target >, Source >
 
struct  NumericCast< std::vector< Target >, Source >
 
class  ParsedValue
 Information about a parsed switch value. More...
 
class  Parser
 The parser for a program command line. More...
 
class  ParserResult
 The result from parsing a command line. More...
 
struct  ParsingProperties
 
class  PositiveIntegerParser
 Parses a positive integer and converts it to numeric type T. More...
 
class  RealNumberParser
 Parses a real number and converts it to numeric type T. More...
 
class  ShowHelp
 Functor to print the Unix man page. More...
 
class  ShowHelpAndExit
 Functor to print the Unix man page and exit. More...
 
class  ShowVersion
 Functor to print a version string. More...
 
class  ShowVersionAndExit
 Functor to print a version string and exit. More...
 
class  StringSetParser
 Parses any one of a set of strings. More...
 
class  Sum
 Sums all previous and current values. More...
 
class  Switch
 Describes one command-line switch. More...
 
class  SwitchAction
 Base class for switch actions. More...
 
class  SwitchArgument
 Describes one argument of a command-line switch. More...
 
class  SwitchGroup
 A collection of related switch declarations. More...
 
class  TypedSaver
 
class  TypedSaver< BitFlags< T > >
 
class  TypedSaver< Optional< T > >
 
class  TypedSaver< Sawyer::Container::IntervalSet< Interval > >
 
class  TypedSaver< Sawyer::Container::Map< std::string, T > >
 
class  TypedSaver< Sawyer::Container::Set< T > >
 
class  TypedSaver< std::list< T > >
 
class  TypedSaver< std::map< std::string, T > >
 
class  TypedSaver< std::set< T > >
 
class  TypedSaver< std::vector< T > >
 
class  UserAction
 Wrapper around a user functor. More...
 
class  ValueAugmenter
 Base class for value agumentors. More...
 
class  ValueParser
 Base class parsing a value from input. More...
 
class  ValueSaver
 

Typedefs

typedef std::vector< ParsedValueParsedValues
 A vector of parsed values.
 
typedef Container::Map< const SwitchGroup *, std::set< const Switch * > > GroupedSwitches
 Subset of switches grouped by their switch groups.
 
typedef Container::Map< std::string, GroupedSwitchesNamedSwitches
 Subset of switches indexed by their command-line representation.
 

Enumerations

enum  SortOrder {
  INSERTION_ORDER,
  DOCKEY_ORDER
}
 The order in which things are sorted in the documentation. More...
 
enum  Canonical {
  CANONICAL,
  NONCANONICAL,
  ALL_STRINGS
}
 Format of a switch string. More...
 
enum  ShowGroupName {
  SHOW_GROUP_OPTIONAL,
  SHOW_GROUP_REQUIRED,
  SHOW_GROUP_NONE,
  SHOW_GROUP_INHERIT
}
 How to show group names in switch synopsis. More...
 
enum  SwitchSkipping {
  SKIP_NEVER,
  SKIP_WEAK,
  SKIP_STRONG
}
 Whether to skip a switch. More...
 
enum  WhichValue {
  SAVE_NONE,
  SAVE_ONE,
  SAVE_LAST,
  SAVE_FIRST,
  SAVE_ALL,
  SAVE_AUGMENTED
}
 Describes how to handle switches that occur multiple times. More...
 

Functions

std::ostream & operator<< (std::ostream &, const Location &)
 Print a location. More...
 
std::ostream & operator<< (std::ostream &, const ParsedValue &)
 Print some information about a parsed value.
 

Variables

const std::string STR_NONE
 
const Location NOWHERE
 Indicates an invalid location. More...
 

Enumeration Type Documentation

◆ SortOrder

The order in which things are sorted in the documentation.

Enumerator
INSERTION_ORDER 

Entities appear in the documentation in the same order they are inserted into the container.

For instance, manual page sections will appear in the order of the Parser::doc calls, or switches are sorted within a switch group according to the order they were inserted into the group.

DOCKEY_ORDER 

Entities are sorted according to their documentation keys.

Documentation keys, which default to lower-case entity names, are used to sort the entities within their container. This is the default.

Definition at line 173 of file util/Sawyer/CommandLine.h.

◆ Canonical

Format of a switch string.

Enumerator
CANONICAL 

Switch strings that are qualified with the switch group name or which belong to a group that has no name.

NONCANONICAL 

Switch strings that are not CANONICAL.

ALL_STRINGS 

The union of CANONICAL and NONCANONICAL.

Definition at line 186 of file util/Sawyer/CommandLine.h.

◆ ShowGroupName

How to show group names in switch synopsis.

Enumerator
SHOW_GROUP_OPTIONAL 

Show name as being optional, like "--[group-]switch".

SHOW_GROUP_REQUIRED 

Show name as being required, like "--group-switch".

SHOW_GROUP_NONE 

Never show the group name.

SHOW_GROUP_INHERIT 

Group inherits value from the parser.

Definition at line 194 of file util/Sawyer/CommandLine.h.

◆ SwitchSkipping

Whether to skip a switch.

Enumerator
SKIP_NEVER 

Treat the switch normally.

SKIP_WEAK 

Process switch normally, but also add to skipped list.

SKIP_STRONG 

Skip switch and its argument(s) without saving any value.

Definition at line 202 of file util/Sawyer/CommandLine.h.

◆ WhichValue

Describes how to handle switches that occur multiple times.

Enumerator
SAVE_NONE 

The switch is disabled.

Any occurrence will be an error.

SAVE_ONE 

The switch cannot occur more than once.

SAVE_LAST 

Use only the last occurrence and ignore all previous.

SAVE_FIRST 

Use only the first occurrence and ignore all previous.

SAVE_ALL 

Save all values as a vector.

SAVE_AUGMENTED 

Save the first value, or modify previously saved value.

Definition at line 2010 of file util/Sawyer/CommandLine.h.

Function Documentation

◆ operator<<()

std::ostream& Sawyer::CommandLine::operator<< ( std::ostream &  ,
const Location  
)

Print a location.

Prints a location as the dotted pair idx.offset.

Variable Documentation

◆ NOWHERE

const Location Sawyer::CommandLine::NOWHERE

Indicates an invalid location.

The library uses this to indicate that a string came from somewhere other than the command-line. The constant NOWHERE compares equal to itself but unequal to (less than) all valid locations.

Referenced by Sawyer::CommandLine::Switch::intrinsicValue(), and Sawyer::CommandLine::SwitchArgument::SwitchArgument().

Sawyer::CommandLine::Switch
Describes one command-line switch.
Definition: util/Sawyer/CommandLine.h:2041
Sawyer::CommandLine::nonNegativeIntegerParser
NonNegativeIntegerParser< T >::Ptr nonNegativeIntegerParser(T &storage)
Factory for value parsers.
Definition: util/Sawyer/CommandLine.h:1450
Sawyer::CommandLine::ParserResult::unreachedArgs
std::vector< std::string > unreachedArgs() const
Returns program arguments that were not reached during parsing.
Sawyer::CommandLine::Parser
The parser for a program command line.
Definition: util/Sawyer/CommandLine.h:2756
Sawyer::CommandLine::ParserResult::apply
const ParserResult & apply() const
Saves parsed values in switch-specified locations.
Sawyer::CommandLine::Parser::with
Parser & with(const SwitchGroup &sg)
Add switch declarations.
Definition: util/Sawyer/CommandLine.h:2795
Sawyer::CommandLine
Parses program command line switches and arguments.
Definition: util/Sawyer/CommandLine.h:164
Sawyer::CommandLine::ParserResult
The result from parsing a command line.
Definition: util/Sawyer/CommandLine.h:3333
Sawyer::CommandLine::anyParser
AnyParser< T >::Ptr anyParser(T &storage)
Factory for value parsers.
Definition: util/Sawyer/CommandLine.h:1430
Sawyer::CommandLine::Parser::purpose
Parser & purpose(const std::string &purpose)
Program purpose.
Definition: util/Sawyer/CommandLine.h:3094
Sawyer::CommandLine::Parser::parse
ParserResult parse(int argc, char *argv[])
Parse program arguments.
Sawyer::CommandLine::showHelpAndExit
ShowHelpAndExit::Ptr showHelpAndExit(int exitStatus)
Factory for switch action.
Sawyer::CommandLine::SwitchGroup::insert
SwitchGroup & insert(const Switch &)
Insert a switch into the group.
Sawyer::CommandLine::Parser::doc
Parser & doc(const std::string &sectionName, const std::string &docKey, const std::string &text)
Documentation for a section of the manual.
Sawyer::CommandLine::SwitchGroup::doc
SwitchGroup & doc(const std::string &s)
Property: Detailed description.
Definition: util/Sawyer/CommandLine.h:2643
Sawyer::CommandLine::showVersionAndExit
ShowVersionAndExit::Ptr showVersionAndExit(const std::string &versionString, int exitStatus)
Factory for switch action.
Sawyer::CommandLine::Switch::doc
Switch & doc(const std::string &s)
Property: detailed description.
Definition: util/Sawyer/CommandLine.h:2185
Sawyer::CommandLine::SwitchGroup
A collection of related switch declarations.
Definition: util/Sawyer/CommandLine.h:2569
Sawyer::Attribute::name
const std::string & name(Id)
Returns the name for an attribute ID.