/* * 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; } } } bool CommandLineParameter::doesMatch(char c) { if(shortName==CommandLineParser::noShortName) return false; return shortName==c ? true:false; } bool CommandLineParameter::doesMatch(const char* s) { if(longName==NULL) return false; if(s == NULL) return false; if(!strcmp(longName, CommandLineParser::noLongName)) return false; return strcmp(longName,s)==0 ? true:false; } char CommandLineParameter::getShortName() const { return shortName; } const char* CommandLineParameter::getLongName() const { return longName; } /// print help text, composed from the option descriptions passwd to cml ostream& CommandLineParameter::printHelp(ostream &os) { if(descriptionText == NULL) return os; static const unsigned int longNameLen=30; static const unsigned int longParamLen=30; os << CommandLineParameter::descIndent; if(isalnum(shortName) && (shortName != CommandLineParser::noShortName)) os<< CommandLineParser::ShortSign <" 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: "<