Geant4 11.4.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
LUPI_argumentParser.cc
Go to the documentation of this file.
1/*
2# <<BEGIN-copyright>>
3# Copyright 2019, Lawrence Livermore National Security, LLC.
4# This file is part of the gidiplus package (https://github.com/LLNL/gidiplus).
5# gidiplus is licensed under the MIT license (see https://opensource.org/licenses/MIT).
6# SPDX-License-Identifier: MIT
7# <<END-copyright>>
8*/
9
10#include <stdlib.h>
11#include <iostream>
12
13#include <LUPI.hpp>
14
15namespace LUPI {
16
17static void printArgumentDescription( std::string const &a_line, std::string const &a_descriptor );
18static std::size_t maxPrintLineWidth = 120;
19
20/*! \class ArgumentBase
21 * Base class for argument and option sub-classes.
22 */
23
24/* *********************************************************************************************************//**
25 * ArgumentBase constructor.
26 *
27 * @param a_argumentType [in] The type of argument to create.
28 * @param a_name [in] The name of the argument.
29 * @param a_descriptor [in] The string printed with arugment's help.
30 * @param a_minimumNeeded [in] The minimum number of times the argument must be entered.
31 * @param a_maximumNeeded [in] The maximum number of times the argument can be entered.
32 ***********************************************************************************************************/
33
34ArgumentBase::ArgumentBase( ArgumentType a_argumentType, std::string const &a_name, std::string const &a_descriptor, int a_minimumNeeded, int a_maximumNeeded ) :
35 m_argumentType( a_argumentType ),
36 m_names( ),
37 m_descriptor( a_descriptor ),
38 m_minimumNeeded( a_minimumNeeded ),
39 m_maximumNeeded( a_maximumNeeded ),
40 m_counts( 0 ) {
41
42 if( m_minimumNeeded < 0 ) throw std::runtime_error( "ERROR 1000 in ArgumentBase::ArgumentBase: m_minimumNeeded must not be negative." );
43 if( m_maximumNeeded > -1 ) {
44 if( m_minimumNeeded > m_maximumNeeded )
45 throw std::runtime_error( "ERROR 1010 in ArgumentBase::ArgumentBase: for argument '" + a_name + "' m_maximumNeeded less than m_minimumNeeded." );
46 }
47
48 if( m_argumentType == ArgumentType::Positional ) {
49 if( a_name[0] == '-' )
50 throw std::runtime_error( "ERROR 1020 in ArgumentBase::ArgumentBase: positional argument name '" + a_name + "' cannot start with a '-'." );
51 }
52
53 addAlias( a_name );
54}
55
56/* *********************************************************************************************************//**
57 * ArgumentBase destructor.
58 ***********************************************************************************************************/
59
63
64/* *********************************************************************************************************//**
65 * Returns true if *a_name* is one of the names for *this* and false otherwise.
66 *
67 * @param a_name [in] The name to search for.
68 *
69 * @return Returns true if *a_name* is a match for one of the names for *this* and false otherwise.
70 ***********************************************************************************************************/
71
72bool ArgumentBase::hasName( std::string const &a_name ) const {
73
74 for( auto iter = m_names.begin( ); iter != m_names.end( ); ++iter ) {
75 if( a_name == *iter ) return( true );
76 }
77 return( false );
78}
79
80/* *********************************************************************************************************//**
81 * Returns the value at index *a_index*. If *a_index* exceeds the number of values entered, a throw is executed.
82 *
83 * @param a_index [in] The 0-based index into the m_values std::vector whose content is returned.
84 *
85 * @return Returns the value entered at index *a_index*.
86 ***********************************************************************************************************/
87
88std::string const &ArgumentBase::value( std::size_t a_index ) const {
89
90 if( ( m_argumentType == ArgumentType::True ) || ( m_argumentType == ArgumentType::False ) || ( m_argumentType == ArgumentType::Count ) )
91 throw Exception( "Argument type for " + name( ) + " does not support calling value() method." );
92
93 if( a_index >= m_values.size( ) ) throw Exception( "Index = " + std::to_string( a_index ) + " out-of-bounds for argument \"" + name( ) + "\"." );
94
95 return( m_values[a_index] );
96}
97
98/* *********************************************************************************************************//**
99 * Add *a_name* as an optional name for *this*.
100 *
101 * @param a_name [in] The name to add.
102 ***********************************************************************************************************/
103
104void ArgumentBase::addAlias( std::string const &a_name ) {
105
106 if( m_argumentType == ArgumentType::Positional ) {
107 if( m_names.size( ) > 0 ) throw std::runtime_error( "ERROR 1100 in ArgumentBase::addAlias: cannot add a name to a positional argument." ); }
108 else {
109 if( a_name[0] != '-' ) throw std::runtime_error( "ERROR 1110 in ArgumentBase::addAlias: name '" + a_name + "' not a valid optional name." );
110 }
111
112 if( hasName( a_name ) ) return;
113
114 m_names.push_back( a_name );
115}
116
117/* *********************************************************************************************************//**
118 * Counts each time a specific argument is found.
119 *
120 * @param a_index [in] The index of the current command argument in *a_argv*.
121 * @param a_argc [in] The number of command arguments.
122 * @param a_argv [in] The list of command arguments.
123 *
124 * @return The value of *a_index* + 1.
125 ***********************************************************************************************************/
126
127int ArgumentBase::parse( ArgumentParser const &a_argumentParser, int a_index, int a_argc, char **a_argv ) {
128
129 ++m_counts;
130 if( m_argumentType != ArgumentType::Positional ) ++a_index;
131
132 if( ( m_argumentType == ArgumentType::Store ) || ( m_argumentType == ArgumentType::Append ) || ( m_argumentType == ArgumentType::Positional ) ) {
133 int maximumNeeded1 = maximumNeeded( );
134 if( m_argumentType == ArgumentType::Positional ) {
135 if( maximumNeeded1 < 0 ) maximumNeeded1 = a_argc; }
136 else {
137 if( ( maximumNeeded1 < static_cast<int>( counts( ) ) ) && ( maximumNeeded1 > -1 ) )
138 throw std::runtime_error( "ERROR 1220 in ArgumentBase::parse: too many values for optional argument " + name( ) + " entered." );
139 maximumNeeded1 = 1;
140 }
141
142 for( int index = 0; index < maximumNeeded1; ++index ) {
143 if( a_index == a_argc ) {
144 if( m_argumentType == ArgumentType::Positional ) break;
145 throw std::runtime_error( "ERROR 1200 in ArgumentBase::parse: missing value for argument " + name( ) + "." );
146 }
147 if( ( m_argumentType == ArgumentType::Positional ) && a_argumentParser.isOptionalArgument( a_argv[a_index] ) ) break;
148
149 m_values.push_back( a_argv[a_index] );
150 if( index > 0 ) ++m_counts;
151 ++a_index;
152 }
153 }
154
155 return( a_index );
156}
157
158/* *********************************************************************************************************//**
159 * Returns the usage string for *this* argument.
160 *
161 * @param a_requiredOption [in] The index of the current command argument in *a_argv*.
162 *
163 * @return The value of *a_index* + 1.
164 ***********************************************************************************************************/
165
166std::string ArgumentBase::usage( bool a_requiredOption ) const {
167
168 std::string usageString;
169
170 if( isOptionalArgument( ) ) {
171 if( a_requiredOption ) {
172 if( m_minimumNeeded != 0 ) return( usageString ); }
173 else {
174 if( m_minimumNeeded == 0 ) return( usageString );
175 }
176 }
177 usageString += " ";
178
179 std::string value;
180 if( isOptionalArgument( ) && requiresAValue( ) ) value = " VALUE";
181 if( isOptionalArgument( ) && ( m_minimumNeeded == 0 ) ) {
182 usageString += "[" + name( ) + value + "]"; }
183 else {
184 usageString += name( ) + value;
185 }
186
187 if( !isOptionalArgument( ) ) {
188 if( ( m_minimumNeeded != 1 ) || ( m_maximumNeeded != 1 ) )
189 usageString += "[" + std::to_string( m_minimumNeeded ) + "," + std::to_string( m_maximumNeeded ) + "]";
190 }
191
192 return( usageString );
193}
194
195/* *********************************************************************************************************//**
196 * Prints generic information about the status of *this*.
197 *
198 * @param a_indent [in] The amount of indentation to start the first line with.
199 *
200 * @return The value of *a_index* + 1.
201 ***********************************************************************************************************/
202
203void ArgumentBase::printStatus( std::string a_indent ) const {
204
205 std::string name1 = name( );
206 if( name1.size( ) < 32 ) name1.resize( 32, ' ' );
207
208 std::cout << a_indent << name1 << ": number entered " << std::to_string( m_counts )
209 << "; number needed (" << std::to_string( m_minimumNeeded ) << "," << std::to_string( m_maximumNeeded ) << ")"
210 << printStatus2( ) << std::endl;
211 printStatus3( a_indent + " " );
212}
213
214/* *********************************************************************************************************//**
215 * Called by *printStatus*. This method returns an empty string. Must be overwritten by argument classes that have value.
216 *
217 * @return An empty **std::string** instance.
218 ***********************************************************************************************************/
219
220std::string ArgumentBase::printStatus2( ) const {
221
222 return( "" );
223
224}
225
226/* *********************************************************************************************************//**
227 * Called by *printStatus*. This method does nothing. Must be overwritten by argument classes that have value(s).
228 *
229 * @param a_indent [in] The amount of indentation to start the first line with.
230 ***********************************************************************************************************/
231
232void ArgumentBase::printStatus3( LUPI_maybeUnused std::string const &a_indent ) const {
233
234}
235
236/*! \class OptionBoolean
237 * Base boolean class.
238 */
239
240/* *********************************************************************************************************//**
241 * OptionBoolean constructor.
242 *
243 * @param a_argumentType [in] The type of argument to create.
244 * @param a_name [in] The name of the argument.
245 * @param a_descriptor [in] The string printed with arugment's help.
246 * @param a_default [in] The default bool value.
247 ***********************************************************************************************************/
248
249OptionBoolean::OptionBoolean( ArgumentType a_argumentType, std::string const &a_name, std::string const &a_descriptor, bool a_default ) :
250 ArgumentBase( a_argumentType, a_name, a_descriptor, 0, -1 ),
251 m_default( a_default ) {
252
253}
254
255/* *********************************************************************************************************//**
256 * OptionBoolean destructor.
257 ***********************************************************************************************************/
258
262
263/* *********************************************************************************************************//**
264 * Called by *printStatus*. This method returns a string representing *this*'s value.
265 *
266 * @return Returns a std::string instance representing the value of *this*.
267 ***********************************************************************************************************/
268
269std::string OptionBoolean::printStatus2( ) const {
270
271 bool value1 = m_default;
272 if( counts() == 0 ) value1 = !m_default;
273
274 if( value1 ) return( ": true" );
275 return( ": false" );
276}
277
278/*! \class OptionTrue
279 * An boolean optional argument whose default is *false* and changes to *true* if one or more options are entered.
280 */
281
282/* *********************************************************************************************************//**
283 * OptionTrue constructor.
284 *
285 * @param a_name [in] The name of the argument.
286 * @param a_descriptor [in] The string printed with arugment's help.
287 * @param a_minimumNeeded [in] Not used. Will probably be deprecated.
288 * @param a_maximumNeeded [in] Not used. Will probably be deprecated.
289 ***********************************************************************************************************/
290
291OptionTrue::OptionTrue( std::string const &a_name, std::string const &a_descriptor, LUPI_maybeUnused int a_minimumNeeded, LUPI_maybeUnused int a_maximumNeeded ) :
292 OptionBoolean( ArgumentType::True, a_name, a_descriptor, false ) {
293
294}
295
296/*! \class OptionFalse
297 * An boolean optional argument whose default is *true* and changes to *false* if one or more options are entered.
298 */
299
300/* *********************************************************************************************************//**
301 * OptionFalse constructor.
302 *
303 * @param a_name [in] The name of the argument.
304 * @param a_descriptor [in] The string printed with arugment's help.
305 * @param a_minimumNeeded [in] Not used. Will probably be deprecated.
306 * @param a_maximumNeeded [in] Not used. Will probably be deprecated.
307 ***********************************************************************************************************/
308
309OptionFalse::OptionFalse( std::string const &a_name, std::string const &a_descriptor, LUPI_maybeUnused int a_minimumNeeded, LUPI_maybeUnused int a_maximumNeeded ) :
310 OptionBoolean( ArgumentType::False, a_name, a_descriptor, true ) {
311
312}
313
314/*! \class OptionCounter
315 * An optional argument that counts the number of times the option is entered.
316 */
317
318/* *********************************************************************************************************//**
319 * OptionCounter constructor.
320 *
321 * @param a_name [in] The name of the argument.
322 * @param a_descriptor [in] The string printed with arugment's help.
323 * @param a_minimumNeeded [in] Not used. Will probably be deprecated.
324 * @param a_maximumNeeded [in] Not used. Will probably be deprecated.
325 ***********************************************************************************************************/
326
327OptionCounter::OptionCounter( std::string const &a_name, std::string const &a_descriptor, LUPI_maybeUnused int a_minimumNeeded, LUPI_maybeUnused int a_maximumNeeded ) :
328 ArgumentBase( ArgumentType::Count, a_name, a_descriptor, 0, -1 ) {
329
330}
331
332/* *********************************************************************************************************//**
333 * Called by *printStatus*. This method returns a string representing *this*'s value.
334 ***********************************************************************************************************/
335
336std::string OptionCounter::printStatus2( ) const {
337
338 return( " counts = " + std::to_string( counts( ) ) );
339}
340
341/*! \class OptionStore
342 * An option with a value. If multiple options with the same name are entered, only the last vluae entered if returned by the value() method.
343 */
344
345/* *********************************************************************************************************//**
346 * OptionStore constructor.
347 *
348 * @param a_name [in] The name of the argument.
349 * @param a_descriptor [in] The string printed with arugment's help.
350 * @param a_minimumNeeded [in] Not used. Will probably be deprecated.
351 * @param a_maximumNeeded [in] Not used. Will probably be deprecated.
352 ***********************************************************************************************************/
353
354OptionStore::OptionStore( std::string const &a_name, std::string const &a_descriptor, LUPI_maybeUnused int a_minimumNeeded, LUPI_maybeUnused int a_maximumNeeded ) :
355 ArgumentBase( ArgumentType::Store, a_name, a_descriptor, 0, -1 ) {
356
357}
358
359/* *********************************************************************************************************//**
360 * Returns the value of
361 *
362 * @param a_index [in] This argument is not used. The last value entered is always returned.
363 *
364 * @return Returns the last value entered or executes a **throw** if option not entered.
365 ***********************************************************************************************************/
366
367std::string const &OptionStore::value( std::size_t a_index ) const {
368
369 a_index = values( ).size( );
370 if( a_index != 0 ) --a_index;
371
372 return ArgumentBase::value( a_index );
373}
374
375/* *********************************************************************************************************//**
376 * Prints the value for *this*. Called by *printStatus*.
377 *
378 * @param a_indent [in] The amount of indentation to start the first line with.
379 ***********************************************************************************************************/
380
381void OptionStore::printStatus3( std::string const &a_indent ) const {
382
383 if( counts( ) > 0 ) std::cout << a_indent << value( ) << std::endl;
384}
385
386/*! \class OptionAppend
387 * An option with a value. If multiple options with the same name are entered, all values will be stored.
388 */
389
390/* *********************************************************************************************************//**
391 * OptionAppend constructor.
392 *
393 * @param a_name [in] The name of the argument.
394 * @param a_descriptor [in] The string printed with arugment's help.
395 * @param a_minimumNeeded [in] The minimum number of times the argument must be entered.
396 * @param a_maximumNeeded [in] The maximum number of times the argument can be entered.
397 ***********************************************************************************************************/
398
399OptionAppend::OptionAppend( std::string const &a_name, std::string const &a_descriptor, int a_minimumNeeded, int a_maximumNeeded ) :
400 ArgumentBase( ArgumentType::Append, a_name, a_descriptor, a_minimumNeeded, a_maximumNeeded ) {
401
402}
403
404/* *********************************************************************************************************//**
405 * Prints the values for *this*. Called by *printStatus*.
406 *
407 * @param a_indent [in] The amount of indentation to start the first line with.
408 ***********************************************************************************************************/
409
410void OptionAppend::printStatus3( std::string const &a_indent ) const {
411
412 for( auto valueIterator = values( ).begin( ); valueIterator != values( ).end( ); ++valueIterator ) {
413 std::cout << a_indent << *valueIterator << std::endl;
414 }
415}
416
417/*! \class Positional
418 * An option with a value. If multiple options with the same name are entered, the *m_value* member will represent the last option entered.
419 */
420
421/* *********************************************************************************************************//**
422 * Positional constructor.
423 *
424 * @param a_name [in] The name of the argument.
425 * @param a_descriptor [in] The string printed with arugment's help.
426 * @param a_minimumNeeded [in] The minimum number of times the argument must be entered.
427 * @param a_maximumNeeded [in] The maximum number of times the argument can be entered.
428 ***********************************************************************************************************/
429
430Positional::Positional( std::string const &a_name, std::string const &a_descriptor, int a_minimumNeeded, int a_maximumNeeded ) :
431 ArgumentBase( ArgumentType::Positional, a_name, a_descriptor, a_minimumNeeded, a_maximumNeeded ) {
432}
433
434/* *********************************************************************************************************//**
435 * Prints the values for *this*. Called by *printStatus*.
436 *
437 * @param a_indent [in] The amount of indentation to start the first line with.
438 ***********************************************************************************************************/
439
440void Positional::printStatus3( std::string const &a_indent ) const {
441
442 for( auto valueIterator = values( ).begin( ); valueIterator != values( ).end( ); ++valueIterator ) {
443 std::cout << a_indent << *valueIterator << std::endl;
444 }
445}
446
447/*! \class ArgumentParser
448 * The main argument parser class.
449 */
450
451/* *********************************************************************************************************//**
452 * ArgumentParser constructor.
453 ***********************************************************************************************************/
454
455ArgumentParser::ArgumentParser( std::string const &a_codeName, std::string const &a_descriptor ) :
456 m_codeName( FileInfo::basenameWithoutExtension( a_codeName ) ),
457 m_descriptor( a_descriptor ) {
458
459}
460
461/* *********************************************************************************************************//**
462 * ArgumentParser destructor.
463 ***********************************************************************************************************/
464
466
467 for( auto argumentIterator = m_arguments.begin( ); argumentIterator != m_arguments.end( ); ++argumentIterator ) {
468 delete *argumentIterator;
469 }
470}
471
472/* *********************************************************************************************************//**
473 * Add *a_argumentBase* to the list of arguments.
474 *
475 * @param a_argumentBase [in] Pointer to the *ArgumentBase* to add to *this*.
476 ***********************************************************************************************************/
477
478void ArgumentParser::add2( ArgumentBase *a_argumentBase ) {
479
480 if( !a_argumentBase->isOptionalArgument( ) ) {
481 for( auto argumentIterator = m_arguments.rbegin( ); argumentIterator != m_arguments.rend( ); ++argumentIterator ) {
482 if( !(*argumentIterator)->isOptionalArgument( ) ) {
483 if( (*argumentIterator)->minimumNeeded( ) == (*argumentIterator)->maximumNeeded( ) ) break;
484 throw std::runtime_error( "ERROR 1400 in ArgumentParser::add: request to add postional argument when prior postional argument '"
485 + (*argumentIterator)->name( ) + "' takes a variable number of values." );
486 }
487 }
488 }
489
490 if( hasName( a_argumentBase->name( ) ) )
491 throw std::runtime_error( "ERROR 1500 in ArgumentParser::add: name '" + a_argumentBase->name( ) + "' already present." );
492
493 m_arguments.push_back( a_argumentBase );
494}
495
496/* *********************************************************************************************************//**
497 * Creates an argument instance of type specified by *a_argumentType* and adds to *this*.
498 *
499 * @param a_argumentType [in] The type of argument to create.
500 * @param a_name [in] The name of the argument.
501 * @param a_descriptor [in] The string printed with arugment's help.
502 * @param a_minimumNeeded [in] The minimum number of times the argument must be entered.
503 * @param a_maximumNeeded [in] The maximum number of times the argument can be entered.
504 *
505 * @return Returns a pointer to to the created argument instance.
506 ***********************************************************************************************************/
507
508ArgumentBase *ArgumentParser::add( ArgumentType a_argumentType, std::string const &a_name, std::string const &a_descriptor,
509 int a_minimumNeeded, int a_maximumNeeded ) {
510
511 ArgumentBase *argument = nullptr;
512
513 switch( a_argumentType ) {
514 case ArgumentType::True :
515 argument = new OptionTrue( a_name, a_descriptor );
516 break;
518 argument = new OptionFalse( a_name, a_descriptor );
519 break;
521 argument = new OptionCounter( a_name, a_descriptor );
522 break;
524 argument = new OptionStore( a_name, a_descriptor );
525 break;
527 argument = new OptionAppend( a_name, a_descriptor, a_minimumNeeded, a_maximumNeeded );
528 break;
529 default :
530 argument = new Positional( a_name, a_descriptor, a_minimumNeeded, a_maximumNeeded );
531 }
532
533 add2( argument );
534
535 return( argument );
536}
537
538/* *********************************************************************************************************//**
539 * Adds the alias *a_alias* to the argument named *a_name*.
540 *
541 * @param a_name [in] The name of the argument to add the alias to.
542 * @param a_alias [in] The alias name to add.
543 ***********************************************************************************************************/
544
545void ArgumentParser::addAlias( std::string const &a_name, std::string const &a_alias ) {
546
547 if( hasName( a_alias ) )
548 throw std::runtime_error( "ERROR 1510 in ArgumentParser::addAlias: name '" + a_alias + "' already present." );
549
550 for( auto argumentIterator = m_arguments.begin( ); argumentIterator != m_arguments.end( ); ++argumentIterator ) {
551 if( (*argumentIterator)->hasName( a_name ) ) {
552 (*argumentIterator)->addAlias( a_alias );
553 return;
554 }
555 }
556 throw std::runtime_error( "ERROR 1520 in ArgumentParser::addAlias: no such argument named '" + a_name + "'." );
557}
558
559/* *********************************************************************************************************//**
560 * Adds the alias *a_alias* to the argument *a_argumentBase*.
561 *
562 * @param a_argumentBase [in] The argument to add the alias to.
563 * @param a_alias [in] The name of the argument to add the alias to.
564 ***********************************************************************************************************/
565
566void ArgumentParser::addAlias( ArgumentBase const * const a_argumentBase, std::string const &a_alias ) {
567
568 addAlias( a_argumentBase->name( ), a_alias );
569}
570
571/* *********************************************************************************************************//**
572 * Returns true if name *a_name* is an optional argument of *this* and false otherwise.
573 *
574 * @param a_name [in] The name to see check if it exists in *this*.
575 *
576 * @return true if name *a_name* is in *this* and false otherwise.
577 ***********************************************************************************************************/
578
579bool ArgumentParser::isOptionalArgument( std::string const &a_name ) const {
580
581 for( auto argumentIterator = m_arguments.begin( ); argumentIterator != m_arguments.end( ); ++argumentIterator ) {
582 if( (*argumentIterator)->hasName( a_name ) ) return( (*argumentIterator)->argumentType( ) != ArgumentType::Positional );
583 }
584
585 return( false );
586}
587
588/* *********************************************************************************************************//**
589 * Returns true if name *a_name* is in *this* and false otherwise.
590 *
591 * @param a_name [in] The name to see check if it exists in *this*.
592 *
593 * @return true if name *a_name* is in *this* and false otherwise.
594 ***********************************************************************************************************/
595
596bool ArgumentParser::hasName( std::string const &a_name ) const {
597
598 for( auto argumentIterator = m_arguments.begin( ); argumentIterator != m_arguments.end( ); ++argumentIterator ) {
599 if( (*argumentIterator)->hasName( a_name ) ) return( true );
600 }
601
602 return( false );
603}
604
605/* *********************************************************************************************************//**
606 * Parses the list of arguments.
607 *
608 * @param a_argc [in] The number of arguments.
609 * @param a_argv [in] The list of arguments.
610 ***********************************************************************************************************/
611
612void ArgumentParser::parse( int a_argc, char **a_argv, bool a_printArguments ) {
613
614 for( int iargc = 1; iargc < a_argc; ++iargc ) { // Check is help requested.
615 std::string arg( a_argv[iargc] );
616
617 if( ( arg == "-h" ) || ( arg == "--help" ) ) help( );
618 }
619
620 auto argumentIterator = m_arguments.begin( ); // Find first non-option argument.
621 for( ; argumentIterator != m_arguments.end( ); ++argumentIterator ) {
622 if( !(*argumentIterator)->isOptionalArgument( ) ) break;
623 }
624
625 int iargc = 1;
626 for( ; iargc < a_argc; ) {
627 std::string arg( a_argv[iargc] );
628
629 if( arg[0] == '-' ) { // Need to check if negative number.
630 auto argumentIterator2 = m_arguments.begin( );
631 for( ; argumentIterator2 != m_arguments.end( ); ++argumentIterator2 ) {
632 if( (*argumentIterator2)->hasName( arg ) ) break;
633 }
634 if( argumentIterator2 == m_arguments.end( ) ) throw std::runtime_error( "ERROR 1600 in ArgumentParser::parse: invalid option '" + arg + "'." );
635 iargc = (*argumentIterator2)->parse( *this, iargc, a_argc, a_argv ); }
636 else {
637 if( argumentIterator == m_arguments.end( ) )
638 throw std::runtime_error( "ERROR 1610 in ArgumentParser::parse: additional positional argument found starting at index "
639 + std::to_string( iargc ) + " (" + arg + ")" );
640
641 iargc = (*argumentIterator)->parse( *this, iargc, a_argc, a_argv );
642
643 ++argumentIterator;
644 for( ; argumentIterator != m_arguments.end( ); ++argumentIterator ) { // Find next positional arguments.
645 if( !(*argumentIterator)->isOptionalArgument( ) ) break;
646 }
647 }
648 }
649 for( auto argumentIterator2 = m_arguments.begin( ); argumentIterator2 != m_arguments.end( ); ++argumentIterator2 ) {
650 if( static_cast<int>( (*argumentIterator2)->counts( ) ) < (*argumentIterator2)->minimumNeeded( ) ) {
651 std::string msg( "arguments for" );
652
653 if( (*argumentIterator2)->isOptionalArgument( ) ) msg = "number of option";
654 throw std::runtime_error( "ERROR 1620 in ArgumentParser::parse: insufficient " + msg + " '" + (*argumentIterator2)->name( )
655 + "' entered. Range of " + std::to_string( (*argumentIterator2)->minimumNeeded( ) ) + " to "
656 + std::to_string( (*argumentIterator2)->maximumNeeded( ) ) + " required, "
657 + std::to_string( (*argumentIterator2)->counts( ) ) + " entered." );
658 }
659 }
660
661 if( a_printArguments ) {
662 std::cerr << " " << LUPI::FileInfo::basenameWithoutExtension( m_codeName );
663 for( int i1 = 1; i1 < a_argc; i1++ ) std::cerr << " " << a_argv[i1];
664 std::cerr << std::endl;
665 }
666}
667
668/* *********************************************************************************************************//**
669 * Prints the help for *this*.
670 ***********************************************************************************************************/
671
672void ArgumentParser::help( ) const {
673
674 usage( );
675
676 if( m_descriptor != "" ) {
677 std::cout << std::endl << "Description:" << std::endl;
678 std::cout << " " << m_descriptor << std::endl;
679 }
680
681 bool printHeader = true;
682 for( auto argumentIterator = m_arguments.begin( ); argumentIterator != m_arguments.end( ); ++argumentIterator ) {
683 if( (*argumentIterator)->isOptionalArgument( ) ) continue;
684
685 if( printHeader ) std::cout << std::endl << "positional arguments:" << std::endl;
686 printHeader = false;
687
688 std::string line = (*argumentIterator)->name( );
689 if( ( (*argumentIterator)->minimumNeeded( ) != (*argumentIterator)->maximumNeeded( ) ) || ( (*argumentIterator)->maximumNeeded( ) != 1 ) )
690 line += " [" + std::to_string( (*argumentIterator)->minimumNeeded( ) ) + "," + std::to_string( (*argumentIterator)->maximumNeeded( ) ) + "]";
691 printArgumentDescription( line, (*argumentIterator)->descriptor( ) );
692 }
693
694 std::cout << std::endl << "optional arguments:" << std::endl;
695 std::cout << " -h, --help Show this help message and exit." << std::endl;
696 for( auto argumentIterator = m_arguments.begin( ); argumentIterator != m_arguments.end( ); ++argumentIterator ) {
697 if( !(*argumentIterator)->isOptionalArgument( ) ) continue;
698
699 std::string line;
700 std::string sep;
701 for( auto namesIterator = (*argumentIterator)->names( ).begin( ); namesIterator != (*argumentIterator)->names( ).end( ); ++namesIterator ) {
702 line += sep + *namesIterator;
703 sep = ", ";
704 }
705 if( (*argumentIterator)->requiresAValue( ) ) line += " VALUE";
706 if( (*argumentIterator)->argumentType( ) == ArgumentType::Append ) {
707 if( ( (*argumentIterator)->minimumNeeded( ) != (*argumentIterator)->maximumNeeded( ) ) || ( (*argumentIterator)->maximumNeeded( ) != 1 ) )
708 line += " [" + std::to_string( (*argumentIterator)->minimumNeeded( ) ) + "," + std::to_string( (*argumentIterator)->maximumNeeded( ) ) + "]";
709 }
710 printArgumentDescription( line, (*argumentIterator)->descriptor( ) );
711 }
712
713 exit( EXIT_SUCCESS );
714}
715
716/* *********************************************************************************************************//**
717 * Prints the usage for *this*.
718 ***********************************************************************************************************/
719
721
722 std::string line( "usage: " );
723 line += codeName( );
724 std::string indent( "" );
725 indent.resize( line.size( ), ' ' );
726
727 for( int counter = 0; counter < 2; ++counter ) {
728 for( auto argumentIterator = m_arguments.begin( ); argumentIterator != m_arguments.end( ); ++argumentIterator ) {
729 if( (*argumentIterator)->isOptionalArgument( ) ) {
730 std::string optionUsage( (*argumentIterator)->usage( counter == 0 ) );
731
732 if( ( line.size( ) + optionUsage.size( ) ) > maxPrintLineWidth ) {
733 std::cout << line << std::endl;
734 line = indent;
735 }
736 line += optionUsage;
737 }
738 }
739 }
740
741 for( auto argumentIterator = m_arguments.begin( ); argumentIterator != m_arguments.end( ); ++argumentIterator ) {
742 if( (*argumentIterator)->isOptionalArgument( ) ) continue;
743 std::string optionUsage( (*argumentIterator)->usage( false ) );
744
745 if( ( line.size( ) + optionUsage.size( ) ) > maxPrintLineWidth ) {
746 std::cout << line << std::endl;
747 line = indent;
748 }
749 line += optionUsage;
750 }
751 if( line.size( ) > indent.size( ) ) std::cout << line << std::endl;
752 std::cout << std::endl;
753}
754
755/* *********************************************************************************************************//**
756 * Returns the usage string for *this* option.
757 *
758 * @param a_indent [in] The amount of indentation to start the first line with.
759 *
760 * @return The value of *a_index* + 1.
761 ***********************************************************************************************************/
762
763void ArgumentParser::printStatus( std::string a_indent ) const {
764
765 for( auto argumentIterator = m_arguments.begin( ); argumentIterator != m_arguments.end( ); ++argumentIterator ) {
766 (*argumentIterator)->printStatus( a_indent );
767 }
768}
769
770
771/* *********************************************************************************************************//**
772 * For internal use only.
773 *
774 * @param a_line [in] A string containing the help line for an argument up to the description string.
775 * @param a_descriptor [in] The help description string.
776 ***********************************************************************************************************/
777
778static void printArgumentDescription( std::string const &a_line, std::string const &a_descriptor ) {
779
780 std::string newLineSpaces = " ";
781 auto size = newLineSpaces.size( );
782 auto maxDescriptionWidth = maxPrintLineWidth - size;
783 std::string line = " " + a_line;
784 if( line.size( ) < size ) line.resize( size, ' ' );
785 std::cout << line;
786 if( line.size( ) > size ) std::cout << std::endl << newLineSpaces;
787
788 std::string descriptor = a_descriptor;
789 while( descriptor.size( ) > 0 ) {
790 auto length = descriptor.size( );
791 if( length > maxDescriptionWidth ) {
792 length = maxDescriptionWidth;
793 length = descriptor.rfind( ' ', length );
794 if( length == 0 ) length = descriptor.find( ' ', length );
795 }
796
797 std::cout << " " << descriptor.substr( 0, length ) << std::endl;
798 descriptor = descriptor.substr( length );
799 auto firstNotOf = descriptor.find_first_not_of( " " );
800 if( firstNotOf != descriptor.npos ) descriptor = descriptor.substr( firstNotOf );
801 if( descriptor.size( ) > 0 ) std::cout << newLineSpaces;
802 }
803}
804
805} // End of namespace LUPI.
#define LUPI_maybeUnused
virtual bool requiresAValue() const
Definition LUPI.hpp:219
std::vector< std::string > const & values() const
Definition LUPI.hpp:217
virtual bool isOptionalArgument() const
Definition LUPI.hpp:218
bool hasName(std::string const &a_name) const
virtual std::string const & value(std::size_t a_index=0) const
std::size_t counts() const
Definition LUPI.hpp:214
ArgumentBase(ArgumentType a_argumentType, std::string const &a_name, std::string const &a_descriptor, int a_minimumNeeded, int a_maximumNeeded)
virtual int parse(ArgumentParser const &a_argumentParser, int a_index, int a_argc, char **a_argv)
std::string const & name() const
Definition LUPI.hpp:208
void printStatus(std::string a_indent) const
int maximumNeeded() const
Definition LUPI.hpp:213
std::string usage(bool a_requiredOption) const
virtual void printStatus(std::string a_indent) const
std::string const & codeName() const
Definition LUPI.hpp:145
T * add(std::string const &a_name, std::string const &a_descriptor, int a_minimumNeeded=1, int a_maximumNeeded=1)
Definition LUPI.hpp:172
ArgumentParser(std::string const &a_codeName, std::string const &a_descriptor="")
bool hasName(std::string const &a_name) const
void parse(int a_argc, char **a_argv, bool a_printArguments=true)
bool isOptionalArgument(std::string const &a_name) const
void addAlias(std::string const &a_name, std::string const &a_alias)
void printStatus3(std::string const &a_indent) const
OptionAppend(std::string const &a_name, std::string const &a_descriptor="", int a_minimumNeeded=0, int a_maximumNeeded=-1)
std::string printStatus2() const
OptionBoolean(ArgumentType a_argumentType, std::string const &a_name, std::string const &a_descriptor, bool a_default)
OptionCounter(std::string const &a_name, std::string const &a_descriptor="", int a_minimumNeeded=0, int a_maximumNeeded=-1)
std::string printStatus2() const
OptionFalse(std::string const &a_name, std::string const &a_descriptor="", int a_minimumNeeded=0, int a_maximumNeeded=-1)
std::string const & value(std::size_t a_index=0) const
OptionStore(std::string const &a_name, std::string const &a_descriptor="", int a_minimumNeeded=0, int a_maximumNeeded=-1)
void printStatus3(std::string const &a_indent) const
OptionTrue(std::string const &a_name, std::string const &a_descriptor="", int a_minimumNeeded=0, int a_maximumNeeded=-1)
void printStatus3(std::string const &a_indent) const
Positional(std::string const &a_name, std::string const &a_descriptor="", int a_minimumNeeded=1, int a_maximumNeeded=1)
std::string basenameWithoutExtension(std::string const &a_path)
Definition LUPI_file.cc:99
Definition LUPI.hpp:40
ArgumentType
Definition LUPI.hpp:128
std::string to_string(G4FermiAtomicMass mass)