diff options
Diffstat (limited to 'src/argparser.cc')
-rw-r--r-- | src/argparser.cc | 322 |
1 files changed, 322 insertions, 0 deletions
diff --git a/src/argparser.cc b/src/argparser.cc new file mode 100644 index 0000000..c8b482c --- /dev/null +++ b/src/argparser.cc @@ -0,0 +1,322 @@ +/** -------------------------------------------------------------------- + * @file argparser.cc + * @brief Implementation of the command line argument parser + * @author Andreas Aardal Hanssen + * @date 2005 + * ------------------------------------------------------------------ **/ +#include "argparser.h" +#include "convert.h" + +#include <string> +#include <map> + +using namespace ::std; +using namespace Binc; + +//---------------------------------------------------------------------- +CommandLineArgs::CommandLineArgs() +{ + errString = "Unknown error for args"; + ac = 0; +} + +//---------------------------------------------------------------------- +bool CommandLineArgs::parse(int argc, char *argv[]) +{ + ac = -1; + head = argv[0]; + head += " <options> --\n"; + + if (argc > 1) { + string lastKey; + bool lastIsBoolean = false; + + for (int i = 1; i < argc; ++i) { + string s = argv[i]; + if (s.length() < 2) { + unqualified.push_back(s); + continue; + } + + if (s[0] != '-') { + // read value of last argument + if (lastKey == "") { + unqualified.push_back(s); + continue; + } + + if (lastIsBoolean && (s != "yes" && s != "no")) { + errString = "syntax error: " + s; + errString += " (expected yes or no)"; + return false; + } + + args[lastKey] = s; + passedArgs[lastKey] = true; + lastKey = ""; + lastIsBoolean = false; + } else if (s[1] == '-') { + if (lastKey != "") { + if (lastIsBoolean) { + args[lastKey] = "yes"; + passedArgs[lastKey] = true; + lastKey = ""; + lastIsBoolean = false; + } else { + errString = "expected value of "; + errString += lastKey; + return false; + } + } + + // break if '--' is detected + if (s.length() == 2) { + ac = i + 1; + break; + } + + // parse --argument + string arg = s.substr(2); + string val; + string::size_type epos = arg.find('='); + if (epos != string::npos) { + val = arg.substr(epos + 1); + arg = arg.substr(0, epos); + } + + if (reg.find(arg) == reg.end()) { + errString = "unrecognized argument: --" + arg; + return false; + } + + if (reg.find(arg)->second.b) { + if (val != "" && val != "yes" && val != "no") { + errString = "syntax error: " + val; + errString += " (expected yes or no)"; + return false; + } else if (val == "") { + val = "yes"; + } + } + + if (val == "") { + errString = "syntax error: " + arg; + errString += " (expected --" + arg + "=<str>)"; + return false; + } + + args[arg] = val; + passedArgs[arg] = true; + + lastKey = ""; + lastIsBoolean = false; + } else { + if (lastKey != "") { + if (lastIsBoolean) { + args[lastKey] = "yes"; + passedArgs[lastKey] = true; + lastKey = ""; + lastIsBoolean = false; + } else { + errString = "expected value of "; + errString += lastKey; + return false; + } + } + + // parse -argument + string arg = s.substr(1); + if (arg.length() == 1) { + map<string, ArgOpts>::const_iterator it = reg.begin(); + bool match = false; + for (; it != reg.end(); ++it) { + if (it->second.c.find(arg[0]) != string::npos) { + lastKey = it->first; + if (it->second.b) lastIsBoolean = true; + match = true; + break; + } + } + + if (!match) { + errString = "unrecognized argument: -"; + errString += arg[0]; + return false; + } + } else { + string::const_iterator its = arg.begin(); + for (; its != arg.end(); ++its) { + map<string, ArgOpts>::const_iterator it = reg.begin(); + bool match = false; + for (; it != reg.end(); ++it) { + if (it->second.c.find(*its) != string::npos) { + if (!it->second.b) { + errString = "argument is not a boolean: "; + errString += "--" + it->first; + errString += " / -"; + errString += it->second.c; + return false; + } + + match = true; + args[it->first] = "yes"; + passedArgs[it->first] = true; + + lastKey = ""; + lastIsBoolean = false; + break; + } + } + + if (!match) { + errString = "unrecognized argument: "; + errString += s; + return false; + } + } + } + } + } + + if (lastKey != "") { + if (lastIsBoolean) { + args[lastKey] = "yes"; + passedArgs[lastKey] = true; + } else { + errString = "expected value of "; + errString += lastKey; + return false; + } + } + } + + // assign default "no" values for arguments that were not passed. + map<string, ArgOpts>::const_iterator it = reg.begin(); + for (; it != reg.end(); ++it) { + if (args.find(it->first) == args.end()) { + if (!it->second.o) { + errString = "missing argument: "; + errString += it->first; + return false; + } + if (it->second.b) args[it->first] = "no"; + } + } + if (ac == -1) ac = argc; + + return true; +} + +//---------------------------------------------------------------------- +string CommandLineArgs::errorString(void) const +{ + return errString; +} + +//---------------------------------------------------------------------- +const string CommandLineArgs::operator [](const string &arg) const +{ + if (args.find(arg) == args.end()) return ""; + return args.find(arg)->second; +} + +//---------------------------------------------------------------------- +void CommandLineArgs::addOptional(const string &arg, const string &desc, + bool boolean) +{ + registerArg(arg, desc, boolean, true); +} + +//---------------------------------------------------------------------- +void CommandLineArgs::addRequired(const string &arg, + const string &desc, bool boolean) +{ + registerArg(arg, desc, boolean, false); +} + +//---------------------------------------------------------------------- +void CommandLineArgs::registerArg(const string &arg, const string &desc, + bool boolean, bool optional) +{ + string name = arg; + + string shorts; + while (name.size() > 1 && name[1] == '|') { + shorts += name[0]; + name = name.substr(2); + } + + reg.insert(make_pair(name, ArgOpts(shorts, boolean, optional, desc))); +} + +//---------------------------------------------------------------------- +bool CommandLineArgs::hasArg(const std::string &arg) const +{ + string tmp = arg; lowercase(tmp); + return passedArgs.find(tmp) != passedArgs.end(); +} + +//---------------------------------------------------------------------- +string CommandLineArgs::usageString(void) const +{ + string tmp = head; + tmp += '\n'; + + map<string, ArgOpts>::const_iterator it = reg.begin(); + for (; it != reg.end(); ++it) { + if (it->second.c != "") { + string::const_iterator sit = it->second.c.begin(); + for (; sit != it->second.c.end(); ++sit) { + if (sit != it->second.c.begin()) tmp += '\n'; + tmp += " -"; + tmp += *sit; + } + tmp += ", "; + } else { + tmp += " "; + } + + tmp += "--"; + tmp += it->first; + if (!it->second.b) tmp += "=<str>"; + + if (!it->second.o) tmp += " (required)"; + + string::size_type lineStart = tmp.rfind('\n'); + if (lineStart == string::npos) lineStart = 0; + + int pad = 21 - (tmp.length() - lineStart); + if (pad < 0) { + tmp += '\n'; + pad = 20; + } + + tmp += string(pad, ' '); + tmp += it->second.desc; + tmp += '\n'; + } + + tmp += '\n'; + tmp += tail; + tmp += '\n'; + + return tmp; +} + +//---------------------------------------------------------------------- +int CommandLineArgs::argc(void) const +{ + return ac; +} + +//---------------------------------------------------------------------- +void CommandLineArgs::setTail(const string &str) +{ + tail = str; +} + +//---------------------------------------------------------------------- +const vector<string> &CommandLineArgs::getUnqualifiedArgs() const +{ + return unqualified; +} |