From 08bc9b7ecfe17324584b201671b3108435c290a7 Mon Sep 17 00:00:00 2001 From: "Pawel \"l0ner\" Soltys" Date: Mon, 19 Jan 2015 17:17:38 +0100 Subject: [PATCH] replaced argParser with getopt_long based one Solves issue: https://github.com/l0ner/tmux-mem-cpu-load/commit/28040b61dad99cb9cb4cfc604a5d38123b4ac66e#commitcomment-9327906 No GPL2-based code anymore in the codebase. --- argParse/argParse.cc | 817 ------------------------------------------ argParse/argParse.h | 337 ----------------- tmux-mem-cpu-load.cpp | 116 +++--- 3 files changed, 66 insertions(+), 1204 deletions(-) delete mode 100644 argParse/argParse.cc delete mode 100644 argParse/argParse.h diff --git a/argParse/argParse.cc b/argParse/argParse.cc deleted file mode 100644 index 7dbece6..0000000 --- a/argParse/argParse.cc +++ /dev/null @@ -1,817 +0,0 @@ -/* - * C++ command line argument parser - * - * Copyright (C) 2005 by - * Michael Hanke michael.hanke@gmail.com - * - * Minor adjustements: 2015 Pawel 'l0ner' Soltys - * - * 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. - */ -#include -#include -#include "argParse.h" - -using namespace std; -using namespace ArgvParse; - -ArgvParser::ArgvParser() - : max_key(1), - help_option(0) // must be smaller than max_key initially - -{ - // nothing -} - -ArgvParser::~ArgvParser() -{ - // nothing -} - -void ArgvParser::reset() -{ - max_key = 1; - option2key.clear(); - option2attribute.clear(); - option2descr.clear(); - option2value.clear(); - errorcode2descr.clear(); - argument_container.clear(); - intro_description.clear(); - error_option.clear(); - help_option = 0; -} - -int ArgvParser::optionKey( const string& _name ) const -{ - String2KeyMap::const_iterator it = option2key.find(_name); - - // if not found - if (it == option2key.end()) - return(-1); - - return(it->second); -} - -bool ArgvParser::isDefinedOption( const string& _name ) const -{ - return(option2key.find(_name) != option2key.end()); -} - -bool ArgvParser::foundOption( const string & _name ) const -{ - int key = optionKey(_name); - - // not defined -> cannot by found - if (key == -1) - return(false); - - // return whether the key of the given option name is in the hash of the - // parsed options. - return(option2value.find(key) != option2value.end()); -} - -string ArgvParser::optionValue(const string& _option) const -{ - int key = optionKey(_option); - - // not defined -> cannot by found - if (key == -1) - { - cerr << "ArgvParser::optionValue(): Requested value of an option the" - "parser did not find or does not know." << endl; - return(""); - } - - return(option2value.find(key)->second); -} - -ArgvParser::ParserResults -ArgvParser::parse(int _argc, char ** _argv) -{ - bool finished_options = false; // flag whether an argument was found - // (options are passed) - - // loop over all command line arguments - int i = 1; // argument counter - while( i< _argc ) - { - string argument = _argv[i]; - unsigned int key = 0; - string option; // option name - string value; // option value - - // if argument is an option - if (!isValidOptionString(argument)) - { - // string is a real argument since values are processed elsewhere - finished_options=true; - argument_container.push_back(argument); - } - else // can be a long or multiple short options at this point - { - // check whether we already found an argument - if (finished_options) - { - error_option = argument; - return(OptionAfterArgument); // return error code - } - // check for long options - if (isValidLongOptionString(argument)) - { - // handle long options - - // remove trailing '--' - argument = argument.substr(2); - // check for option value assignment 'option=value' - splitOptionAndValue(argument, option, value); - - if (!isDefinedOption(option)) // is this a known option - { - error_option = option; // store the option that caused the error - return(UnknownOption); // return error code if not - } - - // get the key of this option - now that we know that it is defined - key = option2key.find(option)->second; - if (key == help_option) // if help is requested return error code - return(HelpRequested); - - // do we need to extract a value - // AND a value is not already assigned from the previous step - if ((option2attribute.find(key)->second & RequiresValue) && value.empty()) - { - if (i+1 >= _argc) // are there arguments left? - { - error_option = option; // store the option that caused the error - return(MissingValue); // the was no argument left although we need a value - } - - string temp = _argv[i+1]; // get the next element - ++i; // increase counter now that we moved forward - - if (isValidOptionString(temp)) - { - error_option = option; // store the option that caused the error - return(MissingValue); // missing option value - } - value = temp; // assign value - } - // add option-value map entry - option2value[key] = value; - } - else // handle short options - { - argument = argument.substr(1); // remove trailing '-' - - // check for option value assignment 'option=value' - if (splitOptionAndValue(argument, option, value)) - { - // there was an option <- value assignment - if (option.length() > 1) - { - error_option = option; // store the option that caused the error - return(MalformedMultipleShortOption); // return error code if option has more than one character - } - - if (!isDefinedOption(option)) // is this a known option - { - error_option = option; // store the option that caused the error - return(UnknownOption); // return error code if not - } - key = option2key.find(option)->second; // get the key for the extracted option name - - if (key == help_option) // if help is requested return error code - return(HelpRequested); - - // if value is still empty for some reason: we have an error - if ((option2attribute.find(key)->second & RequiresValue) && value.empty()) - { - error_option = option; // store the option that caused the error - return(MissingValue); // missing option value - } - else - // add option-value map entry - option2value[key] = value; - } - else // no '=' assignment: can be either multiple short options or - // something like '-s 4' - { - // handle short options with value like '-s 4' - option.clear(); - value.clear(); - - if (argument.length() == 1) // if a single short option - { - if (!isDefinedOption(argument)) // is this a known option - { - error_option = argument; // store the option that caused the error - return(UnknownOption); // return error code if not - } - key = option2key.find(argument)->second; // get the key for the extracted option name - - if (key == help_option) // if help is requested return error code - return(HelpRequested); - - // check if option needs a value and next arg is not an option - if ((option2attribute.find(key)->second & RequiresValue)) - { - if (i+1 >= _argc) // are there arguments left? - { - error_option = argument; // store the option that caused the error - return(MissingValue); // the was no argument left although we need a value - } - string temp = _argv[i+1]; // get the next element - ++i; // increase counter now that we moved forward - - if (isValidOptionString(temp)) - { - error_option = argument; // store the option that caused the error - return(MissingValue); // missing option value - } - // add option-value map entry - option2value[key] = temp; - - } - else // no value needed - { - option2value[key] = ""; // assign value - } - } - else // handle multiple short option like '-svxgh' - { - unsigned int short_option_counter = 0; // position in the multiple short option string - while( short_option_counter < argument.length() ) // parse the whole string - { - option = argument[short_option_counter]; // get the option character - - if (!isDefinedOption(option)) // is this a known option - { - error_option = option; // store the option that caused the error - return(UnknownOption); // return error code if not - } - key = option2key.find(option)->second; // get the key for the extracted option name - - if (key == help_option) // if help is requested return error code - return(HelpRequested); - - option2value[key] = value; - - ++short_option_counter; // advance one character forward - } - } - } - } - } - ++i; - } - - map::iterator it; - for( it = option2attribute.begin(); it != option2attribute.end(); it++ ) - { - // if the current option is required look if we got it - if (it->second & Required) - { - // is the object missing - if (option2value.find(it->first) == option2value.end()) - { - // get the list of alternative names for this option - list alternatives = getAllOptionAlternatives(it->first); - - unsigned int count = 0; - for( list::const_iterator alt = alternatives.begin(); - alt != alternatives.end(); - ++alt ) - { - ++count; - // additional '-' for long options - if (alt->length() > 1) - error_option += "-"; - - error_option += "-" + *alt; - - // alternatives to come? - if (count < alternatives.size()) - error_option += ", "; // add separator - } - return(RequiredOptionMissing); - } - } - } - - return(Success); // everthing went fine -> sucess -} - -unsigned int ArgvParser::arguments() const -{ - return(argument_container.size()); -} - -string ArgvParser::argument(unsigned int _id) const -{ - if (_id >= arguments()) - { - cerr << "ArgvParser::argument(): Request for non-existing argument.\n"; - return (""); - } - else - return(argument_container[_id]); -} - -const vector& ArgvParser::allArguments() const -{ - return(argument_container); -} - -string ArgvParser::usageDescription(unsigned int _width) const -{ - string usage; // the usage description text - - if (intro_description.length()) - usage += formatString(intro_description, _width) + "\n\n"; - - if (max_key>1) // if we have some options - usage += formatString("Available options:",_width) + "\n"; - - // loop over all option attribute entries (which equals looping over all - // different options (not option names) - for (Key2AttributeMap::const_iterator it = option2attribute.begin(); - it != option2attribute.end(); - ++it) - { - string os; // temp string for the option - - // get the list of alternative names for this option - list alternatives = getAllOptionAlternatives(it->first); - - unsigned int count = 0; - for( list::const_iterator alt = alternatives.begin(); - alt != alternatives.end(); - ++alt ) - { - ++count; - // additional '-' for long options - if (alt->length() > 1) - os += "-"; - - os += "-" + *alt; - - // note if the option requires a value - if (option2attribute.find(it->first)->second & RequiresValue) - os += " "; - - // alternatives to come? - if (count < alternatives.size()) - os += ", "; // add separator - } - - // note if the option is required - if (option2attribute.find(it->first)->second & Required) - os += " [required]"; - - usage += formatString(os, _width) + "\n"; - - if (option2descr.find(it->first) != option2descr.end()) - usage += formatString(option2descr.find(it->first)->second, _width, 4); - else - usage += formatString("(no description)", _width, 4); - - // finally a little gap - usage += "\n"; - } - usage += "\n"; - - if (!errorcode2descr.size()) // if have no errorcodes - return(usage); - - usage += formatString("Return codes", _width) + "\n"; - - // map::const_iterator eit; - for( std::map::const_iterator alt = errorcode2descr.begin(); - alt != errorcode2descr.end(); - ++alt ) - { - ostringstream code; - code << alt->first; - string label = formatString(code.str(), _width, 4); - string descr = formatString(alt->second, _width, 10); - usage += label + descr.substr(label.length()) + "\n"; - } - - return(usage); -} - -const string& ArgvParser::errorOption( ) const -{ - return(error_option); -} - -std::string ArgvParser::parseErrorDescription( ParserResults _error_code ) const -{ - string descr; - - switch (_error_code) - { - case ArgvParser::Success: - // no error -> nothing to do - break; - case ArgvParser::UnknownOption: - descr = "Unknown option: '" + errorOption() + "'\n"; - break; - case ArgvParser::MissingValue: - descr = "Missing required value for option: '" + errorOption()+ "'\n"; - break; - case ArgvParser::OptionAfterArgument: - descr = "Misplaced option '" + errorOption() + - "' detected. All option have to be BEFORE the first argument\n"; - break; - case ArgvParser::MalformedMultipleShortOption: - descr = "Malformed short-options: '" + errorOption() + "'\n"; - break; - case ArgvParser::ArgvParser::RequiredOptionMissing: - descr = "Required option missing: '" + errorOption() + "'\n"; - break; - case ArgvParser::HelpRequested: // help - descr = usageDescription(); - break; - default: - cerr << "ArgvParser::documentParserErrors(): Unknown error code\n"; - } - - return(descr); -} - -bool ArgvParser::defineOption( const string & _name, - const string& _descr, - OptionAttributes _attrs) -{ - // do nothing if there already is an option of this name - if (isDefinedOption(_name)) - { - cerr << "ArgvParser::defineOption(): The option label equals an already defined option." << endl; - return(false); - } - - // no digits as short options allowed - if (_name.length() == 1 && isDigit(_name[0])) - { - cerr << "ArgvParser::defineOption(): Digits as short option labels are not allowd." << endl; - return(false); - } - - option2key[_name] = max_key; // give the option a unique key - - // store the option attributes - option2attribute[max_key] = _attrs; - - // store the option description if there is one - if (_descr.length()) - option2descr[max_key] = _descr; - - // inc the key counter - ++max_key; - - return(true); -} - -bool ArgvParser::defineOptionAlternative( const string & _original, - const string & _alternative ) -{ - // do nothing if there already is no option of this name - if (!isDefinedOption(_original)) - { - cerr << "ArgvParser::defineOptionAlternative(): Original option label is not a defined option." << endl; - return(false); - } - - // AND no digits as short options allowed - if (_alternative.length() == 1 && isDigit(_alternative[0])) - { - cerr << "ArgvParser::defineOptionAlternative(): Digits as short option labels are not allowd." << endl; - return(false); - } - - // AND do nothing if there already is an option with the alternativ name - if (isDefinedOption(_alternative)) - { - cerr << "ArgvParser::defineOptionAlternative(): The alternative option label equals an already defined option." << endl; - return(false); - } - - option2key[_alternative] = optionKey(_original); - - return(true); -} - -bool ArgvParser::defineOption( const string & _shortname, - const string & _name, - const string& _descr, - OptionAttributes _attrs) -{ - - defineOption( _name, _descr, _attrs); - defineOptionAlternative( _name, _shortname ); - - return(true); - -} - - -bool ArgvParser::setHelpOption(const string& _shortname, - const string& _longname, - const string& _descr) -{ - // do nothing if any name is already in use - if (isDefinedOption(_shortname) || isDefinedOption(_longname)) - { - cerr << "ArgvParser::setHelpOption(): Short or long help option label equals an already defined option." << endl; - return(false); - } - - // define the help option's short name and the alternative - // longname - defineOption(_shortname, _descr, NoAttribute); - defineOptionAlternative(_shortname, _longname); - - help_option = max_key-1; // store the key in a special member - - return(true); -} - -void ArgvParser::addErrorCode(int _code, const string& _descr) -{ - errorcode2descr[_code] = _descr; -} - -void ArgvParser::setIntroduction(const string& _descr) -{ - intro_description = _descr; -} - -list ArgvParser::getAllOptionAlternatives( unsigned int _key ) const -{ - // keys go here - list keys; - // for all container elements - for( map::const_iterator it = option2key.begin(); - it != option2key.end(); - ++it ) - { - if (it->second == _key) - keys.push_back(it->first); - } - return(keys); -} - -bool ArgvParse::isDigit(const char& _char) -{ - if (_char == '0' || _char == '1' || _char == '2' || _char == '3' - || _char == '4' || _char == '5' || _char == '6' || _char == '7' - || _char == '8' || _char == '9') - return(true); - else - return(false); -} - -bool ArgvParse::isValidOptionString(const string& _string) -{ - // minimal short option length is 2 - if (_string.length() < 2) - return(false); - - // is it an option (check for '-' as first character) - if (_string.compare(0, 1, "-")) - return(false); - - // not an option if just '--' - if (_string.length() == 2 && _string == "--") - return(false); - - // it might still be a negative number - // (but not if there is no digit afterwards) - if (isDigit(_string[1])) - return(false); - - // let's consider this an option - return(true); -} - -bool ArgvParse::isValidLongOptionString(const string& _string) -{ - if (_string.length() < 4) // must be at least '--??' - return(false); - - // is it an option (check for '--') - if (_string.compare(0, 2, "--")) - return(false); - else - return(true); -} - -bool ArgvParse::splitOptionAndValue(const string& _string, - string& _option, string& _value) -{ - // string token container - std::vector tokens; - - // split string by '=' delimiter - splitString(tokens, _string, "="); - - // check for option value assignment 'option=value' - if (tokens.size() < 2) - { - _option = _string; // the option is the whole string - return(false); - } - - // separate option and value - _option = tokens[0]; - - // concat all remaining tokens to the value string - for (unsigned int i=1; i & _expanded ) -{ - list tokens; - // split string by delimiter - splitString(tokens, _string, ","); - - // loop over all entries - for(list::const_iterator it = tokens.begin(); it != tokens.end(); it++) - { - const string& entry = *it; // convenience reference - -#ifdef ARGVPARSER_DEBUG - - cout << "TOKEN: " << entry << endl; -#endif - - // if range was given - if (entry.find("-") != string::npos) - { - // split into upper and lower border - list range_borders; - splitString(range_borders, entry, "-"); - - // fail if insane range spec - if (range_borders.size() != 2) - return(false); - - int first = atoi(range_borders.begin()->c_str()); - int second = atoi((++range_borders.begin())->c_str()); - - // write id in increasing order - if (first <= second) - - { - for (int j=first; j<=second; ++j) - { - _expanded.push_back(j); - } - } - else // write id in decreasing order - { - for (int k=first; k>=second; k--) - { - _expanded.push_back(k); - } - } - } - else // single number was given - _expanded.push_back(atoi(entry.c_str())); // store id - } - - return(true); -} - -std::string ArgvParse::formatString(const std::string& _string, - unsigned int _width, - unsigned int _indent) -{ - // if insane parameters do nothing - if (_indent >= _width) - return(_string); - - // list of lines of the formated string - list lines; - - // current position in the string - unsigned int pos = 0; - - // till the end of the string - while (pos < _string.length()) - { - // get the next line of the string - string line = _string.substr(pos, _width - _indent ); - -#ifdef ARGVPARSER_DEBUG - - cout << "EXTRACT: '" << line << "'" << endl; -#endif - - // check for newlines in the line and break line at first occurence (if any) - string::size_type first_newline = line.find_first_of("\n"); - if (first_newline != string::npos) - { - line = line.substr(0, first_newline); - } - - // we need to check for possible breaks within words only if the extracted - // line spans the whole allowed width - bool check_truncation = true; - if (line.length() < _width - _indent) - check_truncation = false; - - // remove unecessary whitespace at front and back - line = trimmedString(line); - -#ifdef ARGVPARSER_DEBUG - - cout << "TRIMMED: '" << line << "'" << endl; -#endif - - // only perform truncation if there was enough data for a full line - if (!check_truncation) - pos += line.length() + 1; - else - { - // look for the last whitespace character - string::size_type last_white_space = line.find_last_of(" \a\b\f\n\r\t\v"); - - if (last_white_space != string::npos) // whitespace found! - { - // truncated the line at the last whitespace - line = string(line, 0, last_white_space); - pos += last_white_space + 1; - } - else // no whitespace found - // rude break! we can leave the line in its current state - pos += _width - _indent; - } - - if (!line.empty()) - { -#ifdef ARGVPARSER_DEBUG - cout << "UNINDEN: '" << line << "'" << endl; -#endif - - if (_indent) - line.insert(0, _indent, ' '); - -#ifdef ARGVPARSER_DEBUG - - cout << "INDENT: '" << line << "'" << endl; -#endif - - lines.push_back(line); - } - } - - // concat the formated string - string formated; - bool first = true; - // for all lines - for (list::iterator it = lines.begin(); it != lines.end(); ++it) - { - // prefix with newline if not first - if (!first) - formated += "\n"; - else - first = false; - - formated += *it; - } - return(formated); -} - diff --git a/argParse/argParse.h b/argParse/argParse.h deleted file mode 100644 index 6b8ae27..0000000 --- a/argParse/argParse.h +++ /dev/null @@ -1,337 +0,0 @@ -/* - * C++ command line argument parser - * - * Copyright (C) 2005 by - * Michael Hanke michael.hanke@gmail.com - * - * Minor adjustements: 2015 Pawel 'l0ner' Soltys - * - * 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 -#include -#include -#include - -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 String2KeyMap; - typedef std::map Key2AttributeMap; - typedef std::map Key2StringMap; - typedef std::vector 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& 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 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 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 -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& _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 diff --git a/tmux-mem-cpu-load.cpp b/tmux-mem-cpu-load.cpp index 15d090f..11180c2 100644 --- a/tmux-mem-cpu-load.cpp +++ b/tmux-mem-cpu-load.cpp @@ -20,9 +20,9 @@ #include #include #include -#include // EXIT_SUCCESS +#include // EXIT_SUCCESS, atoi() +#include // getopt_long -#include "argParse/argParse.h" #include "version.h" #include "graph.h" @@ -83,64 +83,80 @@ std::string cpu_string( unsigned int cpu_usage_delay, unsigned int graph_lines, return oss.str(); } +void print_help() +{ + using std::cout; + using std::endl; + + cout << "tmux-mem-cpu-load v" << tmux_mem_cpu_load_VERSION << endl + << "Usage: tmux-mem-cpu-load [OPTIONS]\n\n" + << "Available options:\n" + << "-h, --help\n" + << "\t Prints this help message\n" + << "--colors\n" + << "\tUse tmux colors in output\n" + << "-i , --interval \n" + << "\tSet tmux status refresh interval in seconds. Default: 1 second\n" + << "-g , --graph-lines \n" + << "\tSet how many lines should be drawn in a graph. Default: 10\n" + << endl; +} + int main( int argc, char** argv ) { - using namespace ArgvParse; - unsigned cpu_usage_delay = 990000; short graph_lines = 10; // max 32767 should be enough bool use_colors = false; - // Argv parser - ArgvParser arg; - - // ugly, I know - std::string intro = "tmux-mem-cpu-load v"; - intro += tmux_mem_cpu_load_VERSION; - intro += "\nUsage: tmux-mem-cpu-load [OPTIONS]"; - - arg.setIntroduction( intro ); - - arg.setHelpOption( "h", "help", "Prints this help message" ); - - // define actual options - arg.defineOption( "colors", "Use tmux colors in output", - ArgvParser::NoAttribute ); - arg.defineOption( "i", "interval", "set tmux status refresh interval in " - "seconds. Default: 1 second", ArgvParser::RequiresValue ); - arg.defineOption( "g", "graph-lines", "Set how many lines should be drawn in " - "a graph. Default: 10", ArgvParser::RequiresValue ); - - int result = arg.parse( argc, argv ); - - if( result != ArgvParser::Success ) + static struct option long_options[] = { - std::cerr << arg.parseErrorDescription( result ); - return EXIT_FAILURE; - } + // Struct is a s follows: + // const char * name, int has_arg, int *flag, int val + // if *flag is null, val is option identifier to use in switch() + // otherwise it's a value to set the variable *flag points to + { "help", no_argument, NULL, 'h' }, + { "colors", no_argument, NULL, 'c' }, + { "interval", required_argument, NULL, 'i' }, + { "graph-lines", required_argument, NULL, 'g' }, + { 0, 0, 0, 0 } // used to handle unknown long options + }; - // mangle arguments - if( arg.foundOption( "colors" ) ) - use_colors = true; - - if( arg.foundOption( "interval" ) ) + int c; + // while c != -1 + while( (c = getopt_long( argc, argv, "hi:g:", long_options, NULL) ) != -1 ) { - int delay = std::stoi( arg.optionValue( "interval" ) ); - if( delay < 1 ) + switch( c ) { - std::cerr << "Status interval argument must be one or greater.\n"; - return EXIT_FAILURE; - } - cpu_usage_delay = delay * 1000000 - 10000; - } - - if( arg.foundOption( "graph-lines" ) ) - { - graph_lines = std::stoi( arg.optionValue( "graph-lines" ) ); - if( graph_lines < 0 ) - { - std::cerr << "Graph lines argument must be zero or greater.\n"; - return EXIT_FAILURE; + case 'h': // --help, -h + print_help(); + return EXIT_FAILURE; + break; + case 'c': // --colors + use_colors = true; + break; + case 'i': // --interval, -i + if( atoi( optarg ) < 1 ) + { + std::cerr << "Status interval argument must be one or greater.\n"; + return EXIT_FAILURE; + } + cpu_usage_delay = atoi( optarg ) * 1000000 - 10000; + break; + case 'g': // --graph-lines, -g + if( atoi( optarg ) < 0 ) + { + std::cerr << "Graph lines argument must be zero or greater.\n"; + return EXIT_FAILURE; + } + graph_lines = atoi( optarg ); + break; + case '?': + // getopt_long prints error message automatically + return EXIT_FAILURE; + break; + default: + std::cout << "?? getopt returned character code 0 " << c << std::endl; + return EXIT_FAILURE; } }