44 class CommandLineParserArgumentDescription
47 CommandLineParserArgumentDescription(
const string &longArg,
48 const string &longArgPrefix,
49 const string &shortArg,
50 const string &shortArgPrefix,
52 const string &argHelp,
53 const string &argLabel,
60 string &groupDescription)
62 LongArgPrefix(longArgPrefix),
64 ShortArgPrefix(shortArgPrefix),
68 ArgGroupDescription(groupDescription),
69 IgnoreRest(ignoreRest),
70 NumberOfParametersToProcess(0),
71 Deprecated(deprecated),
74 DefaultValue(defaultValue),
84 NumberOfParametersToProcess = 1;
89 NumberOfParametersToProcess = 0;
94 NumberOfParametersToProcess = -1;
99 NumberOfParametersToProcess = 1;
104 NumberOfParametersToProcess = 1;
110 NumberOfParametersToProcess = 1;
116 NumberOfParametersToProcess = 1;
121 NumberOfParametersToProcess = 1;
126 std::cout <<
"Type not supported: " <<
static_cast<int>(type);
130 ~CommandLineParserArgumentDescription() {}
131 bool addParameter(
const string &value);
136 string LongArgPrefix;
138 string ShortArgPrefix;
142 string ArgGroupDescription;
144 int NumberOfParametersToProcess;
155 bool CommandLineParserArgumentDescription::addParameter(
const string &value)
166 if (value.compare(
"true") == 0)
178 list.push_back(value);
184 list.push_back(value);
191 stringstream ss(value);
199 stringstream ss(value);
222 string CommandLineParserArgumentDescription::helpText()
226 string shortAndLongArg;
227 if (!this->ShortArg.empty())
229 shortAndLongArg =
" ";
230 shortAndLongArg += this->ShortArgPrefix;
231 shortAndLongArg += this->ShortArg;
234 if (!this->LongArg.empty())
236 if (this->ShortArg.empty())
237 shortAndLongArg.append(
" ");
239 shortAndLongArg.append(
", ");
241 shortAndLongArg += this->LongArgPrefix;
242 shortAndLongArg += this->LongArg;
245 text = text + shortAndLongArg +
", " + this->ArgHelp;
248 text +=
" (optional)";
250 if (!this->DefaultValue.Empty())
254 if (this->DefaultValue.ToString() ==
"0")
255 text = text +
", (default: false)";
257 text = text +
", (default: true)";
260 text = text +
", (default: " + this->DefaultValue.ToString() +
")";
262 string value_type =
"Unknown";
267 value_type =
"String";
277 value_type =
"StringList";
287 value_type =
"Float";
292 value_type =
"Directory";
302 value_type =
"Image";
305 text = text +
", Type: " + value_type;
307 text = text +
", Channel: input";
309 text = text +
", Channel: output";
319 class mitkCommandLineParser::ctkInternal
322 ctkInternal() :
Debug(false), FieldWidth(0), StrictMode(false) {}
324 CommandLineParserArgumentDescription *argumentDescription(
const string &argument);
326 vector<CommandLineParserArgumentDescription *> ArgumentDescriptionList;
327 map<string, CommandLineParserArgumentDescription *> ArgNameToArgumentDescriptionMap;
328 map<string, vector<CommandLineParserArgumentDescription *>> GroupToArgumentDescriptionListMap;
330 StringContainerType UnparsedArguments;
331 StringContainerType ProcessedArguments;
334 string::size_type FieldWidth;
338 string DisableQSettingsLongArg;
339 string DisableQSettingsShortArg;
347 CommandLineParserArgumentDescription *mitkCommandLineParser::ctkInternal::argumentDescription(
const string &argument)
349 string unprefixedArg = argument;
351 if (!LongPrefix.empty() && argument.compare(0, LongPrefix.size(), LongPrefix) == 0)
354 if (argument == LongPrefix && !ShortPrefix.empty() && argument.compare(0, ShortPrefix.size(), ShortPrefix) == 0)
356 unprefixedArg = argument.substr(ShortPrefix.size(), argument.size());
360 unprefixedArg = argument.substr(LongPrefix.size(), argument.size());
363 else if (!ShortPrefix.empty() && argument.compare(0, ShortPrefix.size(), ShortPrefix) == 0)
365 unprefixedArg = argument.substr(ShortPrefix.size(), argument.size());
367 else if (!LongPrefix.empty() && !ShortPrefix.empty())
372 if (ArgNameToArgumentDescriptionMap.count(unprefixedArg))
374 return this->ArgNameToArgumentDescriptionMap[unprefixedArg];
385 this->Internal =
new ctkInternal();
386 this->Category = string();
387 this->Title = string();
388 this->Contributor = string();
389 this->Description = string();
390 this->ParameterGroupName =
"Parameters";
391 this->ParameterGroupDescription =
"Parameters";
397 delete this->Internal;
404 this->Internal->UnparsedArguments.clear();
405 this->Internal->ProcessedArguments.clear();
406 this->Internal->ErrorString.clear();
408 for (
unsigned int i = 0; i < Internal->ArgumentDescriptionList.size(); i++)
410 CommandLineParserArgumentDescription *desc = Internal->ArgumentDescriptionList.at(i);
411 desc->Value =
us::Any(desc->ValueType);
412 if (!desc->DefaultValue.Empty())
414 desc->Value = desc->DefaultValue;
418 bool ignoreRest =
false;
419 CommandLineParserArgumentDescription *currentArgDesc =
nullptr;
420 vector<CommandLineParserArgumentDescription *> parsedArgDescriptions;
421 for (
unsigned int i = 1; i < arguments.size(); ++i)
423 string argument = arguments.at(i);
425 if (this->Internal->Debug)
427 std::cout <<
"Processing" << argument;
429 if (!argument.compare(
"--version"))
431 std::cout <<
"Git commit hash: " <<
MITK_REVISION << std::endl;
435 if (!argument.compare(
"--xml") || !argument.compare(
"-xml") || !argument.compare(
"--XML") ||
436 !argument.compare(
"-XML"))
438 this->generateXmlOutput();
439 return map<string, us::Any>();
445 if (this->Internal->Debug)
447 std::cout <<
" Skipping: IgnoreRest flag was been set";
449 this->Internal->UnparsedArguments.push_back(argument);
454 if (!(argument.compare(0, Internal->LongPrefix.size(), Internal->LongPrefix) == 0 ||
455 argument.compare(0, Internal->ShortPrefix.size(), Internal->ShortPrefix) == 0))
457 if (this->Internal->StrictMode)
459 this->Internal->ErrorString =
"Unknown argument ";
460 this->Internal->ErrorString += argument;
464 if (this->Internal->Debug)
466 std::cout <<
" Skipping: It does not start with the defined prefix";
468 this->Internal->UnparsedArguments.push_back(argument);
473 bool alreadyProcessed =
false;
474 for (
auto alreadyHandledArgument : Internal->ProcessedArguments)
475 if (argument.compare(alreadyHandledArgument) == 0)
477 alreadyProcessed =
true;
481 if (alreadyProcessed)
483 if (this->Internal->StrictMode)
485 this->Internal->ErrorString =
"Argument ";
486 this->Internal->ErrorString += argument;
487 this->Internal->ErrorString +=
" already processed !";
491 if (this->Internal->Debug)
493 std::cout <<
" Skipping: Already processed !";
499 currentArgDesc = this->Internal->argumentDescription(argument);
505 if (currentArgDesc->Deprecated)
507 std::cout <<
"Deprecated argument " << argument <<
": " << currentArgDesc->ArgHelp;
511 parsedArgDescriptions.push_back(currentArgDesc);
514 this->Internal->ProcessedArguments.push_back(currentArgDesc->ShortArg);
515 this->Internal->ProcessedArguments.push_back(currentArgDesc->LongArg);
516 int numberOfParametersToProcess = currentArgDesc->NumberOfParametersToProcess;
517 ignoreRest = currentArgDesc->IgnoreRest;
518 if (this->Internal->Debug && ignoreRest)
520 std::cout <<
" IgnoreRest flag is True";
524 if (numberOfParametersToProcess == 0)
526 currentArgDesc->addParameter(
"true");
528 else if (numberOfParametersToProcess > 0)
530 string missingParameterError =
"Argument %1 has %2 value(s) associated whereas exacly %3 are expected.";
531 for (
int j = 1; j <= numberOfParametersToProcess; ++j)
533 if (i + j >= arguments.size())
542 return map<string, us::Any>();
544 string parameter = arguments.at(i + j);
545 if (this->Internal->Debug)
547 std::cout <<
" Processing parameter" << j <<
", value:" << parameter;
549 if (this->argumentAdded(parameter))
558 return map<string, us::Any>();
560 if (!currentArgDesc->addParameter(parameter))
570 return map<string, us::Any>();
574 i = i + numberOfParametersToProcess;
576 else if (numberOfParametersToProcess == -1)
578 if (this->Internal->Debug)
580 std::cout <<
" Proccessing StringList ...";
583 while (j + i < arguments.size())
585 if (this->argumentAdded(arguments.at(j + i)))
587 if (this->Internal->Debug)
589 std::cout <<
" No more parameter for" << argument;
593 string parameter = arguments.at(j + i);
595 if (parameter.compare(0, Internal->LongPrefix.size(), Internal->LongPrefix) == 0 ||
596 parameter.compare(0, Internal->ShortPrefix.size(), Internal->ShortPrefix) == 0)
602 if (this->Internal->Debug)
604 std::cout <<
" Processing parameter" << j <<
", value:" << parameter;
606 if (!currentArgDesc->addParameter(parameter))
616 return map<string, us::Any>();
626 if (this->Internal->StrictMode)
628 this->Internal->ErrorString =
"Unknown argument ";
629 this->Internal->ErrorString += argument;
633 if (this->Internal->Debug)
635 std::cout <<
" Skipping: Unknown argument";
637 this->Internal->UnparsedArguments.push_back(argument);
646 map<string, us::Any> parsedArguments;
648 int obligatoryArgs = 0;
649 vector<CommandLineParserArgumentDescription *>::iterator it;
650 for (it = Internal->ArgumentDescriptionList.begin(); it != Internal->ArgumentDescriptionList.end(); ++it)
652 CommandLineParserArgumentDescription *desc = *it;
658 int parsedObligatoryArgs = 0;
659 for (it = parsedArgDescriptions.begin(); it != parsedArgDescriptions.end(); ++it)
661 CommandLineParserArgumentDescription *desc = *it;
664 if (!desc->LongArg.empty())
670 key = desc->ShortArg;
674 parsedObligatoryArgs++;
676 std::pair<string, us::Any> elem;
678 elem.second = desc->Value;
679 parsedArguments.insert(elem);
682 if (obligatoryArgs > parsedObligatoryArgs)
684 parsedArguments.clear();
688 return parsedArguments;
694 std::cout <<
"Running Command Line Utility *" << Title <<
"*" << std::endl;
698 for (
int i = 0; i < argc; ++i)
699 arguments.push_back(argv[i]);
701 return this->parseArguments(arguments, ok);
707 return this->Internal->ErrorString;
713 return this->Internal->UnparsedArguments;
718 const string &shortarg,
720 const string &argLabel,
721 const string &argHelp,
728 if (longarg.empty() && shortarg.empty())
734 bool added = (this->Internal->ArgNameToArgumentDescriptionMap.count(longarg) != 0);
740 added = (this->Internal->ArgNameToArgumentDescriptionMap.count(shortarg) != 0);
746 auto argDesc =
new CommandLineParserArgumentDescription(longarg,
747 this->Internal->LongPrefix,
749 this->Internal->ShortPrefix,
759 ParameterGroupDescription);
761 std::string::size_type argWidth = 0;
762 if (!longarg.empty())
764 this->Internal->ArgNameToArgumentDescriptionMap[longarg] = argDesc;
765 argWidth += longarg.size() + this->Internal->LongPrefix.size();
767 if (!shortarg.empty())
769 this->Internal->ArgNameToArgumentDescriptionMap[shortarg] = argDesc;
770 argWidth += shortarg.size() + this->Internal->ShortPrefix.size() + 2;
775 if (argWidth > this->Internal->FieldWidth)
777 this->Internal->FieldWidth = argWidth;
780 this->Internal->ArgumentDescriptionList.push_back(argDesc);
781 this->Internal->GroupToArgumentDescriptionListMap[this->Internal->CurrentGroup].push_back(argDesc);
786 const string &shortarg,
787 const string &argLabel,
788 const string &argHelp)
790 addArgument(longarg, shortarg,
StringList, argLabel, argHelp,
us::Any(),
false,
true,
false);
796 std::vector < std::map<std::string, us::Any> > parameterList;
798 for (std::size_t i = 0; i< this->Internal->ArgumentDescriptionList.size(); ++i)
800 CommandLineParserArgumentDescription* argument = this->Internal->ArgumentDescriptionList[i];
801 std::map<std::string, us::Any> tmpMap;
803 tmpMap[
"longarg"] =
us::Any(argument->LongArg);
804 tmpMap[
"longargprefix"] =
us::Any(argument->LongArgPrefix);
805 tmpMap[
"shortarg"] =
us::Any(argument->ShortArg);
806 tmpMap[
"shortargprefix"] =
us::Any(argument->ShortArgPrefix);
807 tmpMap[
"arghelp"] =
us::Any(argument->ArgHelp);
808 tmpMap[
"arglabel"] =
us::Any(argument->ArgLabel);
809 tmpMap[
"arggroup"] =
us::Any(argument->ArgGroup);
810 tmpMap[
"arggroupdescription"] =
us::Any(argument->ArgGroupDescription);
811 tmpMap[
"ignorerest"] =
us::Any(argument->IgnoreRest);
812 tmpMap[
"numberofparameterstoprocess"] =
us::Any(argument->NumberOfParametersToProcess);
813 tmpMap[
"deprecated"] =
us::Any(argument->Deprecated);
814 tmpMap[
"optional"] =
us::Any(argument->Optional);
815 tmpMap[
"defaultvalue"] = argument->DefaultValue;
816 tmpMap[
"value"] = argument->Value;
817 tmpMap[
"valuetype"] =
us::Any(argument->ValueType);
818 tmpMap[
"channel"] =
us::Any(argument->Channel);
819 parameterList.push_back(tmpMap);
821 return parameterList;
827 return this->Internal->FieldWidth;
833 this->Internal->CurrentGroup = description;
839 this->Internal->CurrentGroup.clear();
846 vector<CommandLineParserArgumentDescription *> deprecatedArgs;
848 text =
"Command Line Utility *" + Title +
"* in Category *" + Category +
"*\n";
849 text += Description +
"\n";
850 text += Contributor +
"\n\n";
851 text +=
"Use --xml to generate an XML description parsable as a CTK Command Line Module Plugin.\n";
852 text +=
"Use --version to print MITK revision information.\n";
855 map<string, vector<CommandLineParserArgumentDescription *>>::iterator it;
856 for (it = Internal->GroupToArgumentDescriptionListMap.begin();
857 it != Internal->GroupToArgumentDescriptionListMap.end();
860 if (!(*it).first.empty())
862 text = text +
"\n" + (*it).first +
"\n";
865 vector<CommandLineParserArgumentDescription *>::iterator it2;
866 for (it2 = (*it).second.begin(); it2 != (*it).second.end(); ++it2)
868 CommandLineParserArgumentDescription *argDesc = *it2;
869 if (argDesc->Deprecated)
871 deprecatedArgs.push_back(argDesc);
875 text += argDesc->helpText();
880 if (!deprecatedArgs.empty())
882 text +=
"\nDeprecated arguments:\n";
883 vector<CommandLineParserArgumentDescription *>::iterator it2;
884 for (it2 = deprecatedArgs.begin(); it2 != deprecatedArgs.end(); ++it2)
886 CommandLineParserArgumentDescription *argDesc = *it2;
887 text += argDesc->helpText();
897 return (this->Internal->ArgNameToArgumentDescriptionMap.count(argument) != 0);
903 for (
unsigned int i = 0; i < Internal->ProcessedArguments.size(); i++)
904 if (argument.compare(Internal->ProcessedArguments.at(i)) == 0)
912 this->Internal->LongPrefix = longPrefix;
913 this->Internal->ShortPrefix = shortPrefix;
919 this->Internal->StrictMode = strictMode;
925 std::stringstream xml;
927 xml <<
"<executable>" << endl;
928 xml <<
"<category>" << Category <<
"</category>" << endl;
929 xml <<
"<title>" << Title <<
"</title>" << endl;
930 xml <<
"<description>" << Description <<
"</description>" << endl;
931 xml <<
"<contributor>" << Contributor <<
"</contributor>" << endl;
932 xml <<
"<parameters>" << endl;
934 std::vector<CommandLineParserArgumentDescription *>::iterator it;
936 std::string lastParameterGroup =
"";
937 for (it = this->Internal->ArgumentDescriptionList.begin(); it != this->Internal->ArgumentDescriptionList.end(); it++)
940 switch ((*it)->ValueType)
951 type =
"string-vector";
975 if (lastParameterGroup.compare((*it)->ArgGroup))
977 if (it != this->Internal->ArgumentDescriptionList.begin())
979 xml <<
"</parameters>" << endl;
980 xml <<
"<parameters>" << endl;
982 xml <<
"<label>" << (*it)->ArgGroup <<
"</label>" << endl;
983 xml <<
"<description>" << (*it)->ArgGroupDescription <<
"</description>" << endl;
984 lastParameterGroup = (*it)->ArgGroup;
988 if ((*it)->ShortArg ==
"h")
991 auto name = (*it)->LongArg;
993 name = (*it)->ShortArg;
995 xml <<
"<" << type <<
">" << endl;
996 xml <<
"<name>" << name <<
"</name>" << endl;
997 xml <<
"<description>" << (*it)->ArgHelp <<
"</description>" << endl;
998 xml <<
"<label>" << (*it)->ArgLabel <<
"</label>" << endl;
999 if (!(*it)->DefaultValue.Empty())
1000 xml <<
"<default>" << (*it)->DefaultValue.ToString() <<
"</default>" << endl;
1002 xml <<
"<longflag>" << (*it)->LongArg <<
"</longflag>" << endl;
1003 xml <<
"<flag>" << (*it)->ShortArg <<
"</flag>" << endl;
1008 (*it)->Channel == mitkCommandLineParser::Channel::Input)
1010 xml <<
"<channel>input</channel>" << endl;
1015 (*it)->Channel == mitkCommandLineParser::Channel::Output)
1017 xml <<
"<channel>output</channel>" << endl;
1019 else if ((*it)->Channel == mitkCommandLineParser::Channel::Output ||
1020 (*it)->Channel == mitkCommandLineParser::Channel::Input)
1022 std::cout <<
"Only the types Directory, File or Image may be flagged as Input or Output! Ignoring flag for parameter " + name << std::endl;
1024 xml <<
"</" << type <<
">" << endl;
1027 xml <<
"</parameters>" << endl;
1028 xml <<
"</executable>" << endl;
1039 Contributor = contributor;
1044 Category = category;
1049 Description = description;
1054 ParameterGroupName = name;
1055 ParameterGroupDescription = tooltip;
void changeParameterGroup(std::string name, std::string tooltip)
#define MITK_REVISION_NAME
void setStrictModeEnabled(bool strictMode)
void setContributor(std::string contributor)
bool argumentAdded(const std::string &argument) const
std::vector< std::map< std::string, us::Any > > getArgumentList()
ValueType * any_cast(Any *operand)
std::string errorString() const
void addArgument(const std::string &longarg, const std::string &shortarg, Type type, const std::string &argLabel, const std::string &argHelp=std::string(), const us::Any &defaultValue=us::Any(), bool optional=true, bool ignoreRest=false, bool deprecated=false, mitkCommandLineParser::Channel channel=mitkCommandLineParser::Channel::None)
std::map< std::string, us::Any > parseArguments(const StringContainerType &arguments, bool *ok=nullptr)
ValueType
Type of the value held by a Value object.
std::string helpText() const
void setCategory(std::string category)
std::vector< std::string > StringList
const StringContainerType & unparsedArguments() const
void setArgumentPrefix(const std::string &longPrefix, const std::string &shortPrefix)
void addDeprecatedArgument(const std::string &longarg, const std::string &shortarg, const std::string &argLabel, const std::string &argHelp)
bool argumentParsed(const std::string &argument) const
std::vector< std::string > StringContainerType
std::string::size_type fieldWidth() const
void setTitle(std::string title)
void setDescription(std::string description)
void beginGroup(const std::string &description)