//////////////////////////////////////////////////////////////////////////////// /// @brief program options description /// /// @file /// /// DISCLAIMER /// /// Copyright 2004-2012 triagens GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. /// /// Copyright holder is triAGENS GmbH, Cologne, Germany /// /// @author Dr. Frank Celler /// @author Copyright 2010-2012, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// #include "ProgramOptionsDescription.h" #include "BasicsC/terminal-utils.h" #include "Basics/Exceptions.h" #include "Basics/StringUtils.h" #include using namespace std; using namespace triagens::basics; // ----------------------------------------------------------------------------- // --SECTION-- constructors and destructors // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @addtogroup ProgramOptions /// @{ //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// /// @brief constructor //////////////////////////////////////////////////////////////////////////////// ProgramOptionsDescription::ProgramOptionsDescription () : _name(""), _helpOptions(), _subDescriptions(), _hiddenSubDescriptions(), _optionNames(), _optionTypes(), _long2short(), _helpTexts(), _stringOptions(), _vectorStringOptions(), _int32Options(), _vectorInt32Options(), _int64Options(), _vectorInt64Options(), _uint32Options(), _vectorUInt32Options(), _uint64Options(), _vectorUInt64Options(), _doubleOptions(), _vectorDoubleOptions(), _boolOptions(), #if __WORDSIZE == 32 _timeOptions(), #endif _positionals(0) { } //////////////////////////////////////////////////////////////////////////////// /// @brief constructor //////////////////////////////////////////////////////////////////////////////// ProgramOptionsDescription::ProgramOptionsDescription (string const& name) : _name(""), _helpOptions(), _subDescriptions(), _hiddenSubDescriptions(), _optionNames(), _optionTypes(), _long2short(), _helpTexts(), _stringOptions(), _vectorStringOptions(), _int32Options(), _vectorInt32Options(), _int64Options(), _vectorInt64Options(), _uint32Options(), _vectorUInt32Options(), _uint64Options(), _vectorUInt64Options(), _doubleOptions(), _vectorDoubleOptions(), _boolOptions(), #if __WORDSIZE == 32 _timeOptions(), #endif _positionals(0) { setName(name); } //////////////////////////////////////////////////////////////////////////////// /// @brief copy constructor //////////////////////////////////////////////////////////////////////////////// ProgramOptionsDescription::ProgramOptionsDescription (ProgramOptionsDescription const& that) : _name(that._name), _helpOptions(that._helpOptions), _subDescriptions(that._subDescriptions), _hiddenSubDescriptions(that._hiddenSubDescriptions), _optionNames(that._optionNames), _optionTypes(that._optionTypes), _long2short(that._long2short), _helpTexts(that._helpTexts), _stringOptions(that._stringOptions), _vectorStringOptions(that._vectorStringOptions), _int32Options(that._int32Options), _vectorInt32Options(that._vectorInt32Options), _int64Options(that._int64Options), _vectorInt64Options(that._vectorInt64Options), _uint32Options(that._uint32Options), _vectorUInt32Options(that._vectorUInt32Options), _uint64Options(that._uint64Options), _vectorUInt64Options(that._vectorUInt64Options), _doubleOptions(that._doubleOptions), _vectorDoubleOptions(that._vectorDoubleOptions), _boolOptions(that._boolOptions), #if __WORDSIZE == 32 _timeOptions(that._timeOptions), #endif _positionals(that._positionals) { } //////////////////////////////////////////////////////////////////////////////// /// @brief assignment constructor //////////////////////////////////////////////////////////////////////////////// ProgramOptionsDescription& ProgramOptionsDescription::operator= (ProgramOptionsDescription const& that) { if (this != &that) { _name = that._name; _helpOptions = that._helpOptions; _subDescriptions = that._subDescriptions; _hiddenSubDescriptions = that._hiddenSubDescriptions; _optionNames = that._optionNames; _optionTypes = that._optionTypes; _long2short = that._long2short; _helpTexts = that._helpTexts; _stringOptions = that._stringOptions; _vectorStringOptions = that._vectorStringOptions; _int32Options = that._int32Options; _vectorInt32Options = that._vectorInt32Options; _int64Options = that._int64Options; _vectorInt64Options = that._vectorInt64Options; _uint32Options = that._uint32Options; _vectorUInt32Options = that._vectorUInt32Options; _uint64Options = that._uint64Options; _vectorUInt64Options = that._vectorUInt64Options; _doubleOptions = that._doubleOptions; _vectorDoubleOptions = that._vectorDoubleOptions; _boolOptions = that._boolOptions; #if __WORDSIZE == 32 _timeOptions = that._timeOptions; #endif _positionals = that._positionals; } return *this; } //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// // ----------------------------------------------------------------------------- // --SECTION-- public methods // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @addtogroup ProgramOptions /// @{ //////////////////////////////////////////////////////////////////////////////// void ProgramOptionsDescription::setName (string const& name) { vector n = StringUtils::split(name, ':'); if (! n.empty()) { _name = n[0]; for (vector::iterator i = n.begin() + 1; i != n.end(); ++i) { _helpOptions.insert(*i); } } } //////////////////////////////////////////////////////////////////////////////// /// @brief adds a new hidden section //////////////////////////////////////////////////////////////////////////////// ProgramOptionsDescription& ProgramOptionsDescription::operator() (ProgramOptionsDescription& sub, bool hidden) { if (hidden) { _hiddenSubDescriptions.push_back(sub); } else { _subDescriptions.push_back(sub); } return *this; } //////////////////////////////////////////////////////////////////////////////// /// @brief adds a new flag //////////////////////////////////////////////////////////////////////////////// ProgramOptionsDescription& ProgramOptionsDescription::operator() (string const& full, string const& text) { string name = check(full); _optionNames.push_back(name); _optionTypes[name] = OPTION_TYPE_FLAG; _helpTexts[name] = text; return *this; } //////////////////////////////////////////////////////////////////////////////// /// @brief adds a string argument //////////////////////////////////////////////////////////////////////////////// ProgramOptionsDescription& ProgramOptionsDescription::operator() (string const& full, string* value, string const& text) { string name = check(full, value); _optionNames.push_back(name); _optionTypes[name] = OPTION_TYPE_STRING; _stringOptions[name] = value; if (value->empty()) { _helpTexts[name] = text; } else { _helpTexts[name] = text + " (default: \"" + *value + "\")"; } return *this; } //////////////////////////////////////////////////////////////////////////////// /// @brief adds a string vector argument //////////////////////////////////////////////////////////////////////////////// ProgramOptionsDescription& ProgramOptionsDescription::operator() (string const& full, vector* value, string const& text) { string name = check(full, value); _optionNames.push_back(name); _optionTypes[name] = OPTION_TYPE_VECTOR_STRING; _vectorStringOptions[name] = value; _helpTexts[name] = text; return *this; } //////////////////////////////////////////////////////////////////////////////// /// @brief adds an int32_t argument //////////////////////////////////////////////////////////////////////////////// ProgramOptionsDescription& ProgramOptionsDescription::operator() (string const& full, int32_t* value, string const& text) { string name = check(full, value); _optionNames.push_back(name); _optionTypes[name] = OPTION_TYPE_INT32; _int32Options[name] = value; _helpTexts[name] = text + " (default: " + StringUtils::itoa(*value) + ")"; return *this; } //////////////////////////////////////////////////////////////////////////////// /// @brief adds an int32_t vector argument //////////////////////////////////////////////////////////////////////////////// ProgramOptionsDescription& ProgramOptionsDescription::operator() (string const& full, vector* value, string const& text) { string name = check(full, value); _optionNames.push_back(name); _optionTypes[name] = OPTION_TYPE_VECTOR_INT32; _vectorInt32Options[name] = value; _helpTexts[name] = text; return *this; } //////////////////////////////////////////////////////////////////////////////// /// @brief adds an int64_t argument //////////////////////////////////////////////////////////////////////////////// ProgramOptionsDescription& ProgramOptionsDescription::operator() (string const& full, int64_t* value, string const& text) { string name = check(full, value); _optionNames.push_back(name); _optionTypes[name] = OPTION_TYPE_INT64; _int64Options[name] = value; _helpTexts[name] = text + " (default: " + StringUtils::itoa(*value) + ")"; return *this; } //////////////////////////////////////////////////////////////////////////////// /// @brief adds an int64_t vector argument //////////////////////////////////////////////////////////////////////////////// ProgramOptionsDescription& ProgramOptionsDescription::operator() (string const& full, vector* value, string const& text) { string name = check(full, value); _optionNames.push_back(name); _optionTypes[name] = OPTION_TYPE_VECTOR_INT64; _vectorInt64Options[name] = value; _helpTexts[name] = text; return *this; } //////////////////////////////////////////////////////////////////////////////// /// @brief adds an uint32_t argument //////////////////////////////////////////////////////////////////////////////// ProgramOptionsDescription& ProgramOptionsDescription::operator() (string const& full, uint32_t* value, string const& text) { string name = check(full, value); _optionNames.push_back(name); _optionTypes[name] = OPTION_TYPE_UINT32; _uint32Options[name] = value; _helpTexts[name] = text + " (default: " + StringUtils::itoa(*value) + ")"; return *this; } //////////////////////////////////////////////////////////////////////////////// /// @brief adds an uint32_t vector argument //////////////////////////////////////////////////////////////////////////////// ProgramOptionsDescription& ProgramOptionsDescription::operator() (string const& full, vector* value, string const& text) { string name = check(full, value); _optionNames.push_back(name); _optionTypes[name] = OPTION_TYPE_VECTOR_UINT32; _vectorUInt32Options[name] = value; _helpTexts[name] = text; return *this; } //////////////////////////////////////////////////////////////////////////////// /// @brief adds an uint64_t argument //////////////////////////////////////////////////////////////////////////////// ProgramOptionsDescription& ProgramOptionsDescription::operator() (string const& full, uint64_t* value, string const& text) { string name = check(full, value); _optionNames.push_back(name); _optionTypes[name] = OPTION_TYPE_UINT64; _uint64Options[name] = value; _helpTexts[name] = text + " (default: " + StringUtils::itoa(*value) + ")"; return *this; } //////////////////////////////////////////////////////////////////////////////// /// @brief adds an uint64_t vector argument //////////////////////////////////////////////////////////////////////////////// ProgramOptionsDescription& ProgramOptionsDescription::operator() (string const& full, vector* value, string const& text) { string name = check(full, value); _optionNames.push_back(name); _optionTypes[name] = OPTION_TYPE_VECTOR_UINT64; _vectorUInt64Options[name] = value; _helpTexts[name] = text; return *this; } //////////////////////////////////////////////////////////////////////////////// /// @brief adds a double argument //////////////////////////////////////////////////////////////////////////////// ProgramOptionsDescription& ProgramOptionsDescription::operator() (string const& full, double* value, string const& text) { string name = check(full, value); _optionNames.push_back(name); _optionTypes[name] = OPTION_TYPE_DOUBLE; _doubleOptions[name] = value; _helpTexts[name] = text + " (default: " + StringUtils::ftoa(*value) + ")"; return *this; } //////////////////////////////////////////////////////////////////////////////// /// @brief adds a double vector argument //////////////////////////////////////////////////////////////////////////////// ProgramOptionsDescription& ProgramOptionsDescription::operator() (string const& full, vector* value, string const& text) { string name = check(full, value); _optionNames.push_back(name); _optionTypes[name] = OPTION_TYPE_VECTOR_DOUBLE; _vectorDoubleOptions[name] = value; _helpTexts[name] = text; return *this; } //////////////////////////////////////////////////////////////////////////////// /// @brief adds a boolean argument //////////////////////////////////////////////////////////////////////////////// ProgramOptionsDescription& ProgramOptionsDescription::operator() (string const& full, bool* value, string const& text) { string name = check(full, value); _optionNames.push_back(name); _optionTypes[name] = OPTION_TYPE_BOOL; _boolOptions[name] = value; _helpTexts[name] = text + " (default: " + (*value ? "true" : "false") + ")"; return *this; } //////////////////////////////////////////////////////////////////////////////// /// @brief adds a time_t argument //////////////////////////////////////////////////////////////////////////////// #if __WORDSIZE == 32 ProgramOptionsDescription& ProgramOptionsDescription::operator() (string const& full, time_t* value, string const& text) { string name = check(full, value); _optionNames.push_back(name); _optionTypes[name] = OPTION_TYPE_TIME; _timeOptions[name] = value; _helpTexts[name] = text + " (default: " + StringUtils::itoa((int64_t)*value) + ")"; return *this; } #endif //////////////////////////////////////////////////////////////////////////////// /// @brief adds positional arguments //////////////////////////////////////////////////////////////////////////////// void ProgramOptionsDescription::arguments (vector* value) { if (value == 0) { THROW_INTERNAL_ERROR("value is 0"); } if (_positionals != 0) { THROW_INTERNAL_ERROR("_positional arguments are already defined"); } _positionals = value; } //////////////////////////////////////////////////////////////////////////////// /// @brief returns the usage message //////////////////////////////////////////////////////////////////////////////// string ProgramOptionsDescription::usage () const { set help; return usage(help); } //////////////////////////////////////////////////////////////////////////////// /// @brief returns the usage message //////////////////////////////////////////////////////////////////////////////// string ProgramOptionsDescription::usage (set const& help, bool addHelpOptions) const { string desc; bool helpAll = help.find("--HELP-ALL--") != help.end(); bool helpStandard = help.find("--HELP--") != help.end(); // extract help-able sub-descriptions vector subDescriptions; for (vector::const_iterator i = _subDescriptions.begin(); i != _subDescriptions.end(); ++i) { ProgramOptionsDescription pod = *i; set ho = pod._helpOptions; if (ho.empty() || helpAll) { subDescriptions.push_back(pod); } else { set is; set_intersection(ho.begin(), ho.end(), help.begin(), help.end(), std::inserter(is, is.end())); if (! is.empty()) { subDescriptions.push_back(pod); } } } // write help only if help options match if (! _helpOptions.empty() || helpStandard || helpAll) { // produce a head line if (! _name.empty() && ! (subDescriptions.empty() && _optionNames.empty())) { if (_helpOptions.empty()) { desc = _name + ":\n"; } else { desc = "Extended " + _name + ":\n"; } } // collect the maximal width of the option names size_t oWidth = 0; map names; for (vector::const_iterator i = _optionNames.begin(); i != _optionNames.end(); ++i) { string const& option = *i; option_type_e type = _optionTypes.find(option)->second; string name; switch (type) { case OPTION_TYPE_FLAG: name = option; break; case OPTION_TYPE_STRING: name = option + " "; break; case OPTION_TYPE_VECTOR_STRING: name = option + " "; break; case OPTION_TYPE_INT32: name = option + " "; break; case OPTION_TYPE_VECTOR_INT64: name = option + " "; break; case OPTION_TYPE_INT64: name = option + " "; break; case OPTION_TYPE_VECTOR_INT32: name = option + " "; break; case OPTION_TYPE_UINT32: name = option + " "; break; case OPTION_TYPE_VECTOR_UINT32: name = option + " "; break; case OPTION_TYPE_UINT64: name = option + " "; break; case OPTION_TYPE_VECTOR_UINT64: name = option + " "; break; case OPTION_TYPE_DOUBLE: name = option + " "; break; case OPTION_TYPE_VECTOR_DOUBLE: name = option + " "; break; case OPTION_TYPE_TIME: name = option + "