| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605 |
- /*=========================================================================
- 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 KWSYS_HEADER(ios/iostream)
- #include <stdio.h>
- #include <stdlib.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, const char* const argv[])
- {
- int cc;
- this->Initialize();
- for ( cc = 1; cc < argc; cc ++ )
- {
- this->ProcessArgument(argv[cc]);
- }
- }
- //----------------------------------------------------------------------------
- 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
- {
- kwsys_ios::cerr << "Got unknown argument type: \"" << cs->VariableType << "\"" << kwsys_ios::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
- {
- kwsys_ios::cerr << "Got unknown argument: \"" << arg.c_str() << "\"" << kwsys_ios::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 << kwsys_ios::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 << kwsys_ios::endl;
- ptr += skip;
- len -= skip;
- cnt ++;
- }
- }
- this->Help = str.str();
- }
- } // namespace KWSYS_NAMESPACE
|