CMake/CommandLineArguments.cxx

858 lines
26 KiB
C++
Raw Normal View History

/*============================================================================
KWSys - Kitware System Library
Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
Distributed under the OSI-approved BSD License (the "License");
see accompanying file Copyright.txt for details.
This software is distributed WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the License for more information.
============================================================================*/
#include "kwsysPrivate.h"
#include KWSYS_HEADER(CommandLineArguments.hxx)
#include KWSYS_HEADER(Configure.hxx)
#include KWSYS_HEADER(String.hxx)
// Work-around CMake dependency scanning limitation. This must
// duplicate the above list of headers.
#if 0
# include "CommandLineArguments.hxx.in"
# include "Configure.hxx.in"
# include "String.hxx.in"
#endif
#include <vector>
#include <map>
#include <set>
#include <sstream>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _MSC_VER
# pragma warning (disable: 4786)
#endif
#if defined(__sgi) && !defined(__GNUC__)
# pragma set woff 1375 /* base class destructor not virtual */
#endif
#if 0
# define CommandLineArguments_DEBUG(x) \
std::cout << __LINE__ << " CLA: " << x << std::endl
#else
# define CommandLineArguments_DEBUG(x)
#endif
namespace KWSYS_NAMESPACE
{
//----------------------------------------------------------------------------
//============================================================================
struct CommandLineArgumentsCallbackStructure
{
const char* Argument;
int ArgumentType;
CommandLineArguments::CallbackType Callback;
void* CallData;
void* Variable;
int VariableType;
const char* Help;
};
class CommandLineArgumentsVectorOfStrings :
public std::vector<kwsys::String> {};
class CommandLineArgumentsSetOfStrings :
public std::set<kwsys::String> {};
class CommandLineArgumentsMapOfStrucs :
public std::map<kwsys::String,
CommandLineArgumentsCallbackStructure> {};
class CommandLineArgumentsInternal
{
public:
CommandLineArgumentsInternal()
{
this->UnknownArgumentCallback = 0;
this->ClientData = 0;
this->LastArgument = 0;
}
typedef CommandLineArgumentsVectorOfStrings VectorOfStrings;
typedef CommandLineArgumentsMapOfStrucs CallbacksMap;
typedef kwsys::String String;
typedef CommandLineArgumentsSetOfStrings SetOfStrings;
VectorOfStrings Argv;
String Argv0;
CallbacksMap Callbacks;
CommandLineArguments::ErrorCallbackType UnknownArgumentCallback;
void* ClientData;
VectorOfStrings::size_type LastArgument;
VectorOfStrings UnusedArguments;
};
//============================================================================
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
CommandLineArguments::CommandLineArguments()
{
this->Internals = new CommandLineArguments::Internal;
this->Help = "";
this->LineLength = 80;
this->StoreUnusedArgumentsFlag = false;
}
//----------------------------------------------------------------------------
CommandLineArguments::~CommandLineArguments()
{
delete this->Internals;
}
//----------------------------------------------------------------------------
void CommandLineArguments::Initialize(int argc, const char* const argv[])
{
int cc;
this->Initialize();
this->Internals->Argv0 = argv[0];
for ( cc = 1; cc < argc; cc ++ )
{
this->ProcessArgument(argv[cc]);
}
}
//----------------------------------------------------------------------------
void CommandLineArguments::Initialize(int argc, char* argv[])
{
this->Initialize(argc, static_cast<const char* const*>(argv));
}
//----------------------------------------------------------------------------
void CommandLineArguments::Initialize()
{
this->Internals->Argv.clear();
this->Internals->LastArgument = 0;
}
//----------------------------------------------------------------------------
void CommandLineArguments::ProcessArgument(const char* arg)
{
this->Internals->Argv.push_back(arg);
}
//----------------------------------------------------------------------------
bool CommandLineArguments::GetMatchedArguments(
std::vector<std::string>* matches,
const std::string& arg)
{
matches->clear();
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;
CommandLineArgumentsCallbackStructure *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);
}
}
KWSys 2014-05-07 (6074f33f) Extract upstream KWSys using the following shell commands. $ git archive --prefix=upstream-kwsys/ 6074f33f | tar x $ git shortlog --no-merges --abbrev=8 --format='%h %s' f3a36760..6074f33f Ben Boeckel (22): ef3bfa01 c_str: Don't use .c_str() when streaming strings 9c165368 Glob: Use string comparisons if you have them ready 53ba0bc6 containers: Use .empty() instead of .size() where possible 6cbb57ac strings: Use string methods instead of size calculations e53596b7 RegularExpression: Add string overloads aec9de6a CommandLineArguments: Push the string back, not its C string 1d531416 Glob: Accept a string in Glob::AddFile 81f5e0a8 Glob: Accept a string in Glob::AddExpression d40c2706 SystemTools: Remove redundant if guards c1296f4a SystemTools: Defer computing length until after a .empty() check 7ffb7106 SystemTools: Use the iterator constructor for strings 29e3b1d8 SystemTools: Use .rfind('/') rather than .find_last_of("/") 5eb3a65c SystemTools: Don't construct a string just for its length b07b5fc1 SystemTools: Take a string in GetShortPath 153f6df7 SystemTools: Use strings in ComparePath 2c2f6604 SystemTools: Accept strings in IsSubDirectory 84db9ee5 SystemTools: Take strings in AddTranslationPath 4b409aa4 SystemTools: Take strings in SplitPath d2dbff07 SystemTools: Take strings in CollapseFullPath e9204f8f SystemTools: Take strings in AddKeepPath 3254681a SystemTools: Reserve memory in JoinPath 6074f33f SystemTools: Use static strings in SystemToolsAppendComponents Change-Id: I53c7a1005206dba43ee785bf807c478bf146ca0e
2014-05-08 00:31:11 +04:00
return !matches->empty();
}
//----------------------------------------------------------------------------
int CommandLineArguments::Parse()
{
std::vector<std::string>::size_type cc;
std::vector<std::string> matches;
if ( this->StoreUnusedArgumentsFlag )
{
this->Internals->UnusedArguments.clear();
}
for ( cc = 0; cc < this->Internals->Argv.size(); cc ++ )
{
const std::string& arg = this->Internals->Argv[cc];
CommandLineArguments_DEBUG("Process argument: " << arg);
this->Internals->LastArgument = cc;
if ( this->GetMatchedArguments(&matches, arg) )
{
// 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
CommandLineArgumentsCallbackStructure *cs
= &this->Internals->Callbacks[matches[maxidx]];
const std::string& sarg = matches[maxidx];
if ( cs->Argument != sarg )
{
abort();
}
switch ( cs->ArgumentType )
{
case NO_ARGUMENT:
// No value
if ( !this->PopulateVariable(cs, 0) )
{
return 0;
}
break;
case SPACE_ARGUMENT:
if ( cc == this->Internals->Argv.size()-1 )
{
this->Internals->LastArgument --;
return 0;
}
CommandLineArguments_DEBUG("This is a space argument: " << arg
KWSys 2014-05-07 (6074f33f) Extract upstream KWSys using the following shell commands. $ git archive --prefix=upstream-kwsys/ 6074f33f | tar x $ git shortlog --no-merges --abbrev=8 --format='%h %s' f3a36760..6074f33f Ben Boeckel (22): ef3bfa01 c_str: Don't use .c_str() when streaming strings 9c165368 Glob: Use string comparisons if you have them ready 53ba0bc6 containers: Use .empty() instead of .size() where possible 6cbb57ac strings: Use string methods instead of size calculations e53596b7 RegularExpression: Add string overloads aec9de6a CommandLineArguments: Push the string back, not its C string 1d531416 Glob: Accept a string in Glob::AddFile 81f5e0a8 Glob: Accept a string in Glob::AddExpression d40c2706 SystemTools: Remove redundant if guards c1296f4a SystemTools: Defer computing length until after a .empty() check 7ffb7106 SystemTools: Use the iterator constructor for strings 29e3b1d8 SystemTools: Use .rfind('/') rather than .find_last_of("/") 5eb3a65c SystemTools: Don't construct a string just for its length b07b5fc1 SystemTools: Take a string in GetShortPath 153f6df7 SystemTools: Use strings in ComparePath 2c2f6604 SystemTools: Accept strings in IsSubDirectory 84db9ee5 SystemTools: Take strings in AddTranslationPath 4b409aa4 SystemTools: Take strings in SplitPath d2dbff07 SystemTools: Take strings in CollapseFullPath e9204f8f SystemTools: Take strings in AddKeepPath 3254681a SystemTools: Reserve memory in JoinPath 6074f33f SystemTools: Use static strings in SystemToolsAppendComponents Change-Id: I53c7a1005206dba43ee785bf807c478bf146ca0e
2014-05-08 00:31:11 +04:00
<< " value: " << this->Internals->Argv[cc+1]);
// Value is the next argument
if ( !this->PopulateVariable(cs, this->Internals->Argv[cc+1].c_str()) )
{
return 0;
}
cc ++;
break;
case EQUAL_ARGUMENT:
KWSys 2014-05-07 (6074f33f) Extract upstream KWSys using the following shell commands. $ git archive --prefix=upstream-kwsys/ 6074f33f | tar x $ git shortlog --no-merges --abbrev=8 --format='%h %s' f3a36760..6074f33f Ben Boeckel (22): ef3bfa01 c_str: Don't use .c_str() when streaming strings 9c165368 Glob: Use string comparisons if you have them ready 53ba0bc6 containers: Use .empty() instead of .size() where possible 6cbb57ac strings: Use string methods instead of size calculations e53596b7 RegularExpression: Add string overloads aec9de6a CommandLineArguments: Push the string back, not its C string 1d531416 Glob: Accept a string in Glob::AddFile 81f5e0a8 Glob: Accept a string in Glob::AddExpression d40c2706 SystemTools: Remove redundant if guards c1296f4a SystemTools: Defer computing length until after a .empty() check 7ffb7106 SystemTools: Use the iterator constructor for strings 29e3b1d8 SystemTools: Use .rfind('/') rather than .find_last_of("/") 5eb3a65c SystemTools: Don't construct a string just for its length b07b5fc1 SystemTools: Take a string in GetShortPath 153f6df7 SystemTools: Use strings in ComparePath 2c2f6604 SystemTools: Accept strings in IsSubDirectory 84db9ee5 SystemTools: Take strings in AddTranslationPath 4b409aa4 SystemTools: Take strings in SplitPath d2dbff07 SystemTools: Take strings in CollapseFullPath e9204f8f SystemTools: Take strings in AddKeepPath 3254681a SystemTools: Reserve memory in JoinPath 6074f33f SystemTools: Use static strings in SystemToolsAppendComponents Change-Id: I53c7a1005206dba43ee785bf807c478bf146ca0e
2014-05-08 00:31:11 +04:00
if ( arg.size() == sarg.size() || arg.at(sarg.size()) != '=' )
{
this->Internals->LastArgument --;
return 0;
}
// Value is everythng followed the '=' sign
if ( !this->PopulateVariable(cs, arg.c_str() + sarg.size() + 1) )
{
return 0;
}
break;
case CONCAT_ARGUMENT:
// Value is whatever follows the argument
if ( !this->PopulateVariable(cs, arg.c_str() + sarg.size()) )
{
return 0;
}
break;
case MULTI_ARGUMENT:
// Suck in all the rest of the arguments
CommandLineArguments_DEBUG("This is a multi argument: " << arg);
for (cc++; cc < this->Internals->Argv.size(); ++ cc )
{
const std::string& marg = this->Internals->Argv[cc];
CommandLineArguments_DEBUG(" check multi argument value: " << marg);
if ( this->GetMatchedArguments(&matches, marg) )
{
CommandLineArguments_DEBUG("End of multi argument " << arg << " with value: " << marg);
break;
}
CommandLineArguments_DEBUG(" populate multi argument value: " << marg);
if ( !this->PopulateVariable(cs, marg.c_str()) )
{
return 0;
}
}
if ( cc != this->Internals->Argv.size() )
{
CommandLineArguments_DEBUG("Again End of multi argument " << arg);
cc--;
continue;
}
break;
default:
std::cerr << "Got unknown argument type: \"" << cs->ArgumentType << "\"" << std::endl;
this->Internals->LastArgument --;
return 0;
}
}
else
{
// Handle unknown arguments
if ( this->Internals->UnknownArgumentCallback )
{
if ( !this->Internals->UnknownArgumentCallback(arg.c_str(),
this->Internals->ClientData) )
{
this->Internals->LastArgument --;
return 0;
}
return 1;
}
else if ( this->StoreUnusedArgumentsFlag )
{
CommandLineArguments_DEBUG("Store unused argument " << arg);
KWSys 2014-05-07 (6074f33f) Extract upstream KWSys using the following shell commands. $ git archive --prefix=upstream-kwsys/ 6074f33f | tar x $ git shortlog --no-merges --abbrev=8 --format='%h %s' f3a36760..6074f33f Ben Boeckel (22): ef3bfa01 c_str: Don't use .c_str() when streaming strings 9c165368 Glob: Use string comparisons if you have them ready 53ba0bc6 containers: Use .empty() instead of .size() where possible 6cbb57ac strings: Use string methods instead of size calculations e53596b7 RegularExpression: Add string overloads aec9de6a CommandLineArguments: Push the string back, not its C string 1d531416 Glob: Accept a string in Glob::AddFile 81f5e0a8 Glob: Accept a string in Glob::AddExpression d40c2706 SystemTools: Remove redundant if guards c1296f4a SystemTools: Defer computing length until after a .empty() check 7ffb7106 SystemTools: Use the iterator constructor for strings 29e3b1d8 SystemTools: Use .rfind('/') rather than .find_last_of("/") 5eb3a65c SystemTools: Don't construct a string just for its length b07b5fc1 SystemTools: Take a string in GetShortPath 153f6df7 SystemTools: Use strings in ComparePath 2c2f6604 SystemTools: Accept strings in IsSubDirectory 84db9ee5 SystemTools: Take strings in AddTranslationPath 4b409aa4 SystemTools: Take strings in SplitPath d2dbff07 SystemTools: Take strings in CollapseFullPath e9204f8f SystemTools: Take strings in AddKeepPath 3254681a SystemTools: Reserve memory in JoinPath 6074f33f SystemTools: Use static strings in SystemToolsAppendComponents Change-Id: I53c7a1005206dba43ee785bf807c478bf146ca0e
2014-05-08 00:31:11 +04:00
this->Internals->UnusedArguments.push_back(arg);
}
else
{
std::cerr << "Got unknown argument: \"" << arg << "\"" << std::endl;
this->Internals->LastArgument --;
return 0;
}
}
}
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;
// Copy Argv0 as the first argument
char** args = new char*[ size ];
args[0] = new char[ this->Internals->Argv0.size() + 1 ];
strcpy(args[0], this->Internals->Argv0.c_str());
int cnt = 1;
// Copy everything after the LastArgument, since that was not parsed.
for ( cc = this->Internals->LastArgument+1;
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::GetUnusedArguments(int* argc, char*** argv)
{
CommandLineArguments::Internal::VectorOfStrings::size_type size
= this->Internals->UnusedArguments.size() + 1;
CommandLineArguments::Internal::VectorOfStrings::size_type cc;
// Copy Argv0 as the first argument
char** args = new char*[ size ];
args[0] = new char[ this->Internals->Argv0.size() + 1 ];
strcpy(args[0], this->Internals->Argv0.c_str());
int cnt = 1;
// Copy everything after the LastArgument, since that was not parsed.
for ( cc = 0;
cc < this->Internals->UnusedArguments.size(); cc ++ )
{
kwsys::String &str = this->Internals->UnusedArguments[cc];
args[cnt] = new char[ str.size() + 1];
strcpy(args[cnt], str.c_str());
cnt ++;
}
*argc = cnt;
*argv = args;
}
//----------------------------------------------------------------------------
void CommandLineArguments::DeleteRemainingArguments(int argc, char*** argv)
{
int cc;
for ( cc = 0; cc < argc; ++ cc )
{
delete [] (*argv)[cc];
}
delete [] *argv;
}
//----------------------------------------------------------------------------
void CommandLineArguments::AddCallback(const char* argument, ArgumentTypeEnum type,
CallbackType callback, void* call_data, const char* help)
{
CommandLineArgumentsCallbackStructure 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)
{
CommandLineArgumentsCallbackStructure 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();
}
//----------------------------------------------------------------------------
#define CommandLineArgumentsAddArgumentMacro(type, ctype) \
void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type, \
ctype* variable, const char* help) \
{ \
this->AddArgument(argument, type, CommandLineArguments::type##_TYPE, variable, help); \
}
CommandLineArgumentsAddArgumentMacro(BOOL, bool)
CommandLineArgumentsAddArgumentMacro(INT, int)
CommandLineArgumentsAddArgumentMacro(DOUBLE, double)
CommandLineArgumentsAddArgumentMacro(STRING, char*)
CommandLineArgumentsAddArgumentMacro(STL_STRING, std::string)
CommandLineArgumentsAddArgumentMacro(VECTOR_BOOL, std::vector<bool>)
CommandLineArgumentsAddArgumentMacro(VECTOR_INT, std::vector<int>)
CommandLineArgumentsAddArgumentMacro(VECTOR_DOUBLE, std::vector<double>)
CommandLineArgumentsAddArgumentMacro(VECTOR_STRING, std::vector<char*>)
CommandLineArgumentsAddArgumentMacro(VECTOR_STL_STRING, std::vector<std::string>)
//----------------------------------------------------------------------------
#define CommandLineArgumentsAddBooleanArgumentMacro(type, ctype) \
void CommandLineArguments::AddBooleanArgument(const char* argument, \
ctype* variable, const char* help) \
{ \
this->AddArgument(argument, CommandLineArguments::NO_ARGUMENT, \
CommandLineArguments::type##_TYPE, variable, help); \
}
CommandLineArgumentsAddBooleanArgumentMacro(BOOL, bool)
CommandLineArgumentsAddBooleanArgumentMacro(INT, int)
CommandLineArgumentsAddBooleanArgumentMacro(DOUBLE, double)
CommandLineArgumentsAddBooleanArgumentMacro(STRING, char*)
CommandLineArgumentsAddBooleanArgumentMacro(STL_STRING, std::string)
//----------------------------------------------------------------------------
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.
CommandLineArgumentsCallbackStructure *cs = &(it->second);
for(;;)
{
CommandLineArguments::Internal::CallbacksMap::iterator hit
= this->Internals->Callbacks.find(cs->Help);
if ( hit == this->Internals->Callbacks.end() )
{
break;
}
cs = &(hit->second);
}
return cs->Help;
}
//----------------------------------------------------------------------------
void CommandLineArguments::SetLineLength(unsigned int ll)
{
if ( ll < 9 || ll > 1000 )
{
return;
}
this->LineLength = ll;
this->GenerateHelp();
}
//----------------------------------------------------------------------------
const char* CommandLineArguments::GetArgv0()
{
return this->Internals->Argv0.c_str();
}
//----------------------------------------------------------------------------
unsigned int CommandLineArguments::GetLastArgument()
{
return static_cast<unsigned int>(this->Internals->LastArgument + 1);
}
//----------------------------------------------------------------------------
void CommandLineArguments::GenerateHelp()
{
std::ostringstream str;
// Collapse all arguments into the map of vectors of all arguments that do
// the same thing.
CommandLineArguments::Internal::CallbacksMap::iterator it;
typedef std::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 ++ )
{
CommandLineArgumentsCallbackStructure *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 ++ )
{
CommandLineArgumentsCallbackStructure *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 += 3; break;
case CommandLineArguments::SPACE_ARGUMENT: clen += 4; break;
case CommandLineArguments::EQUAL_ARGUMENT: clen += 4; break;
}
if ( clen > maxlen )
{
maxlen = clen;
}
}
}
// Create format for that string
char format[80];
sprintf(format, " %%-%us ", static_cast<unsigned int>(maxlen));
maxlen += 4; // For the space before and after the option
// 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 << std::endl;
char argument[100];
sprintf(argument, "%s", sit->c_str());
switch ( this->Internals->Callbacks[*sit].ArgumentType )
{
case CommandLineArguments::NO_ARGUMENT: break;
case CommandLineArguments::CONCAT_ARGUMENT: strcat(argument, "opt"); break;
case CommandLineArguments::SPACE_ARGUMENT: strcat(argument, " opt"); break;
case CommandLineArguments::EQUAL_ARGUMENT: strcat(argument, "=opt"); break;
case CommandLineArguments::MULTI_ARGUMENT: strcat(argument, " opt opt ..."); break;
}
char buffer[80];
sprintf(buffer, format, argument);
str << buffer;
}
const char* ptr = this->Internals->Callbacks[mpit->first].Help;
size_t 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 << " ";
}
}
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, static_cast<std::streamsize>(skip));
str << std::endl;
ptr += skip;
len -= skip;
cnt ++;
}
}
/*
// This can help debugging help string
str << endl;
unsigned int cc;
for ( cc = 0; cc < this->LineLength; cc ++ )
{
str << cc % 10;
}
str << endl;
*/
this->Help = str.str();
}
//----------------------------------------------------------------------------
void CommandLineArguments::PopulateVariable(
bool* variable, const std::string& value)
{
if ( value == "1" || value == "ON" || value == "on" || value == "On" ||
value == "TRUE" || value == "true" || value == "True" ||
value == "yes" || value == "Yes" || value == "YES" )
{
*variable = true;
}
else
{
*variable = false;
}
}
//----------------------------------------------------------------------------
void CommandLineArguments::PopulateVariable(
int* variable, const std::string& value)
{
char* res = 0;
*variable = static_cast<int>(strtol(value.c_str(), &res, 10));
//if ( res && *res )
// {
// Can handle non-int
// }
}
//----------------------------------------------------------------------------
void CommandLineArguments::PopulateVariable(
double* variable, const std::string& value)
{
char* res = 0;
*variable = strtod(value.c_str(), &res);
//if ( res && *res )
// {
// Can handle non-double
// }
}
//----------------------------------------------------------------------------
void CommandLineArguments::PopulateVariable(
char** variable, const std::string& value)
{
if ( *variable )
{
delete [] *variable;
*variable = 0;
}
*variable = new char[ value.size() + 1 ];
strcpy(*variable, value.c_str());
}
//----------------------------------------------------------------------------
void CommandLineArguments::PopulateVariable(
std::string* variable, const std::string& value)
{
*variable = value;
}
//----------------------------------------------------------------------------
void CommandLineArguments::PopulateVariable(
std::vector<bool>* variable, const std::string& value)
{
bool val = false;
if ( value == "1" || value == "ON" || value == "on" || value == "On" ||
value == "TRUE" || value == "true" || value == "True" ||
value == "yes" || value == "Yes" || value == "YES" )
{
val = true;
}
variable->push_back(val);
}
//----------------------------------------------------------------------------
void CommandLineArguments::PopulateVariable(
std::vector<int>* variable, const std::string& value)
{
char* res = 0;
variable->push_back(static_cast<int>(strtol(value.c_str(), &res, 10)));
//if ( res && *res )
// {
// Can handle non-int
// }
}
//----------------------------------------------------------------------------
void CommandLineArguments::PopulateVariable(
std::vector<double>* variable, const std::string& value)
{
char* res = 0;
variable->push_back(strtod(value.c_str(), &res));
//if ( res && *res )
// {
// Can handle non-int
// }
}
//----------------------------------------------------------------------------
void CommandLineArguments::PopulateVariable(
std::vector<char*>* variable, const std::string& value)
{
char* var = new char[ value.size() + 1 ];
strcpy(var, value.c_str());
variable->push_back(var);
}
//----------------------------------------------------------------------------
void CommandLineArguments::PopulateVariable(
std::vector<std::string>* variable,
const std::string& value)
{
variable->push_back(value);
}
//----------------------------------------------------------------------------
bool CommandLineArguments::PopulateVariable(CommandLineArgumentsCallbackStructure* cs,
const char* value)
{
// Call the callback
if ( cs->Callback )
{
if ( !cs->Callback(cs->Argument, value, cs->CallData) )
{
this->Internals->LastArgument --;
return 0;
}
}
CommandLineArguments_DEBUG("Set argument: " << cs->Argument << " to " << value);
if ( cs->Variable )
{
std::string var = "1";
if ( value )
{
var = value;
}
switch ( cs->VariableType )
{
case CommandLineArguments::INT_TYPE:
this->PopulateVariable(static_cast<int*>(cs->Variable), var);
break;
case CommandLineArguments::DOUBLE_TYPE:
this->PopulateVariable(static_cast<double*>(cs->Variable), var);
break;
case CommandLineArguments::STRING_TYPE:
this->PopulateVariable(static_cast<char**>(cs->Variable), var);
break;
case CommandLineArguments::STL_STRING_TYPE:
this->PopulateVariable(static_cast<std::string*>(cs->Variable), var);
break;
case CommandLineArguments::BOOL_TYPE:
this->PopulateVariable(static_cast<bool*>(cs->Variable), var);
break;
case CommandLineArguments::VECTOR_BOOL_TYPE:
this->PopulateVariable(static_cast<std::vector<bool>*>(cs->Variable), var);
break;
case CommandLineArguments::VECTOR_INT_TYPE:
this->PopulateVariable(static_cast<std::vector<int>*>(cs->Variable), var);
break;
case CommandLineArguments::VECTOR_DOUBLE_TYPE:
this->PopulateVariable(static_cast<std::vector<double>*>(cs->Variable), var);
break;
case CommandLineArguments::VECTOR_STRING_TYPE:
this->PopulateVariable(static_cast<std::vector<char*>*>(cs->Variable), var);
break;
case CommandLineArguments::VECTOR_STL_STRING_TYPE:
this->PopulateVariable(static_cast<std::vector<std::string>*>(cs->Variable), var);
break;
default:
std::cerr << "Got unknown variable type: \"" << cs->VariableType << "\"" << std::endl;
this->Internals->LastArgument --;
return 0;
}
}
return 1;
}
} // namespace KWSYS_NAMESPACE