source: src/UIElements/CommandLineUI/CommandLineParser.cpp@ f63e41

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since f63e41 was f63e41, checked in by Frederik Heber <heber@…>, 12 years ago

Added Actions to add and remove a bond in between two atoms.

  • added new menu "bond".
  • added new CommandLineParser options "bond".
  • added new regression test folder "bond".
  • also added regression tests with undo/redo for the new actions.
  • Property mode set to 100644
File size: 20.9 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010-2012 University of Bonn. All rights reserved.
5 *
6 *
7 * This file is part of MoleCuilder.
8 *
9 * MoleCuilder is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * MoleCuilder is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with MoleCuilder. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23/*
24 * CommandLineParser.cpp
25 *
26 * Created on: May 8, 2010
27 * Author: heber
28 */
29
30// include config.h
31#ifdef HAVE_CONFIG_H
32#include <config.h>
33#endif
34
35#include "CodePatterns/MemDebug.hpp"
36
37#include <boost/filesystem.hpp>
38#include <boost/program_options.hpp>
39#include <fstream>
40#include <iostream>
41#include <set>
42#include <map>
43
44#include "Actions/Action.hpp"
45#include "Actions/ActionRegistry.hpp"
46#include "Actions/ActionTrait.hpp"
47#include "Actions/OptionRegistry.hpp"
48#include "Actions/OptionTrait.hpp"
49#include "Actions/Values.hpp"
50#include "CodePatterns/Log.hpp"
51#include "CodePatterns/Verbose.hpp"
52#include "CommandLineParser.hpp"
53#include "CommandLineParser_validate.hpp"
54
55#include "CodePatterns/Singleton_impl.hpp"
56
57using namespace MoleCuilder;
58
59class element;
60
61/** Constructor of class CommandLineParser.
62 *
63 */
64CommandLineParser::CommandLineParser() :
65 analysis("Analysis options"),
66 atom("Atom options"),
67 bond("Bond options"),
68 command("Command options"),
69 fill("fill options"),
70 shape("shape options"),
71 fragmentation("Fragmentation options"),
72 graph("Graph options"),
73 molecule("Molecule options"),
74 options("Secondary options"),
75 parser("Parser options"),
76 selection("Selection options"),
77 tesselation("Tesselation options"),
78 world("World options")
79{
80 // put all options lists into a lookup
81 CmdParserLookup["analysis"] = &analysis;
82 CmdParserLookup["atom"] = &atom;
83 CmdParserLookup["bond"] = &bond;
84 CmdParserLookup["command"] = &command;
85 CmdParserLookup["edit"] = &edit;
86 CmdParserLookup["fill"] = &fill;
87 CmdParserLookup["shape"] = &shape;
88 CmdParserLookup["fragmentation"] = &fragmentation;
89 CmdParserLookup["graph"] = &graph;
90 CmdParserLookup["options"] = &options;
91 CmdParserLookup["molecule"] = &molecule;
92 CmdParserLookup["parser"] = &parser;
93 CmdParserLookup["selection"] = &selection;
94 CmdParserLookup["tesselation"] = &tesselation;
95 CmdParserLookup["world"] = &world;
96}
97
98/** Destructor of class CommandLineParser.
99 *
100 */
101CommandLineParser::~CommandLineParser()
102{}
103
104/** Initializes command arguments to accept.
105 * Goes through ActionRegistry and puts all actions therein into the map.
106 */
107void CommandLineParser::InitializeCommandArguments()
108{
109 // we need a list of already added options, otherwise we get ambigious exceptions
110 std::set<std::string> AlreadyAddedOptionNames;
111
112 ActionRegistry &AR = ActionRegistry::getInstance();
113 bool ActionAlreadyAdded_flag = false;
114 for (ActionRegistry::const_iterator actioniter = AR.getBeginIter(); actioniter != AR.getEndIter(); ++actioniter) {
115 ActionAlreadyAdded_flag = false;
116 Action* const currentAction = actioniter->second;
117 //std::cout << "Current Action to initialize is: " << actioniter->first << std::endl;
118
119 for (ActionTrait::options_const_iterator optioniter = currentAction->Traits.getBeginIter();
120 optioniter != currentAction->Traits.getEndIter();
121 ++optioniter) {
122 if (optioniter->first == actioniter->first)
123 ActionAlreadyAdded_flag = true;
124 ASSERT( OptionRegistry::getInstance().isOptionPresentByName(optioniter->first),
125 "CommandLineParser::Init() - Option "+optioniter->first+" not present in OptionRegistry." );
126 const OptionTrait* const currentOption = OptionRegistry::getInstance().getOptionByName(optioniter->first);
127
128 if (AlreadyAddedOptionNames.find(optioniter->first) == AlreadyAddedOptionNames.end()) {
129 // add the option
130// std::cout << "Registering Option "
131// << currentOption->getName()
132// << " with type '" << currentOption->getTypeName() << "' "
133// << " with description '" << currentOption->getDescription() << "' ";
134// if (currentOption->hasShortForm())
135// std::cout << ", with short form " << currentOption->getShortForm();
136// else
137// std::cout << ", with no short form ";
138// if (currentOption->hasDefaultValue())
139// std::cout << ", with default value " << currentOption->getDefaultValue();
140// else
141// std::cout << ", with no default value ";
142// std::cout << std::endl;
143
144 AddOptionToParser(currentOption, (CmdParserLookup["options"]));
145
146 AlreadyAddedOptionNames.insert(optioniter->first);
147 } else {
148// std::cout << "Option " << currentOption->getName() << " already registered." << std::endl;
149 }
150 }
151
152 if (!ActionAlreadyAdded_flag) {
153 // add the action
154// std::cout << "Registering Action "
155// << currentAction->Traits.getName()
156// << " in menu " << currentAction->Traits.getMenuName()
157// << " with type '" << currentAction->Traits.getTypeName() << "' "
158// << " with description '" << currentAction->Traits.getDescription() << "' ";
159// if (currentAction->Traits.hasShortForm())
160// std::cout << ", with short form " << currentAction->Traits.getShortForm();
161// else
162// std::cout << ", with no short form ";
163// if (currentAction->Traits.hasDefaultValue())
164// std::cout << ", with default value " << currentAction->Traits.getDefaultValue();
165// else
166// std::cout << ", with no default value ";
167// std::cout << std::endl;
168
169 ASSERT(CmdParserLookup.find(currentAction->Traits.getMenuName()) != CmdParserLookup.end(),
170 "CommandLineParser: boost::program_options::options_description for this Action not present.");
171 AddOptionToParser(dynamic_cast<const OptionTrait * const>(&(currentAction->Traits)),(CmdParserLookup[currentAction->Traits.getMenuName()]));
172 }
173 }
174 // note: positioning is not important on the command line
175}
176
177/** Adds an Action or Option to the CommandLineParser.
178 * Note that Action is derived from Option(Trait)
179 *
180 * This ugly switch function is necessary because of the compile-time problem:
181 * po::value<T> has to be instantiated at compile-time however we do know the type not until run-time.
182 * Not even a templated function like po::value<T> getProgramOptionValuefromType() does help, specialized
183 * to each available type, as the signatures of all the functions differ. Hence, they cannot not put into
184 * one type_info -> po::value<T> map ...
185 *
186 * \param *currentOption pointer to Action/Option to add
187 * \param *OptionList program_options list to add to
188 */
189void CommandLineParser::AddOptionToParser(const OptionTrait * const currentOption, po::options_description* OptionList)
190{
191 // check whether dynamic_cast in Init() suceeded
192 ASSERT(currentOption != NULL, "CommandLineParser::AddOptionToParser() - currentOption is NULL!");
193 // add other options
194// std::cout << "Adding Action " << currentOption->getName() << " with type "
195// << currentOption->getType()->name() << ", " << (currentOption->hasDefaultValue() ? "with" : "without")
196// << " default value, and KeyandShortform " << currentOption->getKeyAndShortForm()
197// << " to CommandLineParser." << std::endl;
198 switch(TypeToEnums.getEnumforType(currentOption->getType())) {
199 default:
200 case TypeEnumContainer::NoneType:
201 OptionList->add_options()
202 (currentOption->getKeyAndShortForm().c_str(), currentOption->getDescription().c_str())
203 ;
204 break;
205 case TypeEnumContainer::BooleanType:
206 OptionList->add_options()
207 (currentOption->getKeyAndShortForm().c_str(),
208 currentOption->hasDefaultValue() ?
209 po::value < bool >()->default_value(boost::lexical_cast<int>(currentOption->getDefaultValue().c_str())) :
210 po::value < bool >(),
211 currentOption->getDescription().c_str())
212 ;
213 break;
214 case TypeEnumContainer::FileType:
215 OptionList->add_options()
216 (currentOption->getKeyAndShortForm().c_str(),
217// currentOption->hasDefaultValue() ?
218// po::value < boost::filesystem::path >()->default_value(boost::lexical_cast<boost::filesystem::path>(currentOption->getDefaultValue().c_str())) :
219 po::value < boost::filesystem::path >(),
220 currentOption->getDescription().c_str())
221 ;
222 break;
223 case TypeEnumContainer::ListOfFilesType:
224 OptionList->add_options()
225 (currentOption->getKeyAndShortForm().c_str(),
226// currentOption->hasDefaultValue() ?
227// po::value < std::vector<boost::filesystem::path> >()->default_value(boost::lexical_cast< std::vector<boost::filesystem::path> >(currentOption->getDefaultValue().c_str())) :
228 po::value < std::vector<boost::filesystem::path> >()->multitoken(),
229 currentOption->getDescription().c_str())
230 ;
231 break;
232 case TypeEnumContainer::IntegerType:
233 OptionList->add_options()
234 (currentOption->getKeyAndShortForm().c_str(),
235 currentOption->hasDefaultValue() ?
236 po::value < int >()->default_value(boost::lexical_cast<int>(currentOption->getDefaultValue().c_str())) :
237 po::value < int >(),
238 currentOption->getDescription().c_str())
239 ;
240 break;
241 case TypeEnumContainer::ListOfIntegersType:
242 OptionList->add_options()
243 (currentOption->getKeyAndShortForm().c_str(),
244// currentOption->hasDefaultValue() ?
245// po::value < std::vector<int> >()->default_value(boost::lexical_cast< std::vector<int> >(currentOption->getDefaultValue().c_str())) :
246 po::value < std::vector<int> >()->multitoken(),
247 currentOption->getDescription().c_str())
248 ;
249 break;
250 case TypeEnumContainer::UnsignedIntegerType:
251 OptionList->add_options()
252 (currentOption->getKeyAndShortForm().c_str(),
253 currentOption->hasDefaultValue() ?
254 po::value < unsigned int >()->default_value(boost::lexical_cast<unsigned int>(currentOption->getDefaultValue().c_str())) :
255 po::value < unsigned int >(),
256 currentOption->getDescription().c_str())
257 ;
258 break;
259 case TypeEnumContainer::ListOfUnsignedIntegersType:
260 OptionList->add_options()
261 (currentOption->getKeyAndShortForm().c_str(),
262// currentOption->hasDefaultValue() ?
263// po::value < std::vector<unsigned int> >()->default_value(boost::lexical_cast< std::vector<unsigned int> >(currentOption->getDefaultValue().c_str())) :
264 po::value < std::vector<unsigned int> >()->multitoken(),
265 currentOption->getDescription().c_str())
266 ;
267 break;
268 case TypeEnumContainer::DoubleType:
269 OptionList->add_options()
270 (currentOption->getKeyAndShortForm().c_str(),
271 currentOption->hasDefaultValue() ?
272 po::value < double >()->default_value(boost::lexical_cast<double>(currentOption->getDefaultValue().c_str())) :
273 po::value < double >(),
274 currentOption->getDescription().c_str())
275 ;
276 break;
277 case TypeEnumContainer::ListOfDoublesType:
278 OptionList->add_options()
279 (currentOption->getKeyAndShortForm().c_str(),
280// currentOption->hasDefaultValue() ?
281// po::value < std::vector<double> >()->default_value(boost::lexical_cast< std::vector<double> >(currentOption->getDefaultValue().c_str())) :
282 po::value < std::vector<double> >()->multitoken(),
283 currentOption->getDescription().c_str())
284 ;
285 break;
286 case TypeEnumContainer::StringType:
287 OptionList->add_options()
288 (currentOption->getKeyAndShortForm().c_str(),
289 currentOption->hasDefaultValue() ?
290 po::value < std::string >()->default_value(currentOption->getDefaultValue()) :
291 po::value < std::string >(),
292 currentOption->getDescription().c_str())
293 ;
294 break;
295 case TypeEnumContainer::ListOfStringsType:
296 OptionList->add_options()
297 (currentOption->getKeyAndShortForm().c_str(),
298// currentOption->hasDefaultValue() ?
299// po::value < std::vector<std::string> >()->default_value(boost::lexical_cast< std::vector<std::string> >(currentOption->getDefaultValue().c_str())) :
300 po::value < std::vector<std::string> >()->multitoken(),
301 currentOption->getDescription().c_str())
302 ;
303 break;
304 case TypeEnumContainer::VectorType:
305 OptionList->add_options()
306 (currentOption->getKeyAndShortForm().c_str(),
307// currentOption->hasDefaultValue() ?
308// po::value < VectorValue >()->default_value(boost::lexical_cast<VectorValue>(currentOption->getDefaultValue().c_str())) :
309 po::value < VectorValue >(),
310 currentOption->getDescription().c_str())
311 ;
312 break;
313 case TypeEnumContainer::ListOfVectorsType:
314 OptionList->add_options()
315 (currentOption->getKeyAndShortForm().c_str(),
316// currentOption->hasDefaultValue() ?
317// po::value < std::vector<VectorValue> >()->default_value(boost::lexical_cast< std::vector<VectorValue> >(currentOption->getDefaultValue().c_str())) :
318 po::value < std::vector<VectorValue> >()->multitoken(),
319 currentOption->getDescription().c_str())
320 ;
321 break;
322 case TypeEnumContainer::MoleculeType:
323 OptionList->add_options()
324 (currentOption->getKeyAndShortForm().c_str(),
325// currentOption->hasDefaultValue() ?
326// po::value < const molecule * >()->default_value(boost::lexical_cast<const molecule *>(currentOption->getDefaultValue().c_str())) :
327 po::value < int >(),
328 currentOption->getDescription().c_str())
329 ;
330 break;
331 case TypeEnumContainer::ListOfMoleculesType:
332 OptionList->add_options()
333 (currentOption->getKeyAndShortForm().c_str(),
334// currentOption->hasDefaultValue() ?
335// po::value < std::vector<const molecule *> >()->default_value(boost::lexical_cast< std::vector<const molecule *> >(currentOption->getDefaultValue().c_str())) :
336 po::value < std::vector<int> >()->multitoken(),
337 currentOption->getDescription().c_str())
338 ;
339 break;
340 case TypeEnumContainer::AtomType:
341 OptionList->add_options()
342 (currentOption->getKeyAndShortForm().c_str(),
343 currentOption->hasDefaultValue() ?
344 po::value < int >()->default_value(boost::lexical_cast<int>(currentOption->getDefaultValue().c_str())) :
345 po::value < int >(),
346 currentOption->getDescription().c_str())
347 ;
348 break;
349 case TypeEnumContainer::ListOfAtomsType:
350 OptionList->add_options()
351 (currentOption->getKeyAndShortForm().c_str(),
352// currentOption->hasDefaultValue() ?
353// po::value < std::vector<const atom *> >()->default_value(boost::lexical_cast< std::vector<const atom *> >(currentOption->getDefaultValue().c_str())) :
354 po::value < std::vector<int> >()->multitoken(),
355 currentOption->getDescription().c_str())
356 ;
357 break;
358 case TypeEnumContainer::ElementType:
359 OptionList->add_options()
360 (currentOption->getKeyAndShortForm().c_str(),
361// currentOption->hasDefaultValue() ?
362// po::value < const element * >()->default_value(boost::lexical_cast<const element *>(currentOption->getDefaultValue().c_str())) :
363 po::value < int >(),
364 currentOption->getDescription().c_str())
365 ;
366 break;
367 case TypeEnumContainer::ListOfElementsType:
368 OptionList->add_options()
369 (currentOption->getKeyAndShortForm().c_str(),
370// currentOption->hasDefaultValue() ?
371// po::value < std::vector<const element *> >()->default_value(boost::lexical_cast< std::vector<const element *> >(currentOption->getDefaultValue().c_str())) :
372 po::value < std::vector<int> >()->multitoken(),
373 currentOption->getDescription().c_str())
374 ;
375 break;
376 case TypeEnumContainer::RandomNumberDistribution_ParametersType:
377 OptionList->add_options()
378 (currentOption->getKeyAndShortForm().c_str(),
379 currentOption->hasDefaultValue() ?
380 po::value < std::string >()->default_value(boost::lexical_cast< std::string >(currentOption->getDefaultValue().c_str())) :
381 po::value < std::string >(),
382 currentOption->getDescription().c_str())
383 ;
384 break;
385 case TypeEnumContainer::RealSpaceMatrixType:
386 OptionList->add_options()
387 (currentOption->getKeyAndShortForm().c_str(),
388// currentOption->hasDefaultValue() ?
389// po::value < RealSpaceMatrixValue >()->default_value(boost::lexical_cast<BoxValue>(currentOption->getDefaultValue().c_str())) :
390 po::value < RealSpaceMatrixValue >(),
391 currentOption->getDescription().c_str())
392 ;
393 break;
394 }
395}
396
397/** States whether there are command line arguments.
398 * \return true - there are none, false - there is at least one command line argument
399 */
400bool CommandLineParser::isEmpty()
401{
402 return vm.empty();
403}
404
405/** Sets the options.
406 * \param _argc arg count from main()
407 * \param **_argv argument array from main()
408 */
409void CommandLineParser::setOptions(int _argc, char **_argv)
410{
411 argc = _argc;
412 argv = _argv;
413 config_file_options.add(options);
414 // append all option_descriptions to both cmdline_options and visible
415 for (CmdParserLookupMap::iterator iter = CmdParserLookup.begin();
416 iter != CmdParserLookup.end();
417 ++iter) {
418 cmdline_options.add(*(iter->second));
419 visible.add(*(iter->second));
420 }
421}
422
423/** Parses the command line arguments.
424 * Calls program_options::store() and program_options::notify()
425 */
426void CommandLineParser::Parse()
427{
428 po::store(po::command_line_parser(argc,argv).options(cmdline_options).run(), vm);
429 std::ifstream input;
430 input.open("example.cfg");
431 if (!input.fail())
432 po::store(po::parse_config_file(input, config_file_options), vm);
433 input.close();
434 po::notify(vm);
435}
436
437/** Scan the argument list for -a or --arguments and store their order for later use.
438 */
439void CommandLineParser::scanforSequenceOfArguments()
440{
441 std::map <std::string, std::string> ShortFormToActionMap = getShortFormToActionMap();
442 LOG(0, "Scanning command line arguments and recognizing Actions.");
443 // go through all arguments
444 for (int i=1;i<argc;i++) {
445 LOG(2, "Checking on " << argv[i]);
446 // check whether they
447 if (argv[i][0] == '-') { // .. begin with -
448 LOG(2, "Possible argument: " << argv[i]);
449 if (argv[i][1] == '-') { // .. or --
450 LOG(1, "Putting " << argv[i] << " into the sequence.");
451 SequenceOfActions.push_back(&(argv[i][2]));
452 // .. and check that next letter is not numeric, if so insert
453 } else if (((argv[i][1] < '0') || (argv[i][1] > '9')) && ((argv[i][1] != '.'))) {
454 std::map <std::string, std::string>::iterator iter = ShortFormToActionMap.find(&(argv[i][1]));
455 if (iter != ShortFormToActionMap.end()) {
456 LOG(1, "Putting " << iter->second << " for " << iter->first << " into the sequence.");
457 SequenceOfActions.push_back(iter->second);
458 }
459 }
460 }
461 }
462}
463
464/** Makes the Parser parse the command line options with current known options.
465 * \param _argc arg count from main()
466 * \param **_argv argument array from main()
467 */
468void CommandLineParser::Run(int _argc, char **_argv)
469{
470 setOptions(_argc,_argv);
471 Parse();
472 scanforSequenceOfArguments();
473}
474
475/** Go through all Actions and create a map from short form to their token.
476 * \return map from Action's ShortForm to token.
477 */
478std::map <std::string, std::string> CommandLineParser::getShortFormToActionMap() const
479{
480 std::map <std::string, std::string> result;
481
482 ActionRegistry &AR = ActionRegistry::getInstance();
483 for (ActionRegistry::const_iterator iter = AR.getBeginIter(); iter != AR.getEndIter(); ++iter)
484 if ((iter->second)->Traits.hasShortForm()) {
485 ASSERT(result.find((iter->second)->Traits.getShortForm()) == result.end(),
486 "Short form "+toString((iter->second)->Traits.getShortForm())+
487 " for action "+toString(iter->first)+" already present from "+
488 std::string(result[(iter->second)->Traits.getShortForm()])+"!");
489 result[(iter->second)->Traits.getShortForm()] = (iter->second)->getName();
490 }
491
492 return result;
493}
494
495CONSTRUCT_SINGLETON(CommandLineParser)
Note: See TracBrowser for help on using the repository browser.