X-Git-Url: https://git.teslayout.com/public/public/public/?a=blobdiff_plain;f=source%2Fcore%2Futil%2FCommandLine.cpp;h=9c495e7c4b746ec05c99cc9ad2119126e415c2c5;hb=93366a0bda79e6fd6e7dad6316bfcf8cc82f5731;hp=a79d63a3e2dec95c67ea7a3fdd50116240b19e94;hpb=3e258840b15577cb8bda3cdedd0b9b88e16404b3;p=anna.git diff --git a/source/core/util/CommandLine.cpp b/source/core/util/CommandLine.cpp index a79d63a..9c495e7 100644 --- a/source/core/util/CommandLine.cpp +++ b/source/core/util/CommandLine.cpp @@ -1,37 +1,9 @@ -// ANNA - Anna is Not Nothingness Anymore -// -// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo -// -// https://bitbucket.org/testillano/anna -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Authors: eduardo.ramos.testillano@gmail.com -// cisco.tierra@gmail.com +// ANNA - Anna is Not Nothingness Anymore // +// // +// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo // +// // +// See project site at http://redmine.teslayout.com/projects/anna-suite // +// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE // #include @@ -41,29 +13,67 @@ #include #include +#include using namespace std; using namespace anna; -#ifndef TOKENINDICATOR -#define TOKENINDICATOR '-' -#endif - //-------------------------------------------------------------------------------- -// Notifica al Parser que la opcion 'argumentName' es soportada +// Notifica al Parser que la opcion 'argumentExpression' es soportada // // (1) Verifica que la opcion no haya sido registrada previamente. //-------------------------------------------------------------------------------- -void CommandLine::add(const char* argumentName, Argument::Type type, const char* comment, const bool needValue) +void CommandLine::add(const char* argumentExpression, Argument::Type type, const char* comment, const bool needValue) throw() { Guard guard(a_mutex, "CommandLine::add"); - if(search(argumentName) == NULL) - a_arguments.push_back(new Variable(argumentName, type, comment, needValue)); + std::string arg1 = "", arg2 = ""; + if (!argumentExpression) { std::cerr << "Invalid argument expression: cannot register NULL literal on command-line" << std::endl; return; } + + anna::Tokenizer expression; + expression.apply (argumentExpression, ","); + if (expression.size() > 2) { std::cerr << "Invalid argument expression '" << argumentExpression << "': only '[,]' or '[,]' are supported for command-line registration" << std::endl; return; } + + anna::Tokenizer::const_iterator tok_it = expression.begin(); + arg1 = anna::Tokenizer::data(tok_it); + // No leading hyphens in the name: + if (arg1[0] == '-') { std::cerr << "Invalid argument expression '" << argumentExpression << "': no leading hyphens allowed in argument names for command-line registration" << std::endl; return; } + + tok_it++; + if (tok_it != expression.end()) { + arg2 = anna::Tokenizer::data(tok_it); + // No hyphens in the name: + if (arg2[0] == '-') { std::cerr << "Invalid argument expression '" << argumentExpression << "': no leading hyphens allowed in argument names for command-line registration" << std::endl; return; } + } + + // swap to have first non empty: + if (arg1 == "") { arg1 = arg2; arg2 = ""; } + + // If both provided, one will be single letter and the other, a word: + if (arg2 != "") { + int s1 = arg1.size(); + int s2 = arg2.size(); + if ((s1 + s2) == 2) { std::cerr << "Invalid argument expression '" << argumentExpression << "': only '[,]' or '[,]' are supported for command-line registration (provided two letters !)" << std::endl; return; } + if ((s1 != 1) && (s2 != 1)) { std::cerr << "Invalid argument expression '" << argumentExpression << "': only '[,]' or '[,]' are supported for command-line registration (provided two words !)" << std::endl; return; } + } + + // assign: + a_arguments.push_back(new Variable(arg1, arg2, type, comment, needValue)); +} + +void CommandLine::initialize(const char** argv, const int argc, int positionalArguments) +throw(RuntimeException) { + if (argc < 1) throw RuntimeException("Provided argc < 1 as command-line argv size !", ANNA_FILE_LOCATION); + if (positionalArguments < 0) throw RuntimeException("Provided negative number of positional arguments as command-line initializer", ANNA_FILE_LOCATION); + if (positionalArguments > (argc-1)) throw RuntimeException("Provided positional arguments > (argc - 1) as command-line initializer", ANNA_FILE_LOCATION); + a_positionalArguments = positionalArguments; + a_argv = argv; + a_argc = argc; + a_wasParsed = false; } //-------------------------------------------------------------------------------- -// Verifica que todos los argumentNameos declarados como obligatorios estan en la +// Verifica que todos los argumentos declarados como obligatorios estan en la // linea de comandos. //-------------------------------------------------------------------------------- void CommandLine::verify() @@ -73,26 +83,26 @@ throw(RuntimeException) { for(int i = 0, maxi = a_arguments.size(); i < maxi; i ++) { if(a_arguments [i]->getType() == Argument::Mandatory) - getValue(a_arguments [i]->getName().c_str()); // JEDS 24/09/2003 + getValue(a_arguments [i]->getName1().c_str()); // exit program if not found (exitOnFault = true by default) } } //-------------------------------------------------------------------------------- -// Obtiene el valor para opcion 'argumentName'. +// Obtiene el valor para opcion 'argumentExpression'. // // (1) Realiza el analisis de la linea de comandos. // (2) Verifica que la opcion recibida existe en la lista de opciones registradas. -// (3) Si la opcion 'argumentName' existe en la linea de comandos ... -// (3.1) Si el argumentNameo debe ir seguido por un valor/valores y no existe +// (3) Si la opcion 'argumentExpression' existe en la linea de comandos ... +// (3.1) Si el argumentExpression debe ir seguido por un valor/valores y no existe // ninguno => error. -// (3.2) Si el argumentNameo no necesita valor, simplemente, le asigna una cadena +// (3.2) Si el argumentExpression no necesita valor, simplemente, le asigna una cadena // que contiene 'true', en otro caso devolvera NULL. // -// (4) Si no existe en la linea de comandos y es un argumentNameo obligatorio => error. +// (4) Si no existe en la linea de comandos y es un argumentExpression obligatorio => error. // // Si el arguemento solicitado no esta en la LC y es opcional devolvera NULL. //-------------------------------------------------------------------------------- -const char* CommandLine::getValue(const char* argumentName, const bool exitOnFault) +const char* CommandLine::getValue(const char* argumentExpression, const bool exitOnFault) throw() { const char* result = NULL; const Variable* argument = NULL; @@ -100,7 +110,7 @@ throw() { bool analized; if((analized = analize()) == true) { // (1) - if((argument = search(argumentName)) != NULL) { // (2) + if((argument = search(argumentExpression)) != NULL) { // (2) error = false; result = argument->getValue(); @@ -122,7 +132,7 @@ throw() { printUsage(); exit(-1); } else if(error == true && exitOnFault == true) { - cout << "Variable: '" << argumentName << "' is not valid" << endl << endl; + cout << "Variable: '" << argumentExpression << "' is not valid" << endl << endl; printUsage(); exit(-1); } @@ -130,84 +140,127 @@ throw() { return result; } +// Auxiliary function: +// Returns first no-leading hyphen position +int removeLeadingHyphens(std::string &argv) throw() { + int startPos = -1; + // Move until no hyphen: + for (int i=0; i < argv.size(); i++) + if (argv[i] != '-') { startPos = i; argv = argv.substr(i); break; } + + // No word found: + if (startPos == -1) return -1; + + // one hyphen: + if (startPos == 1) + if (argv.size() != 1) return -1; + + // two hyphens: + if (startPos == 2) + if (argv.size() == 1) return -1; + + // more than two ! + if (startPos > 2) return -1; + + return startPos; +} + //-------------------------------------------------------------------------------- -// Analiza la linea de comandos para completar la informacion de los argumentNameos. -// -// (1) Comprueba que el analisis no se ha completado con existo previamente. -// (2) El primer argumentNameo despues del nombre del ejecutable debe comenzar por -// el caracter de indicador de argumentNameo. -// (3) Comprueba si el argumentNameo de la LC esta registrado como posible argumentNameo. -// (4) Recoge todo lo que haya entre el argumentNameo actual y el siguiente argumentNameo -// (si lo hay) y todo esto lo asigna como valor del argumentNameo actual. -// (5) Quita el ltimo car�ter +// Analize command line to store the arguments //-------------------------------------------------------------------------------- bool CommandLine::analize() throw() { - Variable* argument; + Variable* variable; bool result = true; - int i = 1; + int i = a_positionalArguments + 1; string aux; - if(a_wasParsed == true) + if(a_wasParsed == true) // already analyzed return true; - Guard guard(a_mutex, "CommandLine::analize"); + Guard guard(a_mutex, "CommandLine::analyze"); if(a_wasParsed == true) return true; + // Control state: while(i < a_argc && result == true) { - if(i == 1 && a_argv [1][0] != TOKENINDICATOR) { // (2) + + aux = a_argv[i]; + if (::removeLeadingHyphens(aux) == -1) { result = false; break; } - - if((argument = const_cast (search(a_argv [i]))) != NULL) { // (3) - aux = ""; - argument->setIsOn(true); - // @Eduardo (allow dashes on values) -// while (++ i < a_argc && a_argv [i][0] != TOKENINDICATOR) { // (4) -// aux += a_argv [i]; -// aux += " "; -// } - bool notArgument = true; - - while(notArgument && (++ i < a_argc)) { // (4) - if(a_argv [i][0] == TOKENINDICATOR) - notArgument = (search(a_argv[i]) == NULL); - - if(notArgument) { - aux += a_argv [i]; - aux += " "; - } + if((variable = const_cast (search(aux.c_str()))) != NULL) { + variable->setIsOn(true); + if (variable->getNeedValue()) { + i++; + if (i < a_argc) { variable->setValue(a_argv[i]); } + else { result = false ; break; } } - - if(aux.length() > 0) { - aux.erase(aux.length() - 1, 1); // 5) - argument->setValue(aux.c_str()); // JEDS 24/09/2003 - } - } else { - cout << "Variable: " << a_argv [i] << " unreconized" << endl; + } + else { + cout << "Variable: " << aux << " unreconized" << endl; result = false; + break; } - } + + i++; + } // while return (a_wasParsed = result); } -const CommandLine::Variable* CommandLine::search(const char *argumentName) const +const CommandLine::Variable* CommandLine::search(const char *argumentExpression) const throw() { - const Variable* result = NULL; - vector ::const_iterator ii, maxii; + if (!argumentExpression) return NULL; + std::string name1, name2, arg; + + vector ::const_iterator arg_min(a_arguments.begin()), arg_max(a_arguments.end()), arg_it; + + // Tokenize: + anna::Tokenizer expression; + expression.apply (argumentExpression, ","); + if (expression.size() > 2) return NULL; + + anna::Tokenizer::const_iterator tok_it; + for (tok_it = expression.begin(); tok_it != expression.end(); tok_it++) { // one or two + arg = anna::Tokenizer::data(tok_it); + for(arg_it = arg_min; arg_it != arg_max; arg_it++) { + name1 = (*arg_it)->getName1(); + name2 = (*arg_it)->getName2(); + if ((name1 != "") && (name1 == arg)) return *arg_it; + if ((name2 != "") && (name2 == arg)) return *arg_it; + } + } - if(*argumentName == TOKENINDICATOR) argumentName ++; + return NULL; +} - for(ii = a_arguments.begin(), maxii = a_arguments.end(); ii != maxii; ii ++) { - if(anna_strcmp((*ii)->getName().c_str(), argumentName) == 0) { - result = *ii; - break; +string CommandLine::Variable::getHelpExpression() const +throw() { + std::string long_name, short_name, result = ""; + + int s1 = a_name1.size(); + int s2 = a_name2.size(); + if ((s1 + s2) > 2) { // both provided + if (s1 > 1) { short_name = a_name2; long_name = a_name1; } + else { short_name = a_name1; long_name = a_name2; } + if (short_name != "") { + result += "-"; + result += short_name; + result += "|"; + } + if (long_name != "") { + result += "--"; + result += long_name; } } + else { + result = "-"; + if (s1 > 1) result = "-"; + result += a_name1; + } return result; } @@ -223,42 +276,36 @@ throw() { cout << endl << "Where: " << endl; for(i = 0; i < maxi; i ++) { - cout << " " << a_arguments [i]->getName() << ": " << endl; + cout << " " << a_arguments [i]->getHelpExpression() << ": " << endl; cout << " " << a_arguments [i]->getComment() << endl; } } - + string CommandLine::Variable::asString() const throw() { string result; result = ((a_type == Argument::Optional) ? "[ " : ""); - result += TOKENINDICATOR; - result += a_name; - - if(a_needValue == true) { - result += " ::const_iterator ii, maxii; const char *value; + for(int pos = 1; pos <= a_positionalArguments; pos++) + result += anna::functions::asString("Positional argument [%d]: %s\n", pos, getPositional(pos)); + for(ii = a_arguments.begin(), maxii = a_arguments.end(); ii != maxii; ii ++) { value = (*ii)->getValue(); if(value) { - result += (*ii)->getName(); + result += (*ii)->getHelpExpression(); result += ": "; result += value; result += "\n"; @@ -273,14 +320,16 @@ xml::Node* CommandLine::asXML(xml::Node* parent) const throw() { vector ::const_iterator ii, maxii; const char *value; + for(int pos = 1; pos <= a_positionalArguments; pos++) + result->createAttribute(anna::functions::asString("PositionalArgument_%d", pos).c_str(), getPositional(pos)); + for(ii = a_arguments.begin(), maxii = a_arguments.end(); ii != maxii; ii ++) { value = (*ii)->getValue(); if(value) - result->createAttribute((*ii)->getName().c_str(), value); + result->createAttribute((*ii)->getHelpExpression().c_str(), value); } return result; } -