tmux-mem-cpu-load/argParse/argParse.h

338 lines
13 KiB
C++

/*
* C++ command line argument parser
*
* Copyright (C) 2005 by
* Michael Hanke michael.hanke@gmail.com
*
* Minor adjustements: 2015 Pawel 'l0ner' Soltys <pwslts@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __ARGVPARSER_H
#define __ARGVPARSER_H
#include <string>
#include <vector>
#include <map>
#include <list>
namespace ArgvParse
{
/** Provides parsing and storage of POSIX-like command line arguments (argc, argv).
* To use this class for CLI-option parsing, first define a set of valid options using
* the defineOption() method. An option can have several attributes: it can be required
* itself (its missing is considered as an error) and/or it can require a value.
* Options with optional values can be realized by defining the option to not need a
* value and use the syntax '--option=value' or '-o=value' on the command line.
* Every option can have different alternative labels; see defineOptionAlternative().
* A usage description (see usageDescription()) can be generated from the set of defined options (also see the
* addErrorCode(), setIntroductoryDescription() and setHelpOption() methods).
* \note The implemented parsing algorithm requires that all options have to be given at
* the beginning of the command line. Everything on the commandline after the first
* non-option (or option value) is considered as an argument.
* \attention Short option labels (single letter options) must not be digits
* (the option string itself not a possible value).
* Valid syntaxes are:
* \li program --long-option value -sdfgh -u=5 -i 7 --last=val arg1 arg2 arg3
* Here is a small code example:
* \code
* #include
* ArgvParser cmd; // the command line parser
*
* // init
* cmd.setIntroductoryDescription("This is foo written by bar.");
*
* //define error codes
* cmd.addErrorCode(0, "Success");
* cmd.addErrorCode(1, "Error");
*
* cmd.setHelpOption("h", "help", "Print this help");
*
* cmd.defineOption("version", ArgvParser::NoOptionAttribute, "Be verbose");
* cmd.defineOptionAlternative("verbose","v");
*
* cmd.defineOption("foo", ArgvParser::OptionRequiresValue, "Fooishness. Default value: 0");
*
* // finally parse and handle return codes (display help etc...)
* int result = cmd.parse(argc, argv);
*
* if (result != ArgvParser::NoParserError)
* cout << cmd.parseErrorDescription(results);
* exit(1);
* \endcode
*
* \author Michael Hanke
*/
class ArgvParser
{
public:
typedef int OptionAttributes;
typedef int ParserResults;
typedef std::map<std::string, unsigned int> String2KeyMap;
typedef std::map<unsigned int, OptionAttributes> Key2AttributeMap;
typedef std::map<unsigned int, std::string> Key2StringMap;
typedef std::vector<std::string> ArgumentContainer;
ArgvParser();
~ArgvParser();
/** Attributes for options. */
enum
{
NoAttribute = 0x00,
RequiresValue = 0x01,
Required = 0x02
};
/** Return values of the parser. */
enum
{
Success = 0x00,
UnknownOption = 0x01,
MissingValue = 0x02,
OptionAfterArgument = 0x04,
MalformedMultipleShortOption = 0x08,
RequiredOptionMissing = 0x16,
HelpRequested = 0x32
};
bool defineOption(const std::string& _name,
const std::string& _description = std::string(),
OptionAttributes _attributes = NoAttribute);
bool defineOption(const std::string& _shortname,
const std::string& _name,
const std::string& _description = std::string(),
OptionAttributes _attributes = NoAttribute);
/** Defines an option with optional attributes (required, ...) and an
* additional (also optional) description. The description becomes part of the
* generated usage help that can be requested by calling the usageDescription()
* method.
* \return Returns FALSE if there already is an option with this name
* OR if a short option string (length == 1) is a digit. In that case no
* action is peformed.
*/
bool defineOptionAlternative(const std::string& _original,
const std::string& _alternative);
/** Define an alternative name for an option that was previously defined by
* defineOption().
* \return Returns FALSE if there already is an option with the alternative
* name or no option with the original name OR if a short option string
* (length == 1) is a digit. In that case no action is performed.
*/
bool isDefinedOption(const std::string& _name) const;
/** Returns whether _name is a defined option. */
bool foundOption(const std::string& _name) const;
/** Returns whether _name is an option that was found while parsing
* the command line arguments with the parse() method. In other word: This
* method returns true if the string is an option AND it was given on the
* parsed command line.
*/
bool setHelpOption(const std::string& _longname = "h",
const std::string& _shortname = "help",
const std::string& _descr = "");
/** Define a help option. If this option is found a special error code is
* returned by the parse method.
* \attention If this method is called twice without an intermediate call
* to the reset() method the previously set help option will remain a valid
* option but is not detected as the special help option and will therefore
* not cause the parse() method to return the special help error code.
* \return Returns FALSE if there already is an option defined that equals
* the short or long name.
*/
unsigned int arguments() const;
/** Returns the number of read arguments. Arguments are efined as beeing
* neither options nor option values and are specified at the end of the
* command line after all options and their values. */
std::string argument(unsigned int _number) const;
/** Returns the Nth argument. See arguments().
* \return Argument string or an empty string if there was no argument of
* that id.
*/
const std::vector<std::string>& allArguments() const;
/** Get the complete argument vector. The order of the arguments in the
* vector is the same as on the commandline.
*/
void addErrorCode(int _code, const std::string& _descr = "");
/** Add an error code and its description to the command line parser.
* This will do nothing more than adding an entry to the usage description.
*/
void setIntroduction(const std::string& _descr);
/** Set some string as a general description, that will be printed before
* the list of available options.
*/
ParserResults parse(int _argc, char ** _argv);
/** Parse the command line arguments for all known options and arguments.
* \return Error code with parsing result.
* \retval NoParserError Everything went fine.
* \retval ParserUnknownOption Unknown option was found.
* \retval ParserMissingValue A value to a given option is missing.
* \retval ParserOptionAfterArgument Option after an argument detected. All
* options have to given before the first argument.
* \retval ParserMalformedMultipleShortOption Malformed short option string.
* \retval ParserRequiredOptionMissing Required option is missing.
* \retval ParserHelpRequested Help option detected.
*/
std::string optionValue(const std::string& _option) const;
/** Return the value of an option.
* \return Value of a commandline options given by the name of the option or
* an empty string if there was no such option or the option required no
* value.
*/
void reset();
/** Reset the parser. Call this function if you want to parse another set of
* command line arguments with the same parser object.
*/
const std::string& errorOption() const;
/** Returns the name of the option that was responsible for a parser error.
* An empty string is returned if no error occured at all.
*/
std::string parseErrorDescription(ParserResults _error_code) const;
/** This method can be used to evaluate parser error codes and generate a
* human-readable description. In case of a help request error code the
* usage description as returned by usageDescription() is printed.
*/
std::string usageDescription(unsigned int _width = 80) const;
/** Returns a string with the usage descriptions for all options. The
* description string is formated to fit into a terminal of width _width.*/
private:
int optionKey( const std::string& _name ) const;
/** Returns the key of a defined option with name _name or -1 if such option
* is not defined. */
std::list<std::string> getAllOptionAlternatives(unsigned int _key) const;
/** Returns a list of option names that are all alternative names associated
* with a single key value.
*/
/** The current maximum key value for an option. */
unsigned int max_key;
/** Map option names to a numeric key. */
String2KeyMap option2key;
/** Map option key to option attributes. */
Key2AttributeMap option2attribute;
/** Map option key to option description. */
Key2StringMap option2descr;
/** Map option key to option value. */
Key2StringMap option2value;
/** Map error code to its description. */
std::map<int, std::string> errorcode2descr;
/** Vector of command line arguments. */
ArgumentContainer argument_container;
/** General description to be returned as first part of the generated help page. */
std::string intro_description;
/** Holds the key for the help option. */
unsigned int help_option;
/** Holds the name of the option that was responsible for a parser error.
*/
std::string error_option;
}; // class ArgvParser
// Auxillary functions
bool isValidOptionString(const std::string& _string);
/** Returns whether the given string is a valid (correct syntax) option string.
* It has to fullfill the following criteria:
* 1. minimum length is 2 characters
* 2. Start with '-'
* 3. if if minimal length -> must not be '--'
* 4. first short option character must not be a digit (to distinguish negative numbers)
*/
bool isValidLongOptionString(const std::string& _string);
/** Returns whether the given string is a valid (correct syntax) long option string.
* It has to fullfill the following criteria:
* 1. minimum length is 4 characters
* 2. Start with '--'
*/
bool splitOptionAndValue(const std::string& _string, std::string& _option,
std::string& _value);
/** Splits option and value string if they are given in the form 'option=value'.
* \return Returns TRUE if a value was found.
*/
template <typename Container>
void splitString(Container& _container, const std::string& _in,
const char* const _delimiters = " \t\n")
{
/** String tokenizer using standard C++ functions. Taken from here:
* http://gcc.gnu.org/onlinedocs/libstdc++/21_strings/howto.html#3
* Splits the string _in by _delimiters and store the tokens in _container.
*/
const std::string::size_type len = _in.length();
std::string::size_type i = 0;
while ( i < len )
{
// eat leading whitespace
i = _in.find_first_not_of (_delimiters, i);
if (i == std::string::npos)
return; // nothing left but white space
// find the end of the token
std::string::size_type j = _in.find_first_of (_delimiters, i);
// push token
if (j == std::string::npos)
{
_container.push_back (_in.substr(i));
return;
}
else
_container.push_back (_in.substr(i, j-i));
// set up for next loop
i = j + 1;
}
}
bool isDigit(const char& _char);
/** Returns true if the character is a digit (what else?). */
bool expandRangeStringToUInt(const std::string& _string,
std::vector<unsigned int>& _expanded);
/** Build a vector of integers from a string of the form:
* '1,3-5,14,25-20'. This string will be expanded to a list of positive
* integers with the following elements: 1,3,4,5,14,25,24,23,22,21,20.
* All of the expanded elements will be added to the provided list.
* \return Returns FALSE if there was any syntax error in the given string
* In that case the function stops at the point where the error occured.
* Only elements processed up to that point will be added to the expanded
* list.
* \attention This function can only handle unsigned integers!
*/
std::string trimmedString(const std::string& _str);
/** Returns a copy of _str with whitespace removed from front and back. */
std::string formatString(const std::string& _string,
unsigned int _width,
unsigned int _indent = 0);
/** Formats a string of an arbitrary length to fit a terminal of width
* _width and to be indented by _indent columns.
*/
}
; // namespace CommandLineProcessing
#endif // __CMDLINEPARSER_H