Branch data Line data Source code
1 : : #include <iostream>
2 : : #include <sstream>
3 : : #include <iomanip>
4 : : #include <cstdlib>
5 : : #include <list>
6 : : #include <limits>
7 : : #include <set>
8 : : #include <algorithm>
9 : :
10 : : #include <assert.h>
11 : : #include <string.h>
12 : :
13 : : #include "moab/MOABConfig.h"
14 : : #include "moab/ProgOptions.hpp"
15 : : #ifdef MOAB_HAVE_MPI
16 : : #include "moab_mpi.h"
17 : : #endif
18 : :
19 : : enum OptType
20 : : {
21 : : FLAG = 0,
22 : : INT,
23 : : REAL,
24 : : STRING,
25 : : INT_VECT
26 : : };
27 : :
28 : : template < typename T >
29 : : inline static OptType get_opt_type();
30 : :
31 : : template <>
32 : 40 : OptType get_opt_type< void >()
33 : : {
34 : 40 : return FLAG;
35 : : }
36 : : template <>
37 : 25 : OptType get_opt_type< int >()
38 : : {
39 : 25 : return INT;
40 : : }
41 : : template <>
42 : 15 : OptType get_opt_type< double >()
43 : : {
44 : 15 : return REAL;
45 : : }
46 : : template <>
47 : 42 : OptType get_opt_type< std::string >()
48 : : {
49 : 42 : return STRING;
50 : : }
51 : : template <>
52 : 5 : OptType get_opt_type< std::vector< int > >()
53 : : {
54 : 5 : return INT_VECT;
55 : : }
56 : :
57 : 196 : class ProgOpt
58 : : {
59 : :
60 : : std::string shortname, longname;
61 : : std::vector< std::string > args;
62 : : OptType type;
63 : : void* storage;
64 : : int flags;
65 : : ProgOpt* cancel_opt;
66 : :
67 : 0 : const char* get_argstring() const
68 : : {
69 [ # # # # : 0 : switch( type )
# ]
70 : : {
71 : : case INT:
72 : 0 : return "int";
73 : : case INT_VECT:
74 : 0 : return "ints";
75 : : case REAL:
76 : 0 : return "val";
77 : : case FLAG:
78 : 0 : return "";
79 : : default:
80 : 0 : return "arg";
81 : : }
82 : : }
83 : :
84 : : public:
85 : 98 : ProgOpt( const std::string& longname_p, const std::string& shortname_p, int flags_p, OptType t = FLAG )
86 : : : shortname( shortname_p ), longname( longname_p ), type( t ), storage( NULL ), flags( flags_p ),
87 [ + - ][ + - ]: 98 : cancel_opt( NULL )
88 : : {
89 : 98 : }
90 : :
91 : : friend class ProgOptions;
92 : : };
93 : :
94 : 25 : ProgOptions::ProgOptions( const std::string& helpstring, const std::string& briefhelp )
95 [ + - ][ + - ]: 25 : : expect_optional_args( false ), optional_args_position( 0 ), max_optional_args( 0 )
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
96 : : {
97 [ + - ]: 25 : brief_help = briefhelp;
98 [ + + ][ + - ]: 25 : if( !helpstring.empty() ) main_help.push_back( helpstring );
99 [ + - ][ + - ]: 25 : addOpt< void >( "help,h", "Show full help text", help_flag );
[ + - ]
100 : 25 : }
101 : :
102 : 50 : ProgOptions::~ProgOptions()
103 : : {
104 [ + + ]: 104 : for( std::vector< help_line >::iterator i = option_help_strings.begin(); i != option_help_strings.end(); ++i )
105 : : {
106 [ + - ][ + - ]: 79 : if( ( *i ).first ) { delete( *i ).first; }
107 : : }
108 : :
109 [ + + ]: 44 : for( std::vector< help_line >::iterator i = arg_help_strings.begin(); i != arg_help_strings.end(); ++i )
110 : : {
111 [ + - ]: 19 : delete( *i ).first;
112 : : }
113 : 25 : }
114 : :
115 : 109 : void ProgOptions::get_namestrings( const std::string& namestring, std::string* longname, std::string* shortname )
116 : : {
117 : 109 : *shortname = "";
118 : 109 : *longname = namestring;
119 : :
120 : 109 : size_t idx = namestring.find_first_of( ',' );
121 [ + + ]: 109 : if( idx != namestring.npos )
122 : : {
123 [ + - ]: 96 : *longname = namestring.substr( 0, idx );
124 [ + - ]: 96 : *shortname = namestring.substr( idx + 1, namestring.npos );
125 : : }
126 : 109 : }
127 : :
128 : 0 : void ProgOptions::setVersion( const std::string& version_string, bool addFlag )
129 : : {
130 : 0 : progversion = version_string;
131 [ # # ][ # # ]: 0 : if( addFlag ) { addOpt< void >( "version", "Print version number and exit", version_flag ); }
[ # # ][ # # ]
132 : 0 : }
133 : :
134 : : template < typename T >
135 : 76 : void ProgOptions::addOpt( const std::string& namestring, const std::string& helpstring, T* value, int flags )
136 : : {
137 : :
138 [ + - ][ + - ]: 152 : std::string shortname, longname;
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
139 [ + - ][ + - ]: 76 : get_namestrings( namestring, &longname, &shortname );
[ + - ][ + - ]
[ + - ]
140 : :
141 [ - + ][ - + ]: 76 : if( flags & int_flag )
[ - + ][ - + ]
[ - + ]
142 : : { // short name is implicit for this flag
143 [ # # ][ # # ]: 0 : if( !shortname.empty() ) error( "Requested short name with int_flag option" );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
144 [ # # ][ # # ]: 0 : if( get_opt_type< T >() != INT ) error( "Requested int_flag for non-integer option" );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
145 [ # # ][ # # ]: 0 : if( !number_option_name.empty() ) error( "Requested int_flag for multiple options" );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
146 [ # # ][ # # ]: 0 : number_option_name = longname;
[ # # ][ # # ]
[ # # ]
147 : : }
148 : :
149 [ + - ][ + - ]: 76 : ProgOpt* opt = new ProgOpt( longname, shortname, flags, get_opt_type< T >() );
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
150 [ + - ][ + + ]: 76 : if( value ) opt->storage = value;
[ + - ][ + - ]
[ + + ]
151 : :
152 [ + - ][ + - ]: 76 : if( longname.length() ) long_names[longname] = opt;
[ + + ][ + - ]
[ + + ][ + - ]
[ + + ][ + - ]
[ + + ][ + - ]
153 [ + - ][ + - ]: 76 : if( shortname.length() ) short_names[shortname] = opt;
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + + ][ + - ]
154 : :
155 [ + - ][ + - ]: 152 : help_line help = std::make_pair( opt, helpstring );
[ + - ][ + - ]
[ + - ]
156 [ + - ][ + - ]: 76 : option_help_strings.push_back( help );
[ + - ][ + - ]
[ + - ]
157 : :
158 [ - + ][ - + ]: 76 : if( flags & add_cancel_opt )
[ - + ][ - + ]
[ + + ]
159 : : {
160 [ # # ][ # # ]: 3 : std::string flag = "no-" + ( longname.length() ? longname : shortname );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ + - ][ + - ]
161 [ # # ][ # # ]: 3 : ProgOpt* cancel_opt = new ProgOpt( flag, "", flags ^ ProgOptions::store_false, FLAG );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ + - ][ + - ]
[ + - ]
162 [ # # ][ # # ]: 3 : if( value ) cancel_opt->storage = value;
[ # # ][ # # ]
[ + - ]
163 : :
164 : 3 : cancel_opt->cancel_opt = opt;
165 [ # # ][ # # ]: 3 : long_names[flag] = cancel_opt;
[ # # ][ # # ]
[ + - ]
166 [ # # ][ # # ]: 6 : std::string clear_helpstring = "Clear previous " + flag.substr( 3, flag.npos ) + " flag";
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ + - ][ + - ]
[ + - ]
167 [ # # ][ # # ]: 3 : help = std::make_pair( cancel_opt, clear_helpstring );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ + - ][ + - ]
168 [ # # # # : 6 : option_help_strings.push_back( help );
# # # # +
- ]
169 : 76 : }
170 : 76 : }
171 : :
172 : : template < typename T >
173 : 19 : void ProgOptions::addRequiredArg( const std::string& helpname, const std::string& helpstring, T* value, int flags )
174 : : {
175 : :
176 : 19 : OptType type = get_opt_type< T >();
177 : :
178 [ + - ][ + - ]: 19 : ProgOpt* opt = new ProgOpt( helpname, "", flags, type );
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
179 [ + - ][ + + ]: 19 : if( value ) opt->storage = value;
[ + + ][ + + ]
180 [ + - ][ + - ]: 19 : help_line help = std::make_pair( opt, helpstring );
[ + - ][ + - ]
181 [ + - ][ + - ]: 19 : arg_help_strings.push_back( help );
[ + - ][ + - ]
182 [ + - ][ + - ]: 19 : required_args[helpname] = opt;
[ + - ][ + - ]
183 : 19 : }
184 : :
185 : : template < typename T >
186 : 4 : void ProgOptions::addOptionalArgs( unsigned max_count, const std::string& helpname, const std::string& helpstring,
187 : : int flags )
188 : : {
189 : : // If there was a previous one, we need to remove it
190 : : // because there can be only one. If we didn't remove
191 : : // the old one then it would be treated as a required arg.
192 [ # # ][ - + ]: 4 : if( expect_optional_args )
[ # # ][ # # ]
193 : : {
194 [ # # ][ # # ]: 0 : std::map< std::string, ProgOpt* >::iterator iter;
[ # # ][ # # ]
195 [ # # ][ # # ]: 0 : iter = required_args.find( arg_help_strings[optional_args_position].second );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
196 [ # # ][ # # ]: 0 : assert( iter != required_args.end() );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
197 [ # # ][ # # ]: 0 : delete iter->second;
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
198 [ # # ][ # # ]: 0 : required_args.erase( iter );
[ # # ][ # # ]
199 [ # # ][ # # ]: 0 : arg_help_strings.erase( arg_help_strings.begin() + optional_args_position );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
200 : : }
201 : :
202 : 4 : expect_optional_args = true;
203 : 4 : optional_args_position = arg_help_strings.size();
204 : 4 : max_optional_args = max_count;
205 : 4 : addRequiredArg< T >( helpname, helpstring, 0, flags );
206 : 4 : }
207 : :
208 : 0 : void ProgOptions::addOptionHelpHeading( const std::string& s )
209 : : {
210 [ # # ][ # # ]: 0 : option_help_strings.push_back( std::make_pair( (ProgOpt*)NULL, s ) );
211 : 0 : }
212 : :
213 : 0 : void ProgOptions::printVersion( std::ostream& out )
214 : : {
215 : 0 : out << progversion << std::endl;
216 : 0 : }
217 : :
218 : 0 : void ProgOptions::printHelp( std::ostream& out )
219 : : {
220 : :
221 : : /* Print introductory help text */
222 [ # # ][ # # ]: 0 : if( !brief_help.empty() ) out << brief_help << std::endl;
[ # # ]
223 [ # # ][ # # ]: 0 : for( std::vector< std::string >::iterator i = main_help.begin(); i != main_help.end(); ++i )
[ # # ]
224 : : {
225 [ # # ][ # # ]: 0 : if( ( *i ).length() ) { out << std::endl << *i << std::endl; }
[ # # ][ # # ]
[ # # ][ # # ]
226 : : }
227 : :
228 [ # # ]: 0 : printUsage( out );
229 : :
230 : : // max number of characters to pad argument/option names with
231 : : // options with long names may exceed this, but will appear out of alignment in help text
232 : 0 : const int max_padding = 20;
233 : :
234 : : /* List required arguments, with help text */
235 [ # # ]: 0 : if( arg_help_strings.size() > 0 )
236 : : {
237 : :
238 : 0 : int max_arg_namelen = 0;
239 : :
240 [ # # ][ # # ]: 0 : for( std::vector< help_line >::iterator i = arg_help_strings.begin(); i != arg_help_strings.end(); ++i )
[ # # ]
241 : : {
242 [ # # ][ # # ]: 0 : max_arg_namelen = std::max( max_arg_namelen, (int)( ( *i ).first->longname.length() ) );
243 : : }
244 : :
245 [ # # ]: 0 : max_arg_namelen = std::min( max_arg_namelen + 3, max_padding );
246 : :
247 [ # # ][ # # ]: 0 : out << "Arguments: " << std::endl;
248 : :
249 [ # # ][ # # ]: 0 : for( std::vector< help_line >::iterator i = arg_help_strings.begin(); i != arg_help_strings.end(); ++i )
[ # # ]
250 : : {
251 [ # # ]: 0 : ProgOpt* option = ( *i ).first;
252 [ # # ]: 0 : std::string& info = ( *i ).second;
253 : :
254 [ # # ][ # # ]: 0 : std::stringstream s;
255 [ # # ][ # # ]: 0 : s << " " << option->longname;
256 [ # # ][ # # ]: 0 : out << std::setw( max_arg_namelen ) << std::left << s.str();
[ # # ][ # # ]
[ # # ]
257 [ # # ][ # # ]: 0 : out << ": " << info << std::endl;
[ # # ]
258 : 0 : }
259 : : }
260 : :
261 : : /* List options, with help text */
262 [ # # ][ # # ]: 0 : out << "Options: " << std::endl;
263 : 0 : int max_option_prefix_len = 0;
264 : :
265 [ # # ][ # # ]: 0 : for( std::vector< help_line >::iterator i = option_help_strings.begin(); i != option_help_strings.end(); ++i )
[ # # ]
266 : : {
267 [ # # ]: 0 : ProgOpt* option = ( *i ).first;
268 [ # # ]: 0 : std::string& info = ( *i ).second;
269 : :
270 [ # # ]: 0 : if( option )
271 : : {
272 : :
273 [ # # ]: 0 : if( max_option_prefix_len == 0 )
274 : : {
275 : : // iterate ahead in the option list to determine whitespace padding
276 : : // stop if (*j).first is NULL, which indicates a help header message
277 [ # # ][ # # ]: 0 : for( std::vector< help_line >::iterator j = i; j != option_help_strings.end() && ( *j ).first; ++j )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
278 : : {
279 [ # # ][ # # ]: 0 : int len = get_option_usage_prefix( *( ( *j ).first ) ).length();
280 [ # # ]: 0 : max_option_prefix_len = std::max( max_option_prefix_len, len );
281 : : }
282 : : }
283 [ # # ]: 0 : max_option_prefix_len = std::min( max_option_prefix_len, max_padding );
284 [ # # ]: 0 : std::string option_prefix = get_option_usage_prefix( *option );
285 : :
286 [ # # ][ # # ]: 0 : out << std::setw( max_option_prefix_len ) << std::left << option_prefix;
[ # # ][ # # ]
287 [ # # ]: 0 : out << ": ";
288 : : }
289 : : else
290 : : {
291 : : // no option: this is a help header. Reset max name length.
292 : 0 : max_option_prefix_len = 0;
293 : : }
294 [ # # ][ # # ]: 0 : out << info << std::endl;
295 : : }
296 : 0 : }
297 : :
298 : 0 : std::string ProgOptions::get_option_usage_prefix( const ProgOpt& option )
299 : : {
300 : 0 : bool has_shortname = option.shortname.length() > 0;
301 : 0 : bool has_longname = option.longname.length() > 0;
302 [ # # ][ # # ]: 0 : std::string argstr = option.get_argstring();
303 : :
304 [ # # ][ # # ]: 0 : std::stringstream s;
305 [ # # ]: 0 : s << " ";
306 [ # # ]: 0 : if( has_shortname )
307 : : {
308 : :
309 [ # # ][ # # ]: 0 : s << "-" << option.shortname;
310 [ # # ][ # # ]: 0 : if( has_longname ) { s << " "; }
311 : : }
312 [ # # ]: 0 : else if( option.flags & int_flag )
313 : : {
314 : :
315 [ # # ]: 0 : s << "-<n>";
316 [ # # ][ # # ]: 0 : if( has_longname ) { s << " "; }
317 : : }
318 [ # # ]: 0 : if( has_longname )
319 : : {
320 : :
321 [ # # ][ # # ]: 0 : if( has_shortname ) s << "[";
322 [ # # ][ # # ]: 0 : s << "--" << option.longname;
323 [ # # ][ # # ]: 0 : if( has_shortname ) s << "]";
324 : : }
325 : :
326 [ # # ][ # # ]: 0 : if( argstr.length() ) s << " <" << argstr << ">";
[ # # ][ # # ]
327 [ # # ]: 0 : return s.str();
328 : : }
329 : :
330 : 0 : void ProgOptions::printUsage( std::ostream& out )
331 : : {
332 : :
333 : 0 : out << "Usage: " << progname << " --help | [options] ";
334 : :
335 [ # # ]: 0 : for( size_t i = 0; i < arg_help_strings.size(); ++i )
336 : : {
337 [ # # ][ # # ]: 0 : if( !expect_optional_args || i != optional_args_position )
338 : 0 : out << '<' << arg_help_strings[i].first->longname << "> ";
339 [ # # ][ # # ]: 0 : else if( 0 == max_optional_args || max_optional_args > 3 )
340 : 0 : out << "[<" << arg_help_strings[i].first->longname << "> ...] ";
341 [ # # ]: 0 : else if( 1 == max_optional_args )
342 : 0 : out << "[" << arg_help_strings[i].first->longname << "] ";
343 : : else
344 [ # # ]: 0 : for( unsigned j = 0; j < max_optional_args; ++j )
345 : 0 : out << "[" << arg_help_strings[i].first->longname << ( j + 1 ) << "] ";
346 : : }
347 : :
348 : 0 : out << std::endl;
349 : 0 : }
350 : :
351 : 97 : ProgOpt* ProgOptions::lookup( const std::map< std::string, ProgOpt* >& table, const std::string& arg )
352 : : {
353 [ + - ]: 97 : std::map< std::string, ProgOpt* >::const_iterator it = table.find( arg );
354 [ + - ][ + + ]: 97 : if( it != table.end() )
355 [ + - ]: 80 : return it->second;
356 [ - + ][ # # ]: 34 : else if( &table == &short_names && arg.size() == 1 && isdigit( arg[0] ) && !number_option_name.empty() &&
[ # # ][ # # ]
[ # # ][ # # ]
[ - + ]
357 [ # # ][ # # ]: 17 : ( it = long_names.find( number_option_name ) ) != long_names.end() )
[ # # ][ # # ]
[ - + ][ - + ]
[ - + ][ + - ]
[ # # # #
# # # # ]
358 [ # # ]: 0 : return it->second;
359 : : else
360 : 97 : return 0;
361 : : }
362 : :
363 : 22 : ProgOpt* ProgOptions::lookup_option( const std::string& namestring )
364 : : {
365 [ + - ][ + - ]: 44 : std::string longname, shortname;
366 [ + - ]: 22 : get_namestrings( namestring, &longname, &shortname );
367 : :
368 [ + - ]: 22 : ProgOpt* opt = lookup( long_names, longname );
369 [ + + ][ + - ]: 22 : if( !opt ) opt = lookup( short_names, shortname );
370 : :
371 [ - + ][ # # ]: 22 : if( !opt ) { error( "Invalid option: " + namestring ); }
[ # # ]
372 : :
373 : 22 : return opt;
374 : : }
375 : :
376 : 0 : void ProgOptions::error( const std::string& err )
377 : : {
378 : 0 : std::cerr << "Error: " << err << "\n" << std::endl;
379 : : ;
380 : 0 : printUsage( std::cerr );
381 : 0 : std::cerr << std::endl;
382 [ # # ]: 0 : if( getenv( "MOAB_PROG_OPT_ABORT" ) ) abort();
383 : 0 : std::exit( EXIT_FAILURE );
384 : : }
385 : :
386 : : // Copied from convert.cpp
387 : : // Parse list of integer ranges
388 : : // e.g. 1,2,5-10,12
389 : 12 : static bool parse_int_list( const char* string, std::vector< int >& results )
390 : : {
391 : 12 : bool okay = true;
392 : 12 : char* mystr = strdup( string );
393 [ + + ]: 40 : for( const char* ptr = strtok( mystr, ", \t" ); ptr; ptr = strtok( 0, ", \t" ) )
394 : : {
395 : : char* endptr;
396 : 28 : long val = strtol( ptr, &endptr, 0 );
397 [ - + ]: 28 : if( endptr == ptr )
398 : : {
399 [ # # ][ # # ]: 0 : std::cerr << "Not an integer: \"" << ptr << '"' << std::endl;
[ # # ][ # # ]
400 : 0 : okay = false;
401 : 0 : break;
402 : : }
403 : :
404 : 28 : long val2 = val;
405 [ + + ]: 28 : if( *endptr == '-' )
406 : : {
407 : 9 : const char* sptr = endptr + 1;
408 : 9 : val2 = strtol( sptr, &endptr, 0 );
409 [ - + ]: 9 : if( endptr == sptr )
410 : : {
411 [ # # ][ # # ]: 0 : std::cerr << "Not an integer: \"" << sptr << '"' << std::endl;
[ # # ][ # # ]
412 : 0 : okay = false;
413 : 0 : break;
414 : : }
415 [ - + ]: 9 : if( val2 < val )
416 : : {
417 [ # # ][ # # ]: 0 : std::cerr << "Invalid id range: \"" << ptr << '"' << std::endl;
[ # # ][ # # ]
418 : 0 : okay = false;
419 : 9 : break;
420 : : }
421 : : }
422 : :
423 [ - + ]: 28 : if( *endptr )
424 : : {
425 : 0 : okay = false;
426 : 0 : break;
427 : : }
428 : :
429 [ + + ]: 82 : for( ; val <= val2; ++val )
430 [ + - ]: 54 : results.push_back( (int)val );
431 : : }
432 : :
433 : 12 : free( mystr );
434 : 12 : return okay;
435 : : }
436 : :
437 : : // Copied from convert.cpp
438 : : // Replace '%' with MPI rank iff compiled with MPI
439 : 7 : static std::string do_rank_subst( const std::string& s )
440 : : {
441 : : #ifndef MOAB_HAVE_MPI
442 : : return s;
443 : : #else
444 : : int rank, size;
445 [ + - ][ + - ]: 7 : if( MPI_SUCCESS != MPI_Comm_rank( MPI_COMM_WORLD, &rank ) || MPI_SUCCESS != MPI_Comm_size( MPI_COMM_WORLD, &size ) )
[ + - ][ - + ]
[ - + ]
446 [ # # ]: 0 : return s;
447 : 7 : int width = 1;
448 [ - + ]: 7 : while( size > 10 )
449 : : {
450 : 0 : size /= 10;
451 : 0 : width++;
452 : : }
453 : :
454 : 7 : size_t j = s.find( '%' );
455 [ - + ][ # # ]: 7 : if( j == std::string::npos ) return s;
456 : :
457 [ + - ]: 7 : std::ostringstream st;
458 [ + - ][ + - ]: 7 : st << std::setfill( '0' );
459 [ + - ][ + - ]: 7 : st << s.substr( 0, j );
460 [ + - ]: 7 : st << rank;
461 : :
462 : : size_t i;
463 [ - + ]: 7 : while( ( i = s.find( '%', j + 1 ) ) != std::string::npos )
464 : : {
465 [ # # ][ # # ]: 0 : st << s.substr( j, i - j );
466 [ # # ][ # # ]: 0 : st << std::setw( width ) << rank;
[ # # ]
467 : 0 : j = i;
468 : : }
469 [ + - ][ + - ]: 7 : st << s.substr( j + 1 );
470 [ + - ]: 7 : return st.str();
471 : : #endif
472 : : }
473 : :
474 : : /**
475 : : * Check the input to a given option for correctness, converting it to its expected type (e.g. int)
476 : : * and storing the result to target, if target is non-NULL.
477 : : * @param option Used only in error messages to state which option could not be successfully
478 : : * converted
479 : : * @param arg_idx If non-NULL, evaluate the (*arg_idx)'th item in opt's args list
480 : : */
481 : 82 : bool ProgOptions::evaluate( const ProgOpt& opt, void* target, const std::string& option, unsigned* arg_idx )
482 : : {
483 : :
484 [ + + ]: 82 : unsigned idx = arg_idx ? *arg_idx : opt.args.size() - 1;
485 : :
486 [ - + + + : 82 : switch( opt.type )
+ - ]
487 : : {
488 : : case FLAG:
489 [ # # ][ # # ]: 0 : error( "Cannot evaluate a flag" );
490 : 0 : break;
491 : : case INT: {
492 : : int temp;
493 [ + + ]: 14 : int* i = target ? reinterpret_cast< int* >( target ) : &temp;
494 [ - + ][ # # ]: 14 : if( opt.args.size() < 1 ) { error( "Missing argument to " + option + " option" ); }
[ # # ][ # # ]
495 [ + - ]: 14 : const char* arg = opt.args.at( idx ).c_str();
496 : : char* p;
497 : 14 : *i = std::strtol( arg, &p, 0 );
498 [ - + ][ # # ]: 14 : if( *p != '\0' ) { error( "Bad integer argument '" + opt.args.at( idx ) + "' to " + option + " option." ); }
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
499 : 14 : return true;
500 : : }
501 : : case REAL: {
502 : : double temp;
503 [ + + ]: 14 : double* i = target ? reinterpret_cast< double* >( target ) : &temp;
504 [ - + ][ # # ]: 14 : if( opt.args.size() < 1 ) { error( "Missing argument to " + option + " option" ); }
[ # # ][ # # ]
505 [ + - ]: 14 : const char* arg = opt.args.at( idx ).c_str();
506 : : char* p;
507 : 14 : *i = std::strtod( arg, &p );
508 [ - + ][ # # ]: 14 : if( *p != '\0' ) { error( "Bad real argument '" + opt.args.at( idx ) + "' to " + option + " option." ); }
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
509 : 14 : return true;
510 : : }
511 : :
512 : : case STRING: {
513 [ + - ]: 42 : std::string temp;
514 [ + + ]: 42 : std::string* i = target ? reinterpret_cast< std::string* >( target ) : &temp;
515 [ - + ][ # # ]: 42 : if( opt.args.size() < 1 ) { error( "Missing argument to " + option + " option" ); }
[ # # ][ # # ]
516 [ + + ]: 42 : if( opt.flags & rank_subst )
517 [ + - ][ + - ]: 7 : *i = do_rank_subst( opt.args.at( idx ) );
[ + - ]
518 : : else
519 [ + - ][ + - ]: 35 : *i = opt.args.at( idx );
520 : 42 : return true;
521 : : }
522 : :
523 : : case INT_VECT: {
524 [ + - ]: 12 : std::vector< int > temp;
525 [ - + ]: 12 : std::vector< int >* i = target ? reinterpret_cast< std::vector< int >* >( target ) : &temp;
526 [ + - ][ + - ]: 12 : if( !parse_int_list( opt.args.at( idx ).c_str(), *i ) )
[ - + ]
527 [ # # ][ # # ]: 0 : error( "Bad integer list '" + opt.args.at( idx ) + "' to " + option + " option." );
[ # # ][ # # ]
[ # # ][ # # ]
528 : 12 : return true;
529 : : }
530 : : }
531 : :
532 : 82 : return false;
533 : : }
534 : :
535 : : template < typename T >
536 : 15 : bool ProgOptions::getOpt( const std::string& namestring, T* t )
537 : : {
538 : :
539 : 15 : ProgOpt* opt = lookup_option( namestring );
540 : :
541 [ - + ][ # # ]: 15 : if( get_opt_type< T >() != opt->type ) { error( "Option '" + namestring + "' looked up with incompatible type" ); }
[ # # ][ - + ]
[ # # ][ # # ]
[ - + ][ # # ]
[ # # ][ - + ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
542 : :
543 : : // This call to evaluate is inefficient, because opt was already evaluated when it was parsed.
544 [ + - ][ + - ]: 15 : if( opt->args.size() )
[ + - ][ + - ]
[ # # ]
545 : : {
546 [ + - ][ + - ]: 15 : if( t ) evaluate( *opt, t, "" );
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ # # ][ # # ]
[ # # ]
547 : 15 : return true;
548 : : }
549 : : else
550 : 15 : return false;
551 : : }
552 : :
553 : : template < typename T >
554 : 7 : void ProgOptions::getOptAllArgs( const std::string& namestring, std::vector< T >& values )
555 : : {
556 : 7 : ProgOpt* opt = lookup_option( namestring );
557 : :
558 : : // special case: if user asks for list of int, but argument
559 : : // was INT_VECT, concatenate all lists
560 [ - + ][ # # ]: 7 : if( get_opt_type< T >() == INT && opt->type == INT_VECT )
[ - + - + ]
[ # # ]
[ - + - + ]
[ # # ]
[ - + + - ]
[ + + ][ + + ]
561 : : {
562 [ # # ][ # # ]: 4 : for( unsigned i = 0; i < opt->args.size(); ++i )
[ # # ][ + + ]
563 [ # # ][ # # ]: 3 : evaluate( *opt, &values, "", &i );
[ # # ][ # # ]
[ # # ][ # # ]
[ + - ][ + - ]
564 : 7 : return;
565 : : }
566 : :
567 [ - + ][ # # ]: 6 : if( get_opt_type< T >() != opt->type ) { error( "Option '" + namestring + "' looked up with incompatible type" ); }
[ # # ][ - + ]
[ # # ][ # # ]
[ - + ][ # # ]
[ # # ][ - + ]
[ # # ][ # # ]
568 : :
569 : 6 : values.resize( opt->args.size() );
570 : :
571 : : // These calls to evaluate are inefficient, because the arguments were evaluated when they were
572 : : // parsed
573 [ + + ][ + + ]: 21 : for( unsigned i = 0; i < opt->args.size(); ++i )
[ + + ][ + + ]
574 : : {
575 [ + - ][ + - ]: 15 : evaluate( *opt, &( values[i] ), "", &i );
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
576 : : }
577 : : }
578 : :
579 : 11 : int ProgOptions::numOptSet( const std::string& namestring )
580 : : {
581 [ + - ][ + - ]: 22 : std::string longname, shortname;
582 [ + - ]: 11 : get_namestrings( namestring, &longname, &shortname );
583 : :
584 [ + - ]: 11 : ProgOpt* opt = lookup( long_names, longname );
585 [ + + ][ + - ]: 11 : if( !opt ) opt = lookup( short_names, shortname );
586 : :
587 [ - + ][ # # ]: 11 : if( !opt ) { error( "Could not look up option: " + namestring ); }
[ # # ]
588 : :
589 : 22 : return opt->args.size();
590 : : }
591 : :
592 : : template < typename T >
593 : 9 : T ProgOptions::getReqArg( const std::string& namestring )
594 : : {
595 : :
596 [ + - ][ + - ]: 9 : ProgOpt* opt = lookup( required_args, namestring );
597 : :
598 [ - + ][ # # ]: 9 : if( !opt ) { error( "Could not look up required arg: " + namestring ); }
[ - + ][ # # ]
[ - + ][ # # ]
[ # # ][ - + ]
[ # # ][ # # ]
599 : :
600 : : // if parseProgramOptions succeeded, we can assume each required arg has a value,
601 : : // so calling evaluate is valid
602 : 5 : T value;
603 [ + - ][ + - ]: 9 : evaluate( *opt, &value, "" );
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
604 : 9 : return value;
605 : : }
606 : :
607 : : template < typename T >
608 : 4 : void ProgOptions::getArgs( const std::string& namestring, std::vector< T >& values )
609 : : {
610 : 4 : ProgOpt* opt = lookup( required_args, namestring );
611 : :
612 [ # # ][ # # ]: 4 : if( !opt ) { error( "Could not look up required arg: " + namestring ); }
[ - + ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
613 : :
614 [ # # ][ # # ]: 4 : if( get_opt_type< T >() != opt->type ) { error( "Option '" + namestring + "' looked up with incompatible type" ); }
[ # # ][ - + ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
615 : :
616 : 4 : values.resize( opt->args.size() );
617 : :
618 : : // These calls to evaluate are inefficient, because the arguments were evaluated when they were
619 : : // parsed
620 [ # # ][ + + ]: 7 : for( unsigned i = 0; i < opt->args.size(); ++i )
[ # # ][ # # ]
621 : : {
622 [ # # ][ # # ]: 3 : evaluate( *opt, &( values[i] ), "", &i );
[ # # ][ + - ]
[ + - ][ + - ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
623 : : }
624 : 4 : }
625 : :
626 : : // Process parsed option.
627 : : // Returns true if value is still expected
628 : : // Should never return true if optional value is passed
629 : : // \param arg Used for error messages only
630 : 34 : bool ProgOptions::process_option( ProgOpt* opt, std::string arg, const char* value )
631 : : {
632 [ - + ]: 34 : if( !opt )
633 : : {
634 [ # # ]: 0 : if( arg == "--manpage" )
635 : : {
636 : 0 : write_man_page( std::cout );
637 : 0 : exit( 0 );
638 : : }
639 : :
640 [ # # ]: 0 : error( "Unknown option: " + arg );
641 : : }
642 : :
643 [ - + ]: 34 : if( opt->flags & help_flag )
644 : : {
645 : 0 : printHelp( std::cout );
646 : 0 : exit( EXIT_SUCCESS );
647 : : }
648 : :
649 [ - + ]: 34 : if( opt->flags & version_flag )
650 : : {
651 : 0 : printVersion( std::cout );
652 : 0 : exit( EXIT_SUCCESS );
653 : : }
654 : :
655 [ + + ]: 34 : if( opt->type != FLAG )
656 : : {
657 [ + + ]: 19 : if( !value ) return true;
658 : :
659 [ + - ][ + - ]: 5 : opt->args.push_back( value );
660 : 5 : evaluate( *opt, opt->storage, arg );
661 : : }
662 : : else
663 : : {
664 [ - + ][ # # ]: 15 : if( value ) { error( "Unexpected value for flag: " + arg ); }
665 : :
666 : : // do flag operations
667 [ + + ]: 15 : if( opt->cancel_opt ) { opt->cancel_opt->args.clear(); }
668 [ + - ]: 15 : if( opt->storage ) { *static_cast< bool* >( opt->storage ) = ( opt->flags & store_false ) ? false : true; }
669 [ + - ][ + - ]: 15 : opt->args.push_back( "" );
670 : : }
671 : :
672 : 34 : return false;
673 : : }
674 : :
675 : 25 : void ProgOptions::parseCommandLine( int argc, char* argv[] )
676 : : {
677 : 25 : const char* name = strrchr( argv[0], '/' );
678 [ + + ]: 25 : if( name )
679 [ + - ]: 4 : this->progname = ++name;
680 : : else
681 [ + - ]: 21 : this->progname = argv[0];
682 : :
683 [ + - ]: 25 : std::vector< const char* > args;
684 [ + - ]: 50 : std::list< ProgOpt* > expected_vals;
685 : 25 : bool no_more_flags = false;
686 : :
687 : : // Loop over all command line arguments
688 [ + + ]: 88 : for( int i = 1; i < argc; ++i )
689 : : {
690 [ + - ]: 63 : std::string arg( argv[i] );
691 [ - + ]: 63 : if( arg.empty() ) continue;
692 : :
693 [ + + ]: 63 : if( !expected_vals.empty() )
694 : : {
695 [ + - ]: 14 : ProgOpt* opt = expected_vals.front();
696 [ + - ]: 14 : expected_vals.pop_front();
697 [ - + ]: 14 : assert( opt->type != FLAG );
698 [ + - ]: 14 : opt->args.push_back( arg );
699 [ + - ]: 14 : evaluate( *opt, opt->storage, arg );
700 : : }
701 [ + + ][ + - ]: 49 : else if( !no_more_flags && arg[0] == '-' )
[ + + ][ + + ]
702 : : {
703 [ + + ][ + - ]: 31 : if( arg.length() > 2 && arg[1] == '-' )
[ + + ][ + + ]
704 : : { // long opt
705 : 17 : size_t eq = arg.find_first_of( '=' );
706 [ + + ]: 17 : if( eq != std::string::npos )
707 : : {
708 [ + - ][ + - ]: 5 : ProgOpt* opt = lookup( long_names, arg.substr( 2, eq - 2 ) );
709 [ + - ][ + - ]: 5 : process_option( opt, arg, arg.substr( eq + 1 ).c_str() );
[ + - ]
710 : : }
711 : : else
712 : : {
713 [ + - ][ + - ]: 12 : ProgOpt* opt = lookup( long_names, arg.substr( 2 ) );
714 [ + - ][ + - ]: 17 : if( process_option( opt, arg ) ) expected_vals.push_back( opt );
[ + + ][ + - ]
715 : : }
716 : : }
717 [ + - ][ + + ]: 14 : else if( arg == "--" )
718 : : { // --
719 : 2 : no_more_flags = true;
720 : : }
721 : : else
722 [ + + ]: 48 : for( size_t f = 1; f < arg.length(); ++f )
723 : : { // for each short opt
724 [ + - ][ + - ]: 17 : ProgOpt* opt = lookup( short_names, std::string( 1, arg[f] ) );
[ + - ]
725 [ + - ][ - + ]: 17 : if( opt && ( opt->flags & int_flag ) )
726 : : {
727 [ # # ]: 0 : const char val[] = { arg[f], 0 };
728 [ # # ][ # # ]: 0 : process_option( opt, std::string( 1, arg[f] ), val );
[ # # ]
729 : : }
730 [ + - ][ + - ]: 17 : else if( process_option( opt, std::string( 1, arg[f] ) ) )
[ + - ][ + + ]
731 [ + - ]: 10 : expected_vals.push_back( opt );
732 : : }
733 : : }
734 : : else
735 : : {
736 : : /* arguments */
737 [ + - ][ + - ]: 63 : args.push_back( argv[i] );
738 : : }
739 : 63 : } /* End loop over inputs */
740 : :
741 : : // Print error if any missing values
742 [ - + ]: 25 : if( !expected_vals.empty() )
743 : : {
744 [ # # ][ # # ]: 0 : error( "Missing value for option: -" + expected_vals.front()->shortname + ",--" +
[ # # ][ # # ]
745 [ # # ][ # # ]: 0 : expected_vals.front()->longname );
746 : : }
747 : :
748 : : // Process non-option arguments
749 : 25 : std::vector< help_line >::iterator arg_help_pos = arg_help_strings.begin();
750 : 25 : std::vector< const char* >::iterator arg_val_pos = args.begin();
751 : 25 : std::vector< help_line >::iterator opt_args_pos = arg_help_strings.end();
752 : 25 : size_t min_required_args = required_args.size();
753 : 25 : size_t max_required_args = required_args.size();
754 [ + + ]: 25 : if( expect_optional_args )
755 : : {
756 : 4 : min_required_args--;
757 [ + + ]: 4 : if( max_optional_args )
758 : 2 : max_required_args += max_optional_args;
759 : : else
760 : 2 : max_required_args = std::numeric_limits< int >::max();
761 [ + - ]: 4 : opt_args_pos = arg_help_pos + optional_args_position;
762 : : }
763 : : // check valid number of non-flag arguments
764 [ - + ]: 25 : if( args.size() < min_required_args )
765 : : {
766 : 0 : size_t missing_pos = args.size();
767 [ # # ][ # # ]: 0 : if( expect_optional_args && missing_pos >= optional_args_position ) ++missing_pos;
768 : :
769 [ # # ]: 0 : const std::string& missed_arg = arg_help_strings[missing_pos].first->longname;
770 [ # # ][ # # ]: 0 : error( "Did not find required positional argument: " + missed_arg );
771 : : }
772 [ - + ]: 25 : else if( args.size() > max_required_args )
773 : : {
774 [ # # ][ # # ]: 0 : error( "Unexpected argument: " + std::string( args[max_required_args] ) );
[ # # ][ # # ]
775 : : }
776 : :
777 : : // proccess arguments up to the first optional argument
778 : : // (or all arguments if no optional args)
779 [ + - ][ + + ]: 36 : while( arg_help_pos != opt_args_pos )
780 : : {
781 [ + - ]: 11 : ProgOpt* opt = arg_help_pos->first;
782 [ + - ]: 11 : ++arg_help_pos;
783 [ + - ][ + - ]: 11 : opt->args.push_back( *arg_val_pos );
[ + - ]
784 [ + - ][ + - ]: 11 : evaluate( *opt, opt->storage, *arg_val_pos );
[ + - ]
785 [ + - ]: 11 : ++arg_val_pos;
786 : : }
787 : : // process any optional args
788 [ + - ][ + + ]: 25 : if( arg_help_pos != arg_help_strings.end() )
789 : : {
790 [ + - ][ - + ]: 4 : assert( arg_help_pos == opt_args_pos );
791 : 4 : size_t num_opt_args = args.size() + 1 - required_args.size();
792 [ + - ]: 4 : ProgOpt* opt = arg_help_pos->first;
793 [ + - ]: 4 : ++arg_help_pos;
794 [ + + ]: 7 : while( num_opt_args-- )
795 : : {
796 [ + - ][ + - ]: 3 : opt->args.push_back( *arg_val_pos );
[ + - ]
797 [ + - ][ + - ]: 3 : evaluate( *opt, opt->storage, *arg_val_pos );
[ + - ]
798 [ + - ]: 3 : ++arg_val_pos;
799 : : }
800 : : }
801 : : // process any remaining args
802 [ + - ][ + + ]: 29 : while( arg_help_pos != arg_help_strings.end() )
803 : : {
804 [ + - ][ - + ]: 4 : assert( arg_val_pos != args.end() );
805 [ + - ]: 4 : ProgOpt* opt = arg_help_pos->first;
806 [ + - ]: 4 : ++arg_help_pos;
807 [ + - ][ + - ]: 4 : opt->args.push_back( *arg_val_pos );
[ + - ]
808 [ + - ][ + - ]: 4 : evaluate( *opt, opt->storage, *arg_val_pos );
[ + - ]
809 [ + - ]: 4 : ++arg_val_pos;
810 : : }
811 [ + - ][ - + ]: 50 : assert( arg_val_pos == args.end() );
812 : 25 : }
813 : :
814 : 0 : void ProgOptions::write_man_page( std::ostream& s )
815 : : {
816 : : // a leading '.' is a control character. strip it if present.
817 [ # # ]: 0 : std::string lprogname;
818 [ # # ][ # # ]: 0 : if( progname.empty() || progname[0] != '.' )
[ # # ][ # # ]
819 [ # # ]: 0 : lprogname = progname;
820 : : else
821 : : {
822 [ # # ][ # # ]: 0 : lprogname = progname.substr( 1 );
823 : : }
824 : :
825 : : // Manpage controls:
826 : : // .TH title
827 : : // .SH section
828 : : // .SS subsection
829 : : // .P paragraph
830 : : // .HP hanging paragraph
831 : : // .B bold
832 : : // .I italic
833 : : // .B bold
834 : : // .I italic
835 : : // .RS begin indent
836 : : // .RE end indent
837 : : // .RB alternating roman and blold
838 : : // .BR alternating bold and roman
839 : :
840 : 0 : std::vector< help_line >::iterator it;
841 [ # # ]: 0 : std::set< ProgOpt* > skip_list;
842 : :
843 : : // start man page
844 [ # # ][ # # ]: 0 : s << std::endl << ".TH " << lprogname << " 1" << std::endl;
[ # # ][ # # ]
[ # # ]
845 : :
846 : : // write NAME section
847 [ # # ][ # # ]: 0 : s << std::endl << ".SH NAME" << std::endl << ".P " << std::endl << lprogname << " \\- ";
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
848 [ # # ][ # # ]: 0 : if( brief_help.empty() && !main_help.empty() )
[ # # ]
849 [ # # ][ # # ]: 0 : s << main_help.front();
850 : : else
851 [ # # ]: 0 : s << brief_help;
852 [ # # ][ # # ]: 0 : s << std::endl << std::endl;
853 : :
854 : : // write SYNOPSIS section
855 [ # # ][ # # ]: 0 : s << std::endl << ".SH SYNOPSIS" << std::endl << ".HP" << std::endl << ".B \"" << lprogname << '"' << std::endl;
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
856 [ # # ][ # # ]: 0 : for( it = option_help_strings.begin(); it != option_help_strings.end(); ++it )
[ # # ]
857 : : {
858 [ # # ][ # # ]: 0 : if( !it->first || skip_list.find( it->first ) != skip_list.end() || it->first->longname == "help" ) continue;
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # # # ]
859 : :
860 [ # # ][ # # ]: 0 : if( it->first->type == FLAG )
861 : : {
862 : 0 : char c = '[';
863 [ # # ]: 0 : s << ".RB";
864 [ # # ][ # # ]: 0 : if( !it->first->shortname.empty() )
865 : : {
866 [ # # ][ # # ]: 0 : s << ' ' << c << " \"-" << it->first->shortname << '"';
[ # # ][ # # ]
[ # # ][ # # ]
867 : 0 : c = '|';
868 : : }
869 [ # # ][ # # ]: 0 : if( !it->first->longname.empty() ) { s << ' ' << c << " \"--" << it->first->longname << '"'; }
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
870 [ # # ][ # # ]: 0 : if( it->first->cancel_opt )
871 : : {
872 [ # # ][ # # ]: 0 : skip_list.insert( it->first->cancel_opt );
873 [ # # ][ # # ]: 0 : if( !it->first->cancel_opt->shortname.empty() )
874 [ # # ][ # # ]: 0 : s << " | \"-" << it->first->cancel_opt->shortname << '"';
[ # # ][ # # ]
875 [ # # ][ # # ]: 0 : if( !it->first->cancel_opt->longname.empty() ) s << " | \"--" << it->first->cancel_opt->longname << '"';
[ # # ][ # # ]
[ # # ][ # # ]
876 : : }
877 [ # # ][ # # ]: 0 : s << " ]" << std::endl;
878 : : }
879 [ # # ][ # # ]: 0 : else if( it->first->flags & int_flag )
880 : : {
881 [ # # ][ # # ]: 0 : s << ".RB [ - <n>| \"--" << it->first->longname << "\" \"=" << it->first->get_argstring() << "]\""
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
882 [ # # ]: 0 : << std::endl;
883 : : }
884 : : else
885 : : {
886 [ # # ]: 0 : s << ".RB [ ";
887 [ # # ][ # # ]: 0 : if( !it->first->shortname.empty() )
888 [ # # ][ # # ]: 0 : s << "\"-" << it->first->shortname << "\" \"\\ " << it->first->get_argstring();
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
889 [ # # ][ # # ]: 0 : if( !it->first->shortname.empty() && !it->first->longname.empty() ) s << "|\" ";
[ # # ][ # # ]
[ # # ][ # # ]
890 [ # # ][ # # ]: 0 : if( !it->first->longname.empty() )
891 [ # # ][ # # ]: 0 : s << "\"--" << it->first->longname << "\" \"=" << it->first->get_argstring();
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
892 [ # # ][ # # ]: 0 : s << "]\"" << std::endl;
893 : : }
894 : : }
895 [ # # ][ # # ]: 0 : for( it = arg_help_strings.begin(); it != arg_help_strings.end(); ++it )
[ # # ]
896 : : {
897 [ # # ][ # # ]: 0 : if( !it->first ) continue;
898 : :
899 [ # # ][ # # ]: 0 : if( !expect_optional_args || (unsigned)( it - arg_help_strings.begin() ) != optional_args_position )
[ # # ][ # # ]
[ # # # # ]
900 [ # # ][ # # ]: 0 : s << it->first->longname << ' ';
[ # # ]
901 [ # # ]: 0 : else if( 1 == max_optional_args )
902 [ # # ][ # # ]: 0 : s << '[' << it->first->longname << "] ";
[ # # ][ # # ]
903 : : else
904 [ # # ][ # # ]: 0 : s << '[' << it->first->longname << " ...] ";
[ # # ][ # # ]
905 : : }
906 [ # # ]: 0 : s << std::endl;
907 [ # # ][ # # ]: 0 : s << ".HP" << std::endl << ".B \"" << lprogname << " -h|--help\"" << std::endl;
[ # # ][ # # ]
[ # # ][ # # ]
908 : :
909 : : // write DESCRIPTION section
910 [ # # ][ # # ]: 0 : s << std::endl << ".SH DESCRIPTION" << std::endl;
[ # # ]
911 [ # # ][ # # ]: 0 : if( main_help.empty() ) s << brief_help << std::endl;
[ # # ]
912 [ # # ]: 0 : for( size_t i = 0; i < main_help.size(); ++i )
913 : : {
914 [ # # ]: 0 : const std::string::size_type n = main_help[i].size();
915 : 0 : std::string::size_type j = 0, k;
916 [ # # ][ # # ]: 0 : s << std::endl << ".P" << std::endl;
[ # # ]
917 [ # # ]: 0 : while( j != n )
918 : : {
919 [ # # ][ # # ]: 0 : if( main_help[i][j] == '\n' )
[ # # ]
920 : : {
921 [ # # ][ # # ]: 0 : s << std::endl << ".P" << std::endl;
[ # # ]
922 : 0 : ++j;
923 : 0 : continue;
924 : : }
925 [ # # ][ # # ]: 0 : k = main_help[i].find( "\n", j );
926 [ # # ]: 0 : if( k == std::string::npos ) k = n;
927 [ # # ][ # # ]: 0 : if( main_help[i][j] == '.' ) s << '\\';
[ # # ][ # # ]
928 [ # # ][ # # ]: 0 : s << main_help[i].substr( j, k - j );
[ # # ]
929 : 0 : j = k;
930 : : }
931 : : }
932 : :
933 : : // write OPTIONS section
934 [ # # ][ # # ]: 0 : s << std::endl << ".SH OPTIONS" << std::endl;
[ # # ]
935 [ # # ][ # # ]: 0 : for( it = arg_help_strings.begin(); it != arg_help_strings.end(); ++it )
[ # # ]
936 : : {
937 [ # # ][ # # ]: 0 : if( it->first )
938 [ # # ][ # # ]: 0 : s << ".IP \"" << it->first->longname << '"' << std::endl << it->second << std::endl;
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
939 : : else
940 [ # # ][ # # ]: 0 : s << ".SS " << it->first->longname << std::endl;
[ # # ][ # # ]
941 : : }
942 [ # # ][ # # ]: 0 : for( it = option_help_strings.begin(); it != option_help_strings.end(); ++it )
[ # # ]
943 : : {
944 [ # # ][ # # ]: 0 : if( !it->first )
945 : : {
946 [ # # ][ # # ]: 0 : s << ".SS " << it->second << std::endl;
[ # # ][ # # ]
947 : 0 : continue;
948 : : }
949 : :
950 [ # # ]: 0 : s << ".IP \"";
951 [ # # ][ # # ]: 0 : if( it->first->longname.empty() )
952 [ # # ][ # # ]: 0 : s << "-" << it->first->shortname;
[ # # ]
953 [ # # ][ # # ]: 0 : else if( it->first->shortname.empty() )
954 [ # # ][ # # ]: 0 : s << "--" << it->first->longname;
[ # # ]
955 : : else
956 [ # # ][ # # ]: 0 : s << "-" << it->first->shortname << ", --" << it->first->longname;
[ # # ][ # # ]
[ # # ][ # # ]
957 [ # # ][ # # ]: 0 : s << '"' << std::endl << it->second << std::endl;
[ # # ][ # # ]
[ # # ]
958 : : }
959 [ # # ]: 0 : s << std::endl;
960 : 0 : }
961 : :
962 : : /* Ensure g++ instantiates the template types we expect to use */
963 : :
964 : : #define DECLARE_OPTION_TYPE( T ) \
965 : : template void ProgOptions::addOpt< T >( const std::string&, const std::string&, T*, int ); \
966 : : template bool ProgOptions::getOpt< T >( const std::string&, T* );
967 : :
968 : : #define DECLARE_VALUED_OPTION_TYPE( T ) \
969 : : DECLARE_OPTION_TYPE( T ) \
970 : : template void ProgOptions::getOptAllArgs< T >( const std::string&, std::vector< T >& ); \
971 : : template void ProgOptions::addRequiredArg< T >( const std::string&, const std::string&, T*, int ); \
972 : : template void ProgOptions::addOptionalArgs< T >( unsigned, const std::string&, const std::string&, int ); \
973 : : template T ProgOptions::getReqArg< T >( const std::string& ); \
974 : : template void ProgOptions::getArgs< T >( const std::string&, std::vector< T >& );
975 : :
976 : : DECLARE_OPTION_TYPE( void )
977 : : DECLARE_VALUED_OPTION_TYPE( int )
978 : : DECLARE_VALUED_OPTION_TYPE( double )
979 : : DECLARE_VALUED_OPTION_TYPE( std::string )
980 [ + - ][ + - ]: 20 : DECLARE_VALUED_OPTION_TYPE( std::vector< int > )
|