source: src/UIElements/CommandLineUI/CommandLineParser.cpp@ 14de8e1

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 14de8e1 was 4dc309, checked in by Frederik Heber <heber@…>, 12 years ago

SetShapeAction added

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