/*
* 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: "<