httpup/argparser.h
2005-11-09 21:44:34 +00:00

243 lines
6.8 KiB
C++

////////////////////////////////////////////////////////////////////////
// FILE: argparser.h
// AUTHOR: Johannes Winkelmann, jw@tks6.net
// COPYRIGHT: (c) 2004 by Johannes Winkelmann
// ---------------------------------------------------------------------
// 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.
////////////////////////////////////////////////////////////////////////
#ifndef _ARGPARSER_H_
#define _ARGPARSER_H_
#include <map>
#include <vector>
#include <string>
// TODO:
// -- important
// - allow multiple occurences of arguments:
// prt-get --config-append="..." --config-append="..."
// - Allow global --help, --usage
// - check for duplicate entries
// -- nice to have
// 2. allow optional values for args, like --with-gtk[=DIR]
// 4. improve predefined commands: allow descriptions even for such
// 7. Add predefined --version, show in usage; add Contact text
// 8. Allow disabling of predefined options
// 9. make parseError more convenient (passing cmd->name all over...)
class APOpt;
class APCmd;
/**
* \brief argument parser class
*
* Yet another argument parser, meant to speed up development of new
* applications. Its focus is on being object oriented and safe to use
*/
class ArgParser
{
public:
/**
* types of argument number checking
*/
enum ArgNumberCheck { NONE, MIN, EQ, MAX };
/*
* APOpt and APCmd are the classes used in client code, to make
* efficient comparison of the selected command.
*
* In addition, it's currently mainly for programs which use a
* command syntax, much like CVS
*/
class APOpt
{
public:
friend class ArgParser;
APOpt() : id(-1), m_initialized(false) {}
bool operator ==(const APOpt& other) const { return other.id == id; }
void init(const std::string& longName,
char shortName,
const std::string& description,
const bool valueRequired=false,
const std::string& valueName="") {
m_initialized = true;
m_longName = longName;
m_shortName = shortName;
m_description = description;
m_valueRequired = valueRequired;
m_valueName = valueName;
}
private:
int id;
std::string m_longName;
char m_shortName;
std::string m_description;
bool m_valueRequired;
std::string m_valueName;
bool m_initialized;
};
class APCmd
{
public:
friend class ArgParser;
APCmd() : id(-1) {}
bool operator ==(const APCmd& other) const { return other.id == id; }
private:
int id;
};
private:
// internal representation of options and commands
class Option
{
public:
int id;
std::string description;
char shortName;
std::string longName;
bool requiresValue;
std::string valueName;
};
class Command
{
public:
int id;
std::string name;
std::string description;
ArgNumberCheck argNumberCheck;
unsigned int argNumber;
std::string otherArguments;
std::map<int, Option*> mandatoryOptions;
std::map<int, Option*> options;
ArgParser::APCmd* apCmd;
};
public:
ArgParser();
virtual ~ArgParser();
/**
* add a command
*
* \param cmd a reference to the command; use it to compare the actually selected command against this one after parsing
* \param name the name of the command to be parsed from the command line
* \param description a description, used for the help screens
* \param argNumberCheck what kind of argument number checking
* \param argNumber optional number of arguments
* \param otherOptions value to display in the help screen for following (non option) arguments
*/
int addCommand(APCmd& cmd,
const std::string& name,
const std::string& description,
ArgNumberCheck argNumberCheck,
const int argNumber=-1,
const std::string& otherArguments="");
/**
* add an option to a command - this will fail with an assertion
* of \a key has not been initialized using init()
*
* \param cmd the command to add an option to
* \param key the option reference; use it to check for certain options after parsing
* \param required whether this option is required
* \param longName the long name of this command (to be used with '--'); leave it empty if you don't want to use a long option name
* \param shortName the short name of this command (to be used with '-'); pass 0 if you don't want to use a short option name
* \param description the description of this option, to be used in the help screen
* \param valueRequired whether this option requires a value
* \param valueName the name of the value, to be used in the help screen
*/
int addOption(const APCmd& cmd,
APOpt& key,
bool required);
/**
* the actual parsing. Highly recommended :-)
*/
void parse(int argc, char** argv);
/**
* the command which was parsed, to be used to compare against
* actual APCmd obtained from addCommand calls
*/
APCmd command() const;
/**
* the name of the application, from argv[0]
*/
std::string appName() const;
/**
* \return true if \a key is set, false otherwise
*/
bool isSet(const APOpt& key) const;
/**
* \return the value attached to the option \key if any
*/
std::string getOptionValue(const APOpt& key) const;
/**
* the remaining arguments
*/
const std::vector<std::string>& otherArguments() const;
/**
* \return an application identification to be used in the usage
*/
virtual std::string getAppIdentification() const { return ""; }
private:
std::string generateHelpForCommand(const std::string& command) const;
std::string generateUsage() const;
bool isSet(int key) const;
std::string generateOptionString(Option* o) const;
void parseError(const std::string& error, const std::string& cmd="") const;
std::map<std::string, Command*> m_commands;
std::map<int, Command*> m_commandIdMap;
std::map<int, Option*> m_options;
std::map<char, Option*> m_optionsByShortName;
std::map<std::string, Option*> m_optionsByLongName;
std::map<int, std::string> m_setOptions;
std::vector<std::string> m_otherArguments;
APCmd m_command;
std::string m_appName;
int m_cmdIdCounter;
int m_optIdCounter;
APOpt PREDEFINED_CMD_HELP;
};
#endif /* _ARGPARSER_H_ */