From 8f27e65bddd7d4b8515ce620fb485fdd78fcdf89 Mon Sep 17 00:00:00 2001 From: Constantin Jucovschi Date: Fri, 24 Apr 2009 07:20:22 -0400 Subject: Initial commit --- commline/cmlparser.cc | 915 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 915 insertions(+) create mode 100644 commline/cmlparser.cc (limited to 'commline/cmlparser.cc') diff --git a/commline/cmlparser.cc b/commline/cmlparser.cc new file mode 100644 index 0000000..7c3d50d --- /dev/null +++ b/commline/cmlparser.cc @@ -0,0 +1,915 @@ +/* +* This file is part of rasdaman community. +* +* Rasdaman community 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 3 of the License, or +* (at your option) any later version. +* +* Rasdaman community 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. +* +* You should have received a copy of the GNU General Public License +* along with rasdaman community. If not, see . +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see +* or contact Peter Baumann via . +/ +/** + * SOURCE: cmlparser.cc + * + * MODULE: akinside/commline + * + * PURPOSE: + * + * COMMENTS: + * None +*/ + + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace std; + +static const char rcsid[] = "@(#)commline,cmlparser: $Id: cmlparser.cc,v 1.5 2006/01/17 07:50:07 rasdev Exp $"; + +const char* CommandLineParserVersion = "1.0 (c) 2003 Dr. Peter Baumann"; + +//############################################################# + +char* +dupString(const char* cc) +{ + if(cc) + { + // strdup uses malloc, we would like to avoid it + char *dup = new char[strlen(cc)+1]; + // new throws? we hope + strcpy(dup,cc); + return dup; + } + + return NULL; +} + +CmlException::CmlException(const string& whatString) +:problem(whatString) +{ +} + +CmlException::~CmlException() throw() +{ +} + +const char* CmlException::what() const throw() +{ + return problem.c_str(); +} + + +//############################################################ + +const char* CommandLineParameter::defaultTitle = "default: "; +const char* CommandLineParameter::descSep = " "; +const char* CommandLineParameter::descTab = "\t"; +const char* CommandLineParameter::descIndent = " "; +const char* CommandLineParameter::descLineSep = "\n"; +const char CommandLineParameter::descOpen = '<'; +const char CommandLineParameter::descClose = '>'; +const char* CommandLineParameter::descLeftDefault = "("; +const char* CommandLineParameter::descRightDefault = ")"; + + + +CommandLineParameter::CommandLineParameter(char newShortName, const char* newLongName, const char* newDefaultValue) throw(CmlException) + : longName(NULL), defaultValue(NULL), descriptionText(NULL), paramDescription(NULL) +{ + + if((!isalnum(newShortName) || (newShortName == CommandLineParser::noShortName)) + && (!newLongName || !strcmp(newLongName, CommandLineParser::noLongName))) + throw CmlException(string("") + "Invalid option: shortName='" + newShortName + "' longName='" + (newLongName? newLongName: "NULL") + "'"); + + shortName = newShortName; + longName = dupString(newLongName); + present = false; + wasLongName = false; + defaultValue = dupString(newDefaultValue); + + shNameString[0] = newShortName; + shNameString[1] = 0; + + paramDescription = NULL; + descriptionText = NULL; +} + +CommandLineParameter::CommandLineParameter(char newShortName, const char* newLongName, long newDefaultValue) throw(CmlException) + : longName(NULL), defaultValue(NULL), descriptionText(NULL), paramDescription(NULL) +{ + + if((!isalnum(newShortName) || (newShortName == CommandLineParser::noShortName)) + && (!newLongName || !strcmp(newLongName, CommandLineParser::noLongName))) + throw CmlException(string("") + "Invalid option: shortName='" + newShortName + "' longName='" + (newLongName? newLongName: "NULL") + "'"); + + shortName = newShortName; + longName = dupString(newLongName); + present = false; + wasLongName = false; + + // convert default to ASCII, for uniform handling + stringstream s; + s << newDefaultValue; + defaultValue = dupString( s.str().c_str() ); + + shNameString[0] = newShortName; + shNameString[1] = 0; + + paramDescription = NULL; + descriptionText = NULL; +} + +const char* CommandLineParameter::calledName() +{ + const char* retval=NULL; + + if(shortName == CommandLineParser::noShortName) + retval = longName; + else + if(!strcmp(longName, CommandLineParser::noLongName)) + retval = shNameString; + else + retval = (wasLongName && longName) ? longName : shNameString; + return retval; +} + +void CommandLineParameter::reset() +{ + present=false; + wasLongName=false; +} + + +CommandLineParameter::~CommandLineParameter() +{ + if(longName) + delete[] longName; + + if(defaultValue) + delete[] defaultValue; + + // paramDescription and descriptionText point both to the same string + // but depends on the context which has to be deleted + if(paramDescription) + { + delete[] paramDescription; + paramDescription = NULL; + descriptionText = NULL; + } + if(descriptionText) + delete[] descriptionText; +} + +void CommandLineParameter::setDescription(const char *desc) +{ + // cleaning the previous paramDescription + // paramDescription and descriptionText point both to the same string + // but depends on the context which has to be deleted + if(paramDescription) + { + delete[] paramDescription; + paramDescription = NULL; + descriptionText = NULL; + } + if(descriptionText) delete[] descriptionText; + + if(desc==NULL) + { + paramDescription=NULL; + descriptionText =NULL; + } + else + { + paramDescription = dupString(desc); + + // if the string is " line1...", for options with parameters + if(paramDescription[0]==descOpen) + { + int len = strlen(paramDescription); + int i=0; + for(i=0;i=len-1) // I didn't find descClose + { + descriptionText=paramDescription; + paramDescription=NULL; + } + } + else + { + // the string is just "line1..." for options without parameters + descriptionText = paramDescription; + paramDescription = NULL; + } + } + +#ifdef DEBUG + cout<<"desc="<" + if(paramDescription) + os << paramDescription; + + // separator between param value and default + if(defaultValue) + os << CommandLineParameter::descTab; + + // print default, if any: "(default: 42)" + if(defaultValue) + os << CommandLineParameter::descLeftDefault << defaultTitle << defaultValue << CommandLineParameter::descRightDefault; + + // in a second line, print description text (2*indent) + if(descriptionText) + os << CommandLineParameter::descLineSep << CommandLineParameter::descIndent << CommandLineParameter::descIndent << descriptionText; + + os<::iterator iter = value.begin(); +/* FIXME: free mem to avoid mem leaks + while ( iter != value.end() ) + { + if (*iter != NULL) + delete[] *iter; + } +*/ + value.clear(); + + CommandLineParameter::reset(); +} + + +bool StringParameter::needsValue() +{ + return true; +} + +bool StringParameter::takeValue(const char* s) +{ + char *aux = dupString(s); + value.push_back( aux ); + return true; +} + +void StringParameter::popValue() +{ + if ( ! value.empty() ) + value.pop_front(); +} + +const char* StringParameter::getValueAsString() throw(CmlException) +{ + return ( !value.empty() ? value.front() : defaultValue ); +} + +long StringParameter::getValueAsLong() throw(CmlException) +{ + const char *r = ( !value.empty() ? value.front() : defaultValue ); + + if(r == NULL) + throw CmlException(string("") + "No value for parameter '" + calledName() + "'"); + + char *endptr; + + long result = strtol( r, &endptr, 0); + + if( *endptr != 0 ) + throw CmlException(string("") + "Invalid integer value for parameter '" + calledName() + "'"); + + return result; +} + +double StringParameter::getValueAsDouble() throw(CmlException) +{ + const char *r = ( !value.empty() ? value.front() : defaultValue ); + + if(r == NULL) + throw CmlException(string("") + "No value for parameter '" + calledName() + "'"); + + char *endptr; + + double result = strtod( r, &endptr); + + if( *endptr != 0 ) + throw CmlException(string("") + "Invalid double value for parameter '" + calledName() + "'"); + + return result; +} + +ostream& StringParameter::printStatus(ostream &os) +{ + if(value.empty()) + os<<"option '"<::iterator iter = value.begin(); + while ( iter != value.end() ) + { + os<< "'" << (*iter ? *iter : "(null)") << "' "; + iter++; + } + } + return os; +} + +//########################################################## +const char CommandLineParser::noShortName = '-'; +const char* CommandLineParser::noLongName = "--"; +const char* CommandLineParser::ShortSign = "-"; +const char* CommandLineParser::LongSign = "--"; + +CommandLineParser* CommandLineParser::myself = NULL; + +CommandLineParser& CommandLineParser::getInstance() +{ + if(myself == NULL) + myself = new CommandLineParser; + return *myself; +} + +CommandLineParser::CommandLineParser() +{ + lastParameter = NULL; + nextTokenIsValue = false; +} + +CommandLineParser::~CommandLineParser() +{ + delete myself; + myself=NULL; + + lastParameter=NULL; + + list::iterator iter = cmlParameter.begin(); + for(unsigned int i=0;isetDescription(description); + cmlParameter.push_back(cp); + return *cp; +} + +CommandLineParameter& CommandLineParser::addStringParameter(char shortName, const char* longName, const char *description, const char* newDefaultValue) throw(CmlException) +{ + CommandLineParameter *cp = new StringParameter(shortName,longName,newDefaultValue); + cp->setDescription(description); + cmlParameter.push_back(cp); + return *cp; +} + +CommandLineParameter& CommandLineParser::addLongParameter(char shortName, const char* longName, const char *description, long newDefaultValue) throw(CmlException) +{ + CommandLineParameter *cp = new StringParameter(shortName,longName,newDefaultValue); + cp->setDescription(description); + cmlParameter.push_back(cp); + return *cp; +} + +bool CommandLineParser::isPresent(char shortName) throw(CmlException) +{ + StringParameter *sp; + FlagParameter *fp; + bool result; + + CommandLineParameter &cml = getParameter(shortName); + if ((sp = dynamic_cast(&cml))) + result = sp->isPresent(); + else if ((fp = dynamic_cast(&cml))) + result = fp->isPresent(); + return result; +} + +bool CommandLineParser::isPresent(const char* longName) throw(CmlException) +{ + StringParameter *sp; + FlagParameter *fp; + bool result; + + CommandLineParameter &cml = getParameter(longName); + if ((sp = dynamic_cast(&cml))) + result = sp->isPresent(); + else if ((fp = dynamic_cast(&cml))) + result = fp->isPresent(); + return result; +} + +const char* CommandLineParser::getValueAsString(char shortName) throw(CmlException) +{ + CommandLineParameter &cml = getParameter(shortName); + return cml.getValueAsString(); +} + +long CommandLineParser::getValueAsLong(char shortName) throw(CmlException) +{ + CommandLineParameter &cml = getParameter(shortName); + return cml.getValueAsLong(); +} + +double CommandLineParser::getValueAsDouble(char shortName) throw(CmlException) +{ + CommandLineParameter &cml = getParameter(shortName); + return cml.getValueAsDouble(); +} + +const char* CommandLineParser::getValueAsString(const char* longName) throw(CmlException) +{ + CommandLineParameter &cml = getParameter(longName); + return cml.getValueAsString(); +} + +long CommandLineParser::getValueAsLong(const char* longName) throw(CmlException) +{ + CommandLineParameter &cml = getParameter(longName); + return cml.getValueAsLong(); +} + +double CommandLineParser::getValueAsDouble(const char* longName) throw(CmlException) +{ + CommandLineParameter &cml = getParameter(longName); + return cml.getValueAsDouble(); +} + + +void CommandLineParser::processCommandLine(int argc, char** argv) throw(CmlException) +{ + for(int i=1;icalledName() + "' in command line"); +} + + +CommandLineParameter& CommandLineParser::getParameter(char shortName) throw(CmlException) +{ + list::iterator iter = cmlParameter.begin(); + + for(unsigned int i=0;idoesMatch(shortName) ) + { + return *(*iter); + } + } + throw CmlException(string("") + "Syntax error: unknown parameter '" + shortName + "' in command line"); +} + +CommandLineParameter& CommandLineParser::getParameter(const char* longName) throw(CmlException) +{ + list::iterator iter = cmlParameter.begin(); + + for(unsigned int i=0;idoesMatch(longName) ) + { + return *(*iter); + } + } + throw CmlException(string("") + "Syntax error: unknown parameter '" + longName + "' in command line"); +} + + +void CommandLineParser::setValue(const char* value) throw(CmlException) +{ + if(lastParameter == NULL) + { + throw CmlException("internal error: setValue - lastParameter==null"); + } + lastParameter->takeValue(value); + nextTokenIsValue=false; +} + +void CommandLineParser::longNameParameter(const char *nextToken) throw(CmlException) +{ + const char* longName = nextToken + strlen(LongSign); // sari peste LongSign (former "--") + + CommandLineParameter &cml = getParameter(longName); + cml.setPresent(longName); + if(cml.needsValue()) + { + lastParameter = &cml; + nextTokenIsValue=true; + } +} + +void CommandLineParser::shortNameParameter(const char *nextToken) throw(CmlException) +{ + int tokenLength = strlen(nextToken); + + for(int i=strlen(ShortSign);i::const_iterator iter=cmlParameter.begin(); + std::list::const_iterator iterEnd=cmlParameter.end(); + for(; iter!=iterEnd; ++iter) + { + CommandLineParameter* ptr=*iter; + ptr->printHelp( std::cout ); + std::cout << std::endl; + } + return; +} + +void CommandLineParser::printStatus() +{ + std::list::const_iterator iter=cmlParameter.begin(); + std::list::const_iterator iterEnd=cmlParameter.end(); + + for(; iter!=iterEnd; ++iter) + { + CommandLineParameter* ptr=*iter; + ptr->printStatus( std::cout ) << std::endl; + } + + std::cout <::const_iterator iter=cmlParameter.begin(); + std::list::const_iterator iterEnd=cmlParameter.end(); + string test; + string::size_type posStart, posEnd; + const char* spaceSep = " \t\v\f\n\r"; + const char* prgName = "program"; + std::vector argList; + char **argv=NULL; + unsigned int argc=0, i=0, n=0; + static unsigned int counter=1; + + if(!testCml) + { + std::cout << "Error: test_cml is null" << endl; + printStatus(); + return false; + } + + std::cout << "Test " << counter << " commandline='" << testCml << "'" << std::endl; + + //converting to argc, argv + test=testCml; + posEnd=0; + while(true) + { + posStart=test.find_first_not_of(spaceSep, posEnd); + if(posStart != string::npos) + { + posEnd=test.find_first_of(spaceSep, posStart); + if(posEnd != string::npos) + { + std::cout << "arg " << argList.size() + 1 << "='" << test.substr(posStart, posEnd-posStart) << "'" << std::endl; + argList.push_back(test.substr(posStart, posEnd-posStart)); + } + else //last element + { + std::cout << "arg " << argList.size() + 1 << "='" << test.substr(posStart, test.size()-posStart) << "'" << std::endl; + argList.push_back(test.substr(posStart, test.size()-posStart)); + break; + } + } + else + break; + } + + //build argv in C style + n=argList.size(); + argc = n + 1; + argv=new char*[ argc ]; + argv[0] = dupString(prgName); + for(i=0; i < n; i++) + argv[i + 1] = dupString(argList[i].c_str()); + + std::cout << "Test " << counter++ << " output:" << std::endl; + + try + { + //reset all options + for(; iter!=iterEnd; ++iter) + { + (*iter)->reset(); + } + //process commandline + processCommandLine(argc, argv); + } + catch(CmlException &e) + { + std::cout<<"Error: "<