ENH: Move command line argument parsing code to kwsys
This commit is contained in:
parent
3e03bed0ac
commit
c8fa658142
|
@ -78,6 +78,7 @@ IF(NOT KWSYS_NAMESPACE)
|
||||||
SET(KWSYS_USE_Process 1)
|
SET(KWSYS_USE_Process 1)
|
||||||
SET(KWSYS_USE_RegularExpression 1)
|
SET(KWSYS_USE_RegularExpression 1)
|
||||||
SET(KWSYS_USE_SystemTools 1)
|
SET(KWSYS_USE_SystemTools 1)
|
||||||
|
SET(KWSYS_USE_CommandLineArguments 1)
|
||||||
ENDIF(NOT KWSYS_NAMESPACE)
|
ENDIF(NOT KWSYS_NAMESPACE)
|
||||||
|
|
||||||
#-----------------------------------------------------------------------------
|
#-----------------------------------------------------------------------------
|
||||||
|
@ -248,12 +249,20 @@ IF(KWSYS_USE_SystemTools)
|
||||||
ENDIF(KWSYS_USE_SystemTools)
|
ENDIF(KWSYS_USE_SystemTools)
|
||||||
|
|
||||||
# Add selected C++ classes.
|
# Add selected C++ classes.
|
||||||
FOREACH(c Directory RegularExpression SystemTools)
|
FOREACH(c Directory RegularExpression SystemTools CommandLineArguments)
|
||||||
IF(KWSYS_USE_${c})
|
IF(KWSYS_USE_${c})
|
||||||
SET(KWSYS_CLASSES ${KWSYS_CLASSES} ${c})
|
SET(KWSYS_CLASSES ${KWSYS_CLASSES} ${c})
|
||||||
ENDIF(KWSYS_USE_${c})
|
ENDIF(KWSYS_USE_${c})
|
||||||
ENDFOREACH(c)
|
ENDFOREACH(c)
|
||||||
|
|
||||||
|
IF(KWSYS_USE_CommandLineArguments)
|
||||||
|
IF(NOT ParaView_SOURCE_DIR)
|
||||||
|
IF(NOT KWSYS_STANDALONE)
|
||||||
|
MESSAGE("Command Line Arguments is experimental code for now")
|
||||||
|
ENDIF(NOT KWSYS_STANDALONE)
|
||||||
|
ENDIF(NOT ParaView_SOURCE_DIR)
|
||||||
|
ENDIF(KWSYS_USE_CommandLineArguments)
|
||||||
|
|
||||||
# Add selected C components.
|
# Add selected C components.
|
||||||
FOREACH(c Process Base64)
|
FOREACH(c Process Base64)
|
||||||
IF(KWSYS_USE_${c})
|
IF(KWSYS_USE_${c})
|
||||||
|
@ -411,9 +420,11 @@ IF(KWSYS_STANDALONE)
|
||||||
ADD_EXECUTABLE(testIOS testIOS.cxx)
|
ADD_EXECUTABLE(testIOS testIOS.cxx)
|
||||||
ADD_EXECUTABLE(testProcess testProcess.c)
|
ADD_EXECUTABLE(testProcess testProcess.c)
|
||||||
ADD_EXECUTABLE(test1 test1.cxx)
|
ADD_EXECUTABLE(test1 test1.cxx)
|
||||||
|
ADD_EXECUTABLE(testCommandLineArguments testCommandLineArguments.cxx)
|
||||||
TARGET_LINK_LIBRARIES(testIOS ${KWSYS_NAMESPACE})
|
TARGET_LINK_LIBRARIES(testIOS ${KWSYS_NAMESPACE})
|
||||||
TARGET_LINK_LIBRARIES(testProcess ${KWSYS_NAMESPACE}_c)
|
TARGET_LINK_LIBRARIES(testProcess ${KWSYS_NAMESPACE}_c)
|
||||||
TARGET_LINK_LIBRARIES(test1 ${KWSYS_NAMESPACE})
|
TARGET_LINK_LIBRARIES(test1 ${KWSYS_NAMESPACE})
|
||||||
|
TARGET_LINK_LIBRARIES(testCommandLineArguments ${KWSYS_NAMESPACE})
|
||||||
|
|
||||||
IF(BUILD_TESTING)
|
IF(BUILD_TESTING)
|
||||||
ADD_TEST(testProcess-1 testProcess 1)
|
ADD_TEST(testProcess-1 testProcess 1)
|
||||||
|
|
|
@ -0,0 +1,591 @@
|
||||||
|
/*=========================================================================
|
||||||
|
|
||||||
|
Program: KWSys - Kitware System Library
|
||||||
|
Module: $RCSfile$
|
||||||
|
|
||||||
|
Copyright (c) Kitware, Inc., Insight Consortium. All rights reserved.
|
||||||
|
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
|
||||||
|
|
||||||
|
This software is distributed WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. See the above copyright notices for more information.
|
||||||
|
|
||||||
|
=========================================================================*/
|
||||||
|
#include "kwsysPrivate.h"
|
||||||
|
#include KWSYS_HEADER(CommandLineArguments.hxx)
|
||||||
|
|
||||||
|
#include KWSYS_HEADER(Configure.hxx)
|
||||||
|
|
||||||
|
#include KWSYS_HEADER(stl/vector)
|
||||||
|
#include KWSYS_HEADER(stl/map)
|
||||||
|
#include KWSYS_HEADER(stl/set)
|
||||||
|
#include KWSYS_HEADER(ios/sstream)
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
namespace KWSYS_NAMESPACE
|
||||||
|
{
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
//============================================================================
|
||||||
|
class CommandLineArgumentsString : public kwsys_stl::string
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef kwsys_stl::string StdString;
|
||||||
|
CommandLineArgumentsString(): StdString() {}
|
||||||
|
CommandLineArgumentsString(const value_type* s): StdString(s) {}
|
||||||
|
CommandLineArgumentsString(const value_type* s, size_type n): StdString(s, n) {}
|
||||||
|
CommandLineArgumentsString(const StdString& s, size_type pos=0, size_type n=npos):
|
||||||
|
StdString(s, pos, n) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class CommandLineArgumentsVectorOfStrings :
|
||||||
|
public kwsys_stl::vector<CommandLineArgumentsString> {};
|
||||||
|
class CommandLineArgumentsSetOfStrings :
|
||||||
|
public kwsys_stl::set<CommandLineArgumentsString> {};
|
||||||
|
class CommandLineArgumentsMapOfStrucs :
|
||||||
|
public kwsys_stl::map<CommandLineArgumentsString,
|
||||||
|
CommandLineArguments::CallbackStructure> {};
|
||||||
|
|
||||||
|
class CommandLineArgumentsInternal
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CommandLineArgumentsInternal()
|
||||||
|
{
|
||||||
|
this->UnknownArgumentCallback = 0;
|
||||||
|
this->ClientData = 0;
|
||||||
|
this->LastArgument = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef CommandLineArgumentsVectorOfStrings VectorOfStrings;
|
||||||
|
typedef CommandLineArgumentsMapOfStrucs CallbacksMap;
|
||||||
|
typedef CommandLineArgumentsString String;
|
||||||
|
typedef CommandLineArgumentsSetOfStrings SetOfStrings;
|
||||||
|
|
||||||
|
VectorOfStrings Argv;
|
||||||
|
CallbacksMap Callbacks;
|
||||||
|
|
||||||
|
CommandLineArguments::ErrorCallbackType UnknownArgumentCallback;
|
||||||
|
void* ClientData;
|
||||||
|
|
||||||
|
VectorOfStrings::size_type LastArgument;
|
||||||
|
};
|
||||||
|
//============================================================================
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
CommandLineArguments::CommandLineArguments()
|
||||||
|
{
|
||||||
|
this->Internals = new CommandLineArguments::Internal;
|
||||||
|
this->Help = "";
|
||||||
|
this->LineLength = 80;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
CommandLineArguments::~CommandLineArguments()
|
||||||
|
{
|
||||||
|
delete this->Internals;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void CommandLineArguments::Initialize(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
int cc;
|
||||||
|
|
||||||
|
this->Initialize();
|
||||||
|
for ( cc = 1; cc < argc; cc ++ )
|
||||||
|
{
|
||||||
|
this->ProcessArgument(argv[cc]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void CommandLineArguments::Initialize()
|
||||||
|
{
|
||||||
|
this->Internals->Argv.clear();
|
||||||
|
this->Internals->LastArgument = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void CommandLineArguments::ProcessArgument(const char* arg)
|
||||||
|
{
|
||||||
|
this->Internals->Argv.push_back(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
int CommandLineArguments::Parse()
|
||||||
|
{
|
||||||
|
CommandLineArguments::Internal::VectorOfStrings::size_type cc;
|
||||||
|
CommandLineArguments::Internal::VectorOfStrings matches;
|
||||||
|
for ( cc = 0; cc < this->Internals->Argv.size(); cc ++ )
|
||||||
|
{
|
||||||
|
matches.clear();
|
||||||
|
CommandLineArguments::Internal::String& arg = this->Internals->Argv[cc];
|
||||||
|
CommandLineArguments::Internal::CallbacksMap::iterator it;
|
||||||
|
|
||||||
|
// Does the argument match to any we know about?
|
||||||
|
for ( it = this->Internals->Callbacks.begin();
|
||||||
|
it != this->Internals->Callbacks.end();
|
||||||
|
it ++ )
|
||||||
|
{
|
||||||
|
const CommandLineArguments::Internal::String& parg = it->first;
|
||||||
|
CommandLineArguments::CallbackStructure *cs = &it->second;
|
||||||
|
if (cs->ArgumentType == CommandLineArguments::NO_ARGUMENT ||
|
||||||
|
cs->ArgumentType == CommandLineArguments::SPACE_ARGUMENT)
|
||||||
|
{
|
||||||
|
if ( arg == parg )
|
||||||
|
{
|
||||||
|
matches.push_back(parg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( arg.find( parg ) == 0 )
|
||||||
|
{
|
||||||
|
matches.push_back(parg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( matches.size() > 0 )
|
||||||
|
{
|
||||||
|
// Ok, we found one or more arguments that match what user specified.
|
||||||
|
// Let's find the longest one.
|
||||||
|
CommandLineArguments::Internal::VectorOfStrings::size_type kk;
|
||||||
|
CommandLineArguments::Internal::VectorOfStrings::size_type maxidx = 0;
|
||||||
|
CommandLineArguments::Internal::String::size_type maxlen = 0;
|
||||||
|
for ( kk = 0; kk < matches.size(); kk ++ )
|
||||||
|
{
|
||||||
|
if ( matches[kk].size() > maxlen )
|
||||||
|
{
|
||||||
|
maxlen = matches[kk].size();
|
||||||
|
maxidx = kk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// So, the longest one is probably the right one. Now see if it has any
|
||||||
|
// additional value
|
||||||
|
const char* value = 0;
|
||||||
|
CommandLineArguments::CallbackStructure *cs
|
||||||
|
= &this->Internals->Callbacks[matches[maxidx]];
|
||||||
|
const CommandLineArguments::Internal::String& sarg = matches[maxidx];
|
||||||
|
if ( cs->ArgumentType == NO_ARGUMENT )
|
||||||
|
{
|
||||||
|
// No value
|
||||||
|
}
|
||||||
|
else if ( cs->ArgumentType == SPACE_ARGUMENT )
|
||||||
|
{
|
||||||
|
if ( cc == this->Internals->Argv.size()-1 )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// Value is the next argument
|
||||||
|
value = this->Internals->Argv[cc+1].c_str();
|
||||||
|
cc ++;
|
||||||
|
}
|
||||||
|
else if ( cs->ArgumentType == EQUAL_ARGUMENT )
|
||||||
|
{
|
||||||
|
if ( arg.size() == sarg.size() || *(arg.c_str() + sarg.size()) != '=' )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// Value is everythng followed the '=' sign
|
||||||
|
value = arg.c_str() + sarg.size()+1;
|
||||||
|
}
|
||||||
|
else if ( cs->ArgumentType == CONCAT_ARGUMENT )
|
||||||
|
{
|
||||||
|
// Value is whatever follows the argument
|
||||||
|
value = arg.c_str() + sarg.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call the callback
|
||||||
|
if ( cs->Callback )
|
||||||
|
{
|
||||||
|
if ( !cs->Callback(sarg.c_str(), value, cs->CallData) )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( cs->Variable )
|
||||||
|
{
|
||||||
|
kwsys_stl::string var = "1";
|
||||||
|
if ( value )
|
||||||
|
{
|
||||||
|
var = value;
|
||||||
|
}
|
||||||
|
if ( cs->VariableType == CommandLineArguments::INT_TYPE )
|
||||||
|
{
|
||||||
|
int* variable = static_cast<int*>(cs->Variable);
|
||||||
|
char* res = 0;
|
||||||
|
*variable = strtol(var.c_str(), &res, 10);
|
||||||
|
//if ( res && *res )
|
||||||
|
// {
|
||||||
|
// Can handle non-int
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
else if ( cs->VariableType == CommandLineArguments::DOUBLE_TYPE )
|
||||||
|
{
|
||||||
|
double* variable = static_cast<double*>(cs->Variable);
|
||||||
|
char* res = 0;
|
||||||
|
*variable = strtod(var.c_str(), &res);
|
||||||
|
//if ( res && *res )
|
||||||
|
// {
|
||||||
|
// Can handle non-int
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
else if ( cs->VariableType == CommandLineArguments::STRING_TYPE )
|
||||||
|
{
|
||||||
|
char** variable = static_cast<char**>(cs->Variable);
|
||||||
|
if ( *variable )
|
||||||
|
{
|
||||||
|
delete [] *variable;
|
||||||
|
*variable = 0;
|
||||||
|
}
|
||||||
|
*variable = new char[ strlen(var.c_str()) + 1 ];
|
||||||
|
strcpy(*variable, var.c_str());
|
||||||
|
}
|
||||||
|
else if ( cs->VariableType == CommandLineArguments::STL_STRING_TYPE )
|
||||||
|
{
|
||||||
|
kwsys_stl::string* variable = static_cast<kwsys_stl::string*>(cs->Variable);
|
||||||
|
*variable = var;
|
||||||
|
}
|
||||||
|
else if ( cs->VariableType == CommandLineArguments::BOOL_TYPE )
|
||||||
|
{
|
||||||
|
bool* variable = static_cast<bool*>(cs->Variable);
|
||||||
|
if ( var == "1" || var == "ON" || var == "TRUE" || var == "true" || var == "on" ||
|
||||||
|
var == "True" || var == "yes" || var == "Yes" || var == "YES" )
|
||||||
|
{
|
||||||
|
*variable = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*variable = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cerr << "Got unknown argument type: \"" << cs->VariableType << "\"" << endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Handle unknown arguments
|
||||||
|
if ( this->Internals->UnknownArgumentCallback )
|
||||||
|
{
|
||||||
|
if ( !this->Internals->UnknownArgumentCallback(arg.c_str(),
|
||||||
|
this->Internals->ClientData) )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cerr << "Got unknown argument: \"" << arg.c_str() << "\"" << endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We are done parsing, so remember what was the last argument
|
||||||
|
this->Internals->LastArgument = cc;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void CommandLineArguments::GetRemainingArguments(int* argc, char*** argv)
|
||||||
|
{
|
||||||
|
CommandLineArguments::Internal::VectorOfStrings::size_type size
|
||||||
|
= this->Internals->Argv.size() - this->Internals->LastArgument + 1;
|
||||||
|
CommandLineArguments::Internal::VectorOfStrings::size_type cc;
|
||||||
|
|
||||||
|
char** args = new char*[ size ];
|
||||||
|
args[0] = new char[ this->Internals->Argv[0].size() + 1 ];
|
||||||
|
strcpy(args[0], this->Internals->Argv[0].c_str());
|
||||||
|
int cnt = 1;
|
||||||
|
for ( cc = this->Internals->LastArgument;
|
||||||
|
cc < this->Internals->Argv.size(); cc ++ )
|
||||||
|
{
|
||||||
|
args[cnt] = new char[ this->Internals->Argv[cc].size() + 1];
|
||||||
|
strcpy(args[cnt], this->Internals->Argv[cc].c_str());
|
||||||
|
cnt ++;
|
||||||
|
}
|
||||||
|
*argc = cnt;
|
||||||
|
*argv = args;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void CommandLineArguments::AddCallback(const char* argument, ArgumentTypeEnum type,
|
||||||
|
CallbackType callback, void* call_data, const char* help)
|
||||||
|
{
|
||||||
|
CommandLineArguments::CallbackStructure s;
|
||||||
|
s.Argument = argument;
|
||||||
|
s.ArgumentType = type;
|
||||||
|
s.Callback = callback;
|
||||||
|
s.CallData = call_data;
|
||||||
|
s.VariableType = CommandLineArguments::NO_VARIABLE_TYPE;
|
||||||
|
s.Variable = 0;
|
||||||
|
s.Help = help;
|
||||||
|
|
||||||
|
this->Internals->Callbacks[argument] = s;
|
||||||
|
this->GenerateHelp();
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
|
||||||
|
VariableTypeEnum vtype, void* variable, const char* help)
|
||||||
|
{
|
||||||
|
CommandLineArguments::CallbackStructure s;
|
||||||
|
s.Argument = argument;
|
||||||
|
s.ArgumentType = type;
|
||||||
|
s.Callback = 0;
|
||||||
|
s.CallData = 0;
|
||||||
|
s.VariableType = vtype;
|
||||||
|
s.Variable = variable;
|
||||||
|
s.Help = help;
|
||||||
|
|
||||||
|
this->Internals->Callbacks[argument] = s;
|
||||||
|
this->GenerateHelp();
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
|
||||||
|
int* variable, const char* help)
|
||||||
|
{
|
||||||
|
this->AddArgument(argument, type, CommandLineArguments::INT_TYPE, variable, help);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
|
||||||
|
double* variable, const char* help)
|
||||||
|
{
|
||||||
|
this->AddArgument(argument, type, CommandLineArguments::DOUBLE_TYPE, variable, help);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
|
||||||
|
char** variable, const char* help)
|
||||||
|
{
|
||||||
|
this->AddArgument(argument, type, CommandLineArguments::STRING_TYPE, variable, help);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
|
||||||
|
kwsys_stl::string* variable, const char* help)
|
||||||
|
{
|
||||||
|
this->AddArgument(argument, type, CommandLineArguments::STL_STRING_TYPE, variable, help);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
|
||||||
|
bool* variable, const char* help)
|
||||||
|
{
|
||||||
|
this->AddArgument(argument, type, CommandLineArguments::BOOL_TYPE, variable, help);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void CommandLineArguments::AddBooleanArgument(const char* argument, bool*
|
||||||
|
variable, const char* help)
|
||||||
|
{
|
||||||
|
this->AddArgument(argument, CommandLineArguments::NO_ARGUMENT,
|
||||||
|
CommandLineArguments::BOOL_TYPE, variable, help);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void CommandLineArguments::AddBooleanArgument(const char* argument, int*
|
||||||
|
variable, const char* help)
|
||||||
|
{
|
||||||
|
this->AddArgument(argument, CommandLineArguments::NO_ARGUMENT,
|
||||||
|
CommandLineArguments::INT_TYPE, variable, help);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void CommandLineArguments::SetClientData(void* client_data)
|
||||||
|
{
|
||||||
|
this->Internals->ClientData = client_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void CommandLineArguments::SetUnknownArgumentCallback(
|
||||||
|
CommandLineArguments::ErrorCallbackType callback)
|
||||||
|
{
|
||||||
|
this->Internals->UnknownArgumentCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
const char* CommandLineArguments::GetHelp(const char* arg)
|
||||||
|
{
|
||||||
|
CommandLineArguments::Internal::CallbacksMap::iterator it
|
||||||
|
= this->Internals->Callbacks.find(arg);
|
||||||
|
if ( it == this->Internals->Callbacks.end() )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since several arguments may point to the same argument, find the one this
|
||||||
|
// one point to if this one is pointing to another argument.
|
||||||
|
CommandLineArguments::CallbackStructure *cs = &(it->second);
|
||||||
|
while ( 1 )
|
||||||
|
{
|
||||||
|
CommandLineArguments::Internal::CallbacksMap::iterator hit
|
||||||
|
= this->Internals->Callbacks.find(cs->Help);
|
||||||
|
if ( hit == this->Internals->Callbacks.end() )
|
||||||
|
{
|
||||||
|
return cs->Help;
|
||||||
|
}
|
||||||
|
cs = &(hit->second);
|
||||||
|
}
|
||||||
|
// Should never happened
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void CommandLineArguments::GenerateHelp()
|
||||||
|
{
|
||||||
|
kwsys_ios::ostringstream str;
|
||||||
|
|
||||||
|
// Collapse all arguments into the map of vectors of all arguments that do
|
||||||
|
// the same thing.
|
||||||
|
CommandLineArguments::Internal::CallbacksMap::iterator it;
|
||||||
|
typedef kwsys_stl::map<CommandLineArguments::Internal::String,
|
||||||
|
CommandLineArguments::Internal::SetOfStrings > MapArgs;
|
||||||
|
MapArgs mp;
|
||||||
|
MapArgs::iterator mpit, smpit;
|
||||||
|
for ( it = this->Internals->Callbacks.begin();
|
||||||
|
it != this->Internals->Callbacks.end();
|
||||||
|
it ++ )
|
||||||
|
{
|
||||||
|
CommandLineArguments::CallbackStructure *cs = &(it->second);
|
||||||
|
mpit = mp.find(cs->Help);
|
||||||
|
if ( mpit != mp.end() )
|
||||||
|
{
|
||||||
|
mpit->second.insert(it->first);
|
||||||
|
mp[it->first].insert(it->first);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mp[it->first].insert(it->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for ( it = this->Internals->Callbacks.begin();
|
||||||
|
it != this->Internals->Callbacks.end();
|
||||||
|
it ++ )
|
||||||
|
{
|
||||||
|
CommandLineArguments::CallbackStructure *cs = &(it->second);
|
||||||
|
mpit = mp.find(cs->Help);
|
||||||
|
if ( mpit != mp.end() )
|
||||||
|
{
|
||||||
|
mpit->second.insert(it->first);
|
||||||
|
smpit = mp.find(it->first);
|
||||||
|
CommandLineArguments::Internal::SetOfStrings::iterator sit;
|
||||||
|
for ( sit = smpit->second.begin(); sit != smpit->second.end(); sit++ )
|
||||||
|
{
|
||||||
|
mpit->second.insert(*sit);
|
||||||
|
}
|
||||||
|
mp.erase(smpit);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mp[it->first].insert(it->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the length of the longest string
|
||||||
|
CommandLineArguments::Internal::String::size_type maxlen = 0;
|
||||||
|
for ( mpit = mp.begin();
|
||||||
|
mpit != mp.end();
|
||||||
|
mpit ++ )
|
||||||
|
{
|
||||||
|
CommandLineArguments::Internal::SetOfStrings::iterator sit;
|
||||||
|
for ( sit = mpit->second.begin(); sit != mpit->second.end(); sit++ )
|
||||||
|
{
|
||||||
|
CommandLineArguments::Internal::String::size_type clen = sit->size();
|
||||||
|
switch ( this->Internals->Callbacks[*sit].ArgumentType )
|
||||||
|
{
|
||||||
|
case CommandLineArguments::NO_ARGUMENT: clen += 0; break;
|
||||||
|
case CommandLineArguments::CONCAT_ARGUMENT: clen += 6; break;
|
||||||
|
case CommandLineArguments::SPACE_ARGUMENT: clen += 7; break;
|
||||||
|
case CommandLineArguments::EQUAL_ARGUMENT: clen += 7; break;
|
||||||
|
}
|
||||||
|
if ( clen > maxlen )
|
||||||
|
{
|
||||||
|
maxlen = clen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create format for that string
|
||||||
|
char format[80];
|
||||||
|
sprintf(format, "%%%ds", static_cast<unsigned int>(maxlen));
|
||||||
|
|
||||||
|
|
||||||
|
// Print help for each option
|
||||||
|
for ( mpit = mp.begin();
|
||||||
|
mpit != mp.end();
|
||||||
|
mpit ++ )
|
||||||
|
{
|
||||||
|
CommandLineArguments::Internal::SetOfStrings::iterator sit;
|
||||||
|
for ( sit = mpit->second.begin(); sit != mpit->second.end(); sit++ )
|
||||||
|
{
|
||||||
|
str << endl;
|
||||||
|
char argument[100];
|
||||||
|
sprintf(argument, sit->c_str());
|
||||||
|
switch ( this->Internals->Callbacks[*sit].ArgumentType )
|
||||||
|
{
|
||||||
|
case CommandLineArguments::NO_ARGUMENT: break;
|
||||||
|
case CommandLineArguments::CONCAT_ARGUMENT: strcat(argument, "option"); break;
|
||||||
|
case CommandLineArguments::SPACE_ARGUMENT: strcat(argument, " option"); break;
|
||||||
|
case CommandLineArguments::EQUAL_ARGUMENT: strcat(argument, "=option"); break;
|
||||||
|
}
|
||||||
|
char buffer[80];
|
||||||
|
sprintf(buffer, format, argument);
|
||||||
|
str << buffer;
|
||||||
|
}
|
||||||
|
str << "\t";
|
||||||
|
const char* ptr = this->Internals->Callbacks[mpit->first].Help;
|
||||||
|
int len = strlen(ptr);
|
||||||
|
int cnt = 0;
|
||||||
|
while ( len > 0)
|
||||||
|
{
|
||||||
|
// If argument with help is longer than line length, split it on previous
|
||||||
|
// space (or tab) and continue on the next line
|
||||||
|
CommandLineArguments::Internal::String::size_type cc;
|
||||||
|
for ( cc = 0; ptr[cc]; cc ++ )
|
||||||
|
{
|
||||||
|
if ( *ptr == ' ' || *ptr == '\t' )
|
||||||
|
{
|
||||||
|
ptr ++;
|
||||||
|
len --;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( cnt > 0 )
|
||||||
|
{
|
||||||
|
for ( cc = 0; cc < maxlen; cc ++ )
|
||||||
|
{
|
||||||
|
str << " ";
|
||||||
|
}
|
||||||
|
str << "\t";
|
||||||
|
}
|
||||||
|
CommandLineArguments::Internal::String::size_type skip = len;
|
||||||
|
if ( skip > this->LineLength - maxlen )
|
||||||
|
{
|
||||||
|
skip = this->LineLength - maxlen;
|
||||||
|
for ( cc = skip-1; cc > 0; cc -- )
|
||||||
|
{
|
||||||
|
if ( ptr[cc] == ' ' || ptr[cc] == '\t' )
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( cc != 0 )
|
||||||
|
{
|
||||||
|
skip = cc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
str.write(ptr, skip);
|
||||||
|
str << endl;
|
||||||
|
ptr += skip;
|
||||||
|
len -= skip;
|
||||||
|
cnt ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this->Help = str.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace KWSYS_NAMESPACE
|
|
@ -0,0 +1,173 @@
|
||||||
|
/*=========================================================================
|
||||||
|
|
||||||
|
Program: KWSys - Kitware System Library
|
||||||
|
Module: $RCSfile$
|
||||||
|
|
||||||
|
Copyright (c) Kitware, Inc., Insight Consortium. All rights reserved.
|
||||||
|
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
|
||||||
|
|
||||||
|
This software is distributed WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. See the above copyright notices for more information.
|
||||||
|
|
||||||
|
=========================================================================*/
|
||||||
|
#ifndef @KWSYS_NAMESPACE@_CommandLineArguments_hxx
|
||||||
|
#define @KWSYS_NAMESPACE@_CommandLineArguments_hxx
|
||||||
|
|
||||||
|
#include <@KWSYS_NAMESPACE@/Configure.h>
|
||||||
|
#include <@KWSYS_NAMESPACE@/Configure.hxx>
|
||||||
|
|
||||||
|
#include <@KWSYS_NAMESPACE@/stl/string>
|
||||||
|
|
||||||
|
/* Define this macro temporarily to keep the code readable. */
|
||||||
|
#if !defined (KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
|
||||||
|
# define kwsys_stl @KWSYS_NAMESPACE@_stl
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace @KWSYS_NAMESPACE@
|
||||||
|
{
|
||||||
|
|
||||||
|
class CommandLineArgumentsInternal;
|
||||||
|
|
||||||
|
/** \class CommandLineArguments
|
||||||
|
* \brief Command line arguments processing code.
|
||||||
|
*
|
||||||
|
* Find specified arguments with optional options and execute specified methods
|
||||||
|
* or set given variables.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class @KWSYS_NAMESPACE@_EXPORT CommandLineArguments
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CommandLineArguments();
|
||||||
|
~CommandLineArguments();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Various argument types.
|
||||||
|
*/
|
||||||
|
enum ArgumentTypeEnum {
|
||||||
|
NO_ARGUMENT, // The option takes no argument --foo
|
||||||
|
CONCAT_ARGUMENT,// The option takes argument after no space --foobar
|
||||||
|
SPACE_ARGUMENT, // The option takes argument after space --foo bar
|
||||||
|
EQUAL_ARGUMENT // The option takes argument after equal --foo=bar
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Various string types.
|
||||||
|
*/
|
||||||
|
enum VariableTypeEnum {
|
||||||
|
NO_VARIABLE_TYPE = 0, // The variable is not specified
|
||||||
|
INT_TYPE, // The variable is integer (int)
|
||||||
|
BOOL_TYPE, // The vairable is boolean (bool)
|
||||||
|
DOUBLE_TYPE, // The variable is float (double)
|
||||||
|
STRING_TYPE, // The variable is string (char*)
|
||||||
|
STL_STRING_TYPE // The variable is string (char*)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prototypes for callbacks for callback interface.
|
||||||
|
*/
|
||||||
|
typedef int(*CallbackType)(const char* argument, const char* value,
|
||||||
|
void* call_data);
|
||||||
|
typedef int(*ErrorCallbackType)(const char* argument, void* client_data);
|
||||||
|
|
||||||
|
struct CallbackStructure
|
||||||
|
{
|
||||||
|
const char* Argument;
|
||||||
|
int ArgumentType;
|
||||||
|
CallbackType Callback;
|
||||||
|
void* CallData;
|
||||||
|
void* Variable;
|
||||||
|
int VariableType;
|
||||||
|
const char* Help;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize internal data structures. This should be called before parsing.
|
||||||
|
*/
|
||||||
|
void Initialize(int argc, char* argv[]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize internal data structure and pass arguments one by one. This is
|
||||||
|
* convinience method for use from scripting languages where argc and argv
|
||||||
|
* are not available.
|
||||||
|
*/
|
||||||
|
void Initialize();
|
||||||
|
void ProcessArgument(const char* arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will parse arguments and call apropriate methods.
|
||||||
|
*/
|
||||||
|
int Parse();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will add a callback for a specific argument. The arguments to
|
||||||
|
* it are argument, argument type, callback method, and call data. The
|
||||||
|
* argument help specifies the help string used with this option. The
|
||||||
|
* callback and call_data can be skipped.
|
||||||
|
*/
|
||||||
|
void AddCallback(const char* argument, ArgumentTypeEnum type, CallbackType callback,
|
||||||
|
void* call_data, const char* help);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add handler for argument which is going to set the variable to the
|
||||||
|
* specified value.
|
||||||
|
*/
|
||||||
|
void AddArgument(const char* argument, ArgumentTypeEnum type, VariableTypeEnum vtype, void* variable, const char* help);
|
||||||
|
void AddArgument(const char* argument, ArgumentTypeEnum type, bool* variable, const char* help);
|
||||||
|
void AddArgument(const char* argument, ArgumentTypeEnum type, int* variable, const char* help);
|
||||||
|
void AddArgument(const char* argument, ArgumentTypeEnum type, double* variable, const char* help);
|
||||||
|
void AddArgument(const char* argument, ArgumentTypeEnum type, char** variable, const char* help);
|
||||||
|
void AddArgument(const char* argument, ArgumentTypeEnum type, kwsys_stl::string* variable, const char* help);
|
||||||
|
void AddBooleanArgument(const char* argument, bool* variable, const char* help);
|
||||||
|
void AddBooleanArgument(const char* argument, int* variable, const char* help);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the callbacks for error handling.
|
||||||
|
*/
|
||||||
|
void SetClientData(void* client_data);
|
||||||
|
void SetUnknownArgumentCallback(ErrorCallbackType callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get remaining arguments. It allocates space for argv, so you have to call
|
||||||
|
* delete[] on it.
|
||||||
|
*/
|
||||||
|
void GetRemainingArguments(int* argc, char*** argv);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return string containing help. If the argument is specified, only return
|
||||||
|
* help for that argument.
|
||||||
|
*/
|
||||||
|
const char* GetHelp() { return this->Help.c_str(); }
|
||||||
|
const char* GetHelp(const char* arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get / Set the help line length. Default length is 80.
|
||||||
|
*/
|
||||||
|
void SetLineLength();
|
||||||
|
unsigned int GetLineLength();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void GenerateHelp();
|
||||||
|
|
||||||
|
typedef CommandLineArgumentsInternal Internal;
|
||||||
|
Internal* Internals;
|
||||||
|
kwsys_stl::string Help;
|
||||||
|
|
||||||
|
unsigned int LineLength;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace @KWSYS_NAMESPACE@
|
||||||
|
|
||||||
|
/* Undefine temporary macro. */
|
||||||
|
#if !defined (KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
|
||||||
|
# undef kwsys_stl
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*=========================================================================
|
||||||
|
|
||||||
|
Program: KWSys - Kitware System Library
|
||||||
|
Module: $RCSfile$
|
||||||
|
|
||||||
|
Copyright (c) Kitware, Inc., Insight Consortium. All rights reserved.
|
||||||
|
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
|
||||||
|
|
||||||
|
This software is distributed WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. See the above copyright notices for more information.
|
||||||
|
|
||||||
|
=========================================================================*/
|
||||||
|
#include <kwsys/CommandLineArguments.hxx>
|
||||||
|
|
||||||
|
void* random_ptr = (void*)0x123;
|
||||||
|
|
||||||
|
int argument(const char* arg, const char* value, void* call_data)
|
||||||
|
{
|
||||||
|
cout << "Got argument: \"" << arg << "\" value: \"" << (value?value:"(null)") << "\"" << endl;
|
||||||
|
if ( call_data != random_ptr )
|
||||||
|
{
|
||||||
|
cerr << "Problem processing call_data" << endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int unknown_argument(const char* argument, void* call_data)
|
||||||
|
{
|
||||||
|
cout << "Got unknown argument: \"" << argument << "\"" << endl;
|
||||||
|
if ( call_data != random_ptr )
|
||||||
|
{
|
||||||
|
cerr << "Problem processing call_data" << endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
// Example run: ./testCommandLineArguments --some-int-variable 4
|
||||||
|
// --another-bool-variable --some-bool-variable=yes
|
||||||
|
// --some-stl-string-variable=foobar --set-bool-arg1 --set-bool-arg2
|
||||||
|
// --some-string-variable=hello
|
||||||
|
|
||||||
|
int res = 0;
|
||||||
|
kwsys::CommandLineArguments arg;
|
||||||
|
arg.Initialize(argc, argv);
|
||||||
|
|
||||||
|
// For error handling
|
||||||
|
arg.SetClientData(random_ptr);
|
||||||
|
arg.SetUnknownArgumentCallback(unknown_argument);
|
||||||
|
|
||||||
|
int some_int_variable = 10;
|
||||||
|
double some_double_variable = 10.10;
|
||||||
|
char* some_string_variable = 0;
|
||||||
|
kwsys_stl::string some_stl_string_variable = "";
|
||||||
|
bool some_bool_variable = false;
|
||||||
|
bool some_bool_variable1 = false;
|
||||||
|
bool bool_arg1 = false;
|
||||||
|
int bool_arg2 = 0;
|
||||||
|
|
||||||
|
typedef kwsys::CommandLineArguments argT;
|
||||||
|
|
||||||
|
arg.AddArgument("--some-int-variable", argT::SPACE_ARGUMENT, &some_int_variable, "Set some random int variable");
|
||||||
|
arg.AddArgument("--some-double-variable", argT::CONCAT_ARGUMENT, &some_double_variable, "Set some random double variable");
|
||||||
|
arg.AddArgument("--some-string-variable", argT::EQUAL_ARGUMENT, &some_string_variable, "Set some random string variable");
|
||||||
|
arg.AddArgument("--some-stl-string-variable", argT::EQUAL_ARGUMENT, &some_stl_string_variable, "Set some random stl string variable");
|
||||||
|
arg.AddArgument("--some-bool-variable", argT::EQUAL_ARGUMENT, &some_bool_variable, "Set some random bool variable");
|
||||||
|
arg.AddArgument("--another-bool-variable", argT::NO_ARGUMENT, &some_bool_variable1, "Set some random bool variable 1");
|
||||||
|
arg.AddBooleanArgument("--set-bool-arg1", &bool_arg1, "Test AddBooleanArgument 1");
|
||||||
|
arg.AddBooleanArgument("--set-bool-arg2", &bool_arg2, "Test AddBooleanArgument 2");
|
||||||
|
|
||||||
|
arg.AddCallback("-A", argT::NO_ARGUMENT, argument, random_ptr, "Some option -A. This option has a multiline comment. It should demonstrate how the code splits lines.");
|
||||||
|
arg.AddCallback("-B", argT::SPACE_ARGUMENT, argument, random_ptr, "Option -B takes argument with space");
|
||||||
|
arg.AddCallback("-C", argT::EQUAL_ARGUMENT, argument, random_ptr, "Option -C takes argument after =");
|
||||||
|
arg.AddCallback("-D", argT::CONCAT_ARGUMENT, argument, random_ptr, "This option takes concatinated argument");
|
||||||
|
arg.AddCallback("--long1", argT::NO_ARGUMENT, argument, random_ptr, "-A");
|
||||||
|
arg.AddCallback("--long2", argT::SPACE_ARGUMENT, argument, random_ptr, "-B");
|
||||||
|
arg.AddCallback("--long3", argT::EQUAL_ARGUMENT, argument, random_ptr, "Same as -C but a bit different");
|
||||||
|
arg.AddCallback("--long4", argT::CONCAT_ARGUMENT, argument, random_ptr, "-C");
|
||||||
|
|
||||||
|
if ( !arg.Parse() )
|
||||||
|
{
|
||||||
|
cerr << "Problem parsing arguments" << endl;
|
||||||
|
res = 1;
|
||||||
|
}
|
||||||
|
cout << "Help: " << arg.GetHelp() << endl;
|
||||||
|
|
||||||
|
cout << "Some int variable was set to: " << some_int_variable << endl;
|
||||||
|
cout << "Some double variable was set to: " << some_double_variable << endl;
|
||||||
|
if ( some_string_variable )
|
||||||
|
{
|
||||||
|
cout << "Some string variable was set to: " << some_string_variable << endl;
|
||||||
|
delete [] some_string_variable;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cerr << "Problem setting string variable" << endl;
|
||||||
|
res = 1;
|
||||||
|
}
|
||||||
|
cout << "Some STL String variable was set to: " << some_stl_string_variable.c_str() << endl;
|
||||||
|
cout << "Some bool variable was set to: " << some_bool_variable << endl;
|
||||||
|
cout << "Some bool variable was set to: " << some_bool_variable1 << endl;
|
||||||
|
cout << "bool_arg1 variable was set to: " << bool_arg1 << endl;
|
||||||
|
cout << "bool_arg2 variable was set to: " << bool_arg2 << endl;
|
||||||
|
cout << endl;
|
||||||
|
return res;
|
||||||
|
}
|
Loading…
Reference in New Issue