diff --git a/code/nel/include/nel/misc/cmd_args.h b/code/nel/include/nel/misc/cmd_args.h index 26e097eee..25195b64d 100644 --- a/code/nel/include/nel/misc/cmd_args.h +++ b/code/nel/include/nel/misc/cmd_args.h @@ -40,6 +40,8 @@ public: std::string helpName; // name of argument in help. Eg: std::string helpDescription; // description of argument in help. Eg: Specifies the directory where to write generated files + bool onlyOnce; // only one argument of this type is used, if several are provided, only the last one is kept + bool required; // at least one argument of this type must be provided bool found; // all values for this argument std::vector values; // all values for this argument @@ -55,12 +57,15 @@ public: /// longName is "print" of the argument is --print /// helpName is the name that will be displayed in help if it's a required argument /// helpDescription is the description of the argument that will be displayed in help - void addArg(const std::string &shortName, const std::string &longName, const std::string &helpName, const std::string &helpDescription); + /// onlyOnce can be set to false, if we allows to use this argument more than once + void addArg(const std::string &shortName, const std::string &longName, const std::string &helpName, const std::string &helpDescription, bool onlyOnce = true); - /// Add a required argument to arguments list. + /// Add a additional argument to arguments list. /// helpName is the name that will be displayed in help if it's a required argument /// helpDescription is the description of the argument that will be displayed in help - void addArg(const std::string &helpName, const std::string &helpDescription); + /// onlyOnce can be set to false, if we allows to use this argument more than once + /// required can be set to false, if this argument is required + void addAdditionalArg(const std::string &name, const std::string &helpDescription, bool onlyOnce = true, bool required = true); /// Parse the command line from main() parameters argc and argv and process default arguments. bool parse(int argc, char **argv); @@ -93,21 +98,39 @@ public: std::vector getLongArg(const std::string &argName) const; /// return true if there are arguments that are required - bool needRequiredArg() const; + bool needAdditionalArg() const; - /// return true if required or optional args are present on the commandline - bool haveRequiredArg() const; + /// return true if any additional args are present on the commandline + bool haveAdditionalArg() const; - /// Returns all additional required parameters - std::vector getRequiredArg() const; + /// return true if a specific additional arg is present on the commandline + bool haveAdditionalArg(const std::string &name) const; + + /// Returns values of a specific additional arg + std::vector getAdditionalArg(const std::string &name) const; /// Display help of the program. void displayHelp(); /// Display version of the program. void displayVersion(); + + /// Returns program name or path passed as first parameter to parse() method + std::string getProgramName() const { return _ProgramName; } + std::string getProgramPath() const { return _ProgramPath; } + + /// Set or get description to display in help + void setDescription(const std::string &description) { _Description = description; } + std::string getDescription() const { return _Description; } + + /// Set or get version to display in -v + void setVersion(const std::string &version) { _Version = version; } + std::string getVersion() const { return _Version; } protected: - std::string _ProgramName; + std::string _ProgramName; // filename of the program + std::string _ProgramPath; // full path of the program + std::string _Description; // description of the program + std::string _Version; // version of the program /// Array of arguments pass from the command line TArgs _Args; diff --git a/code/nel/src/misc/cmd_args.cpp b/code/nel/src/misc/cmd_args.cpp index bbdee0e11..f44bc15b1 100644 --- a/code/nel/src/misc/cmd_args.cpp +++ b/code/nel/src/misc/cmd_args.cpp @@ -33,6 +33,10 @@ namespace NLMISC CCmdArgs::CCmdArgs() { +#ifdef NL_VERSION + _Version = NL_VERSION; +#endif + // add help addArg("h", "help", "", "Display this help"); @@ -45,24 +49,28 @@ void CCmdArgs::addArg(const TArg &arg) _Args.push_back(arg); } -void CCmdArgs::addArg(const std::string &shortName, const std::string &longName, const std::string &helpName, const std::string &helpDescription) +void CCmdArgs::addArg(const std::string &shortName, const std::string &longName, const std::string &helpName, const std::string &helpDescription, bool onlyOnce) { TArg arg; arg.shortName = shortName; arg.longName = longName; arg.helpName = helpName; arg.helpDescription = helpDescription; + arg.onlyOnce = onlyOnce; arg.found = false; + arg.required = false; addArg(arg); } -void CCmdArgs::addArg(const std::string &helpName, const std::string &helpDescription) +void CCmdArgs::addAdditionalArg(const std::string &helpName, const std::string &helpDescription, bool onlyOnce, bool required) { TArg arg; arg.helpName = helpName; arg.helpDescription = helpDescription; + arg.onlyOnce = onlyOnce; arg.found = false; + arg.required = required; addArg(arg); } @@ -125,7 +133,7 @@ std::vector CCmdArgs::getLongArg(const std::string &argName) const return std::vector(); } -bool CCmdArgs::needRequiredArg() const +bool CCmdArgs::needAdditionalArg() const { // process each argument for(uint i = 0; i < _Args.size(); ++i) @@ -133,14 +141,14 @@ bool CCmdArgs::needRequiredArg() const const TArg &arg = _Args[i]; // they don't have any short or long name, but need a name in help - if (arg.shortName.empty() && arg.longName.empty() && !arg.helpName.empty()) + if (arg.shortName.empty() && arg.longName.empty() && !arg.helpName.empty() && arg.required) return true; } return false; } -bool CCmdArgs::haveRequiredArg() const +bool CCmdArgs::haveAdditionalArg() const { // process each argument for(uint i = 0; i < _Args.size(); ++i) @@ -148,14 +156,14 @@ bool CCmdArgs::haveRequiredArg() const const TArg &arg = _Args[i]; // they don't have any short or long name, but need a name in help - if (arg.shortName.empty() && arg.longName.empty() && !arg.helpName.empty()) - return !arg.values.empty(); + if (arg.shortName.empty() && arg.longName.empty() && !arg.helpName.empty() && arg.found) + return false; } return false; } -std::vector CCmdArgs::getRequiredArg() const +bool CCmdArgs::haveAdditionalArg(const std::string &name) const { // process each argument for(uint i = 0; i < _Args.size(); ++i) @@ -163,7 +171,22 @@ std::vector CCmdArgs::getRequiredArg() const const TArg &arg = _Args[i]; // they don't have any short or long name, but need a name in help - if (arg.shortName.empty() && arg.longName.empty() && !arg.helpName.empty()) + if (arg.shortName.empty() && arg.longName.empty() && !arg.helpName.empty() && arg.helpName == name && arg.found) + return false; + } + + return false; +} + +std::vector CCmdArgs::getAdditionalArg(const std::string &name) const +{ + // process each argument + for(uint i = 0; i < _Args.size(); ++i) + { + const TArg &arg = _Args[i]; + + // they don't have any short or long name, but need a name in help + if (arg.shortName.empty() && arg.longName.empty() && !arg.helpName.empty() && arg.helpName == name) return arg.values; } @@ -174,6 +197,15 @@ std::vector CCmdArgs::getRequiredArg() const bool CCmdArgs::parse(const std::string &args) { std::vector argv; + +#ifdef NL_OS_WINDOWS + char str[4096]; + uint len = GetModuleFileNameA(NULL, str, 4096); + + if (len && len < 4096) + argv.push_back(str); +#endif + std::string::size_type pos1 = 0, pos2 = 0; do @@ -230,6 +262,7 @@ bool CCmdArgs::parse(const std::vector &argv) // first argument is always the program name _ProgramName = CFile::getFilename(argv.front()); + _ProgramPath = CPath::standardizePath(CFile::getPath(argv.front())); // arguments count uint argc = argv.size(); @@ -272,6 +305,8 @@ bool CCmdArgs::parse(const std::vector &argv) name = name.substr(0, 1); } + bool found = false; + // process each argument definition for(uint j = 0; j < _Args.size(); ++j) { @@ -280,8 +315,15 @@ bool CCmdArgs::parse(const std::vector &argv) // only process arguments of the right type if ((useLongName && name != arg.longName) || (!useLongName && name != arg.shortName)) continue; + // already get the only once argument + if (arg.found && arg.onlyOnce) + { + // the last one is the only kept, so discard previous ones + arg.values.clear(); + } + // argument is found - arg.found = true; + found = arg.found = true; // another argument is required if (!arg.helpName.empty()) @@ -302,6 +344,11 @@ bool CCmdArgs::parse(const std::vector &argv) break; } + + if (!found) + { + printf("Warning: Argument %s not recognized, skip it!\n", name.c_str()); + } } else { @@ -313,6 +360,11 @@ bool CCmdArgs::parse(const std::vector &argv) // only process arguments that don't have a name if (!arg.shortName.empty() || !arg.longName.empty()) continue; + // already get the only once argument + if (arg.found && arg.onlyOnce) continue; + + arg.found = true; + // in fact, if there are more than one required arguments, all arguments are added in first one to simplify arg.values.push_back(name); @@ -329,7 +381,7 @@ bool CCmdArgs::parse(const std::vector &argv) } // process help if requested or if required arguments are missing - if (haveLongArg("help") || (needRequiredArg() && !haveRequiredArg())) + if (haveLongArg("help") || (needAdditionalArg() && !haveAdditionalArg())) { displayHelp(); return false; @@ -363,14 +415,6 @@ void CCmdArgs::displayHelp() } } - sint last = -1; - - // look for last required argument - for(uint i = 0; i < _Args.size(); ++i) - { - if (_Args[i].shortName.empty()) last = (sint)i; - } - // display required arguments for(uint i = 0; i < _Args.size(); ++i) { @@ -379,18 +423,24 @@ void CCmdArgs::displayHelp() // they don't have any short or long name, but need a name in help if (arg.shortName.empty() && arg.longName.empty() && !arg.helpName.empty()) { - printf(" <%s>", arg.helpName.c_str()); + printf(" %c%s", arg.required ? '<':'[', arg.helpName.c_str()); - // if last argument, it can support additional arguments - if ((sint)i == last) - { - printf(" [%s...]", arg.helpName.c_str()); - } + // if support more than once argument + if (!arg.onlyOnce) printf("..."); + + printf("%c", arg.required ? '>':']'); } } printf("\n"); + if (!_Description.empty()) + { + printf("\n%s", _Description.c_str()); + } + + printf("\nWhere options are:\n"); + // display details on each argument for(uint i = 0; i < _Args.size(); ++i) { @@ -399,19 +449,23 @@ void CCmdArgs::displayHelp() // not an optional argument if (arg.shortName.empty() && arg.longName.empty()) continue; - // a tab - printf("\t"); + // 2 spaces + printf(" "); + + std::vector syntaxes; // display short argument if (!arg.shortName.empty()) { - printf("-%s", arg.shortName.c_str()); - // and it's required argument if (!arg.helpName.empty()) { - printf(" <%s>", arg.helpName.c_str()); - printf(" or -%s<%s>", arg.shortName.c_str(), arg.helpName.c_str()); + syntaxes.push_back(toString("-%s <%s>", arg.shortName.c_str(), arg.helpName.c_str())); + syntaxes.push_back(toString("-%s<%s>", arg.shortName.c_str(), arg.helpName.c_str())); + } + else + { + syntaxes.push_back(toString("-%s", arg.shortName.c_str())); } } @@ -420,29 +474,29 @@ void CCmdArgs::displayHelp() { if (!arg.helpName.empty()) { - // prepend a coma if a short argument was already displayed - if (!arg.shortName.empty()) - { - printf(", "); - } - // display first syntax for long argument, --arg - printf("--%s <%s>", arg.longName.c_str(), arg.helpName.c_str()); + syntaxes.push_back(toString("--%s <%s>", arg.longName.c_str(), arg.helpName.c_str())); } - // prepend " or " if 3 formats for argument - if (!arg.shortName.empty() || !arg.helpName.empty()) - { - printf(" or "); - } - - // display second syntax for long argument, --arg= - printf("--%s", arg.longName.c_str()); - if (!arg.helpName.empty()) { - printf("=<%s>", arg.helpName.c_str()); + // display second syntax for long argument, --arg= + syntaxes.push_back(toString("--%s=<%s>", arg.longName.c_str(), arg.helpName.c_str())); } + else + { + syntaxes.push_back(toString("--%s", arg.longName.c_str())); + } + } + + for(uint j = 0; j < syntaxes.size(); ++j) + { + if (j > 0) + { + printf("%s ", (j == syntaxes.size() - 1) ? " or":","); + } + + printf("%s", syntaxes[j].c_str()); } // display argument description @@ -462,7 +516,7 @@ void CCmdArgs::displayHelp() // only display required arguments if (arg.shortName.empty() && arg.longName.empty() && !arg.helpName.empty() && !arg.helpDescription.empty()) { - printf("\t%s : %s\n", arg.helpName.c_str(), arg.helpDescription.c_str()); + printf(" %s : %s\n", arg.helpName.c_str(), arg.helpDescription.c_str()); } } } @@ -471,7 +525,7 @@ void CCmdArgs::displayVersion() { // display a verbose version string #ifdef BUILD_DATE - printf("%s %s (built on %s)\nCopyright (C) %s\n", _ProgramName.c_str(), NL_VERSION, BUILD_DATE, COPYRIGHT); + printf("%s %s (built on %s)\nCopyright (C) %s\n", _ProgramName.c_str(), _Version.c_str(), BUILD_DATE, COPYRIGHT); #endif }