f21de674ca791c2e7f03b97f85a82d05b2a85e78
1 /******************************************************************************
5 * $Date: 2008/08/25 21:02:24 $
8 * $Log: configuration_manager.cpp,v $
9 * Revision 2.3 2008/08/25 21:02:24 hachti
10 * *** empty log message ***
12 * Revision 2.2 2007-06-15 12:46:04 hachti
13 * Some small changes in configuration_manager output - added (c/f) info.
14 * Changed order in tool.hh:add_unique....
16 * Revision 2.1 2007-03-26 04:05:37 hachti
17 * *** empty log message ***
19 * Revision 2.0 2007-03-26 01:00:38 hachti
20 * *** empty log message ***
23 ******************************************************************************/
25 #include "configuration_manager.hh"
31 #define MAX_LINE_LENGTH 80
36 * This constructor makes a new configuration_manager ready to use.
37 *\arg name Name of the application as mentioned in the
38 * "Use: <appname> ..." help message.
40 configuration_manager::configuration_manager(string name
){
46 *\brief Add a new configuration value to be searched for.
47 *\param shortname A character for the short form.
48 * For example the o in -o
49 *\param longname The double dash longname. For example
50 * output_file in --output_file=
51 *\param description A detailed description of the value.
52 *\param status Pointer to an integer. Will be set to 1 if arg found.
53 *\param target Pointer to string to put the value in.
54 *\param placeholder A placeholder for the documentation.
55 * For example <filename> in -f<filename>
56 *\param allow_cmdline Specifies if this value may be specified on the
58 *\param allow_conffile Specifies if this value may be specified in a
62 void configuration_manager::add_option_value (const string
& shortname
,
63 const string
& longname
,
64 const string
& description
,
67 const string
& placeholder
,
68 const bool & allow_cmdline
,
69 const bool & allow_conffile
72 if(status
!=NULL
) if (target
!=NULL
)
73 option_values
.insert(option_values
.end(),
74 opt_value_t(shortname
,
89 *\brief Add a new configuration switch to be searched for.
90 *\param shortname A character for the short form.
91 * For example the h in -h
92 *\param longname The double dash longname. For example
94 *\param description A detailed description of the value.
95 *\param status Pointer to an integer. Will be set to 1 if arg found.
96 *\param allow_cmdline Specifies whether the switch is acceptable on the
98 *\param allow_conffile Specifies whether the switch is acceptable
99 * in a configuration file.
101 void configuration_manager::add_option_switch (const string
& shortname
,
102 const string
& longname
,
103 const string
& description
,
105 const bool & allow_cmdline
,
106 const bool & allow_conffile
110 option_switches
.insert(option_switches
.end(),
111 opt_switch_t(shortname
,
121 *\brief Add an accepted argument to the argument reader.
122 *\param placeholder Something like "<input-file>".
123 *\param description Text describing the argument.
124 *\param status A pointer to a status variable. Will be set to 0 by default.
125 * If the argument is filled in, it will be set to 1.
126 *\param target A pointer to a c++ string where the argument goes to.
128 *\note Arguments are filled in the order of adding them to the
130 * There would be no other way to determine the order.
132 void configuration_manager::add_argument(const string
& description
,
135 const string
& placeholder
){
139 if (target
!=NULL
) if(status
!=NULL
)
140 cmd_args
.insert(cmd_args
.end(),cmd_arg_t(placeholder
,
148 *\brief Read in the args passed to main().
149 *\returns empty vector on success or the error messages to be output.
151 vector
<string
> configuration_manager::read_args(int argc
, char ** args
){
153 vector
<string
> messages
;
156 // First we make a C++ string vector out of the **argv.
157 for (char ** akt
=args
+1; *akt
;akt
++) argv
.insert(argv
.end(),string(*akt
));
159 // Counter for the free command line parameters.
160 unsigned int free_parms_count
=0;
162 // Loop through the command line arguments
163 for (unsigned int arg_no
=0;arg_no
<argv
.size();arg_no
++){
167 // Look for long parameters.
168 // if ((argv[arg_no].substr(0,2)=="--")&&(free_parms_count==0)){
169 if ((argv
[arg_no
].substr(0,2)=="--")){ // Changed for comfort.
170 argstring
=argv
[arg_no
].substr(2);
172 // Look for long switches.
173 for (unsigned int switch_no
=0;switch_no
<option_switches
.size();switch_no
++){
174 string switch_name
=option_switches
[switch_no
].longname
;
175 if (argstring
.compare(0,switch_name
.length(),switch_name
,0,switch_name
.length())==0){
176 string value
=analyse_string(argstring
);
177 bool result
=analyse_bool(value
);
178 if(option_switches
[switch_no
].allow_cmdline
==true){
179 *(option_switches
[switch_no
].status
)=result
;
181 messages
.insert(messages
.end(),"Switch \"--"
182 +option_switches
[switch_no
].longname
183 +"\" is not allowed on the command line!");
190 // Look for long values.
191 for (unsigned int value_no
=0;value_no
<option_values
.size();value_no
++){
192 string value_name
=option_values
[value_no
].longname
;
193 if (argstring
.compare(0,value_name
.length(),value_name
,0,value_name
.length())==0){
194 string value
=analyse_string(argstring
);
195 if(option_values
[value_no
].allow_cmdline
==true){
196 *(option_values
[value_no
].status
)=1;
197 *(option_values
[value_no
].target
)=value
;
199 messages
.insert(messages
.end(),"Option value \"--"
200 +option_values
[value_no
].longname
201 +"\" is not allowed on the command line!");
208 messages
.insert(messages
.begin(),"Unknown option: --"+argstring
+"!");
213 // Look for short parameters
214 // if ((argv[arg_no].substr(0,1)=="-")&&(free_parms_count==0)&&(!found)){ // Short parameters
215 if ((argv
[arg_no
].substr(0,1)=="-")&&(!found
)){ // Changed for comfort.
217 argstring
=argv
[arg_no
].substr(1); // Reassign, with one more character now
218 for (unsigned int pos
=0;pos
< argstring
.length();pos
++){
219 bool short_found
=false;
221 // First, find short switches
222 for (unsigned int switch_no
=0;switch_no
<option_switches
.size();switch_no
++){
223 string short_name
=option_switches
[switch_no
].shortname
;
224 if (short_name
.compare(0,short_name
.length(),argstring
,pos
,short_name
.length())==0){
225 if(option_switches
[switch_no
].allow_cmdline
==true){
226 *(option_switches
[switch_no
].status
)=1;
228 messages
.insert(messages
.end(),"Switch \"-"
229 +option_switches
[switch_no
].shortname
230 +"\" is not allowed on the command line!");
233 pos
+=short_name
.length()-1;
238 // Now, find short values
240 for (unsigned int value_no
=0;value_no
<option_values
.size();value_no
++){
241 string short_name
=option_values
[value_no
].shortname
;
243 if (short_name
.compare(0,short_name
.length(),argstring
,pos
,short_name
.length())==0){
244 if (pos
==argstring
.length()-1){ // Last character, where's the value?
245 if (arg_no
<argv
.size()-1){ // Take next complete argument as value!
246 *(option_values
[value_no
].status
)=1;
247 *(option_values
[value_no
].target
)=argv
[arg_no
+1];
248 arg_no
+=1; // Consume the next argument
250 } else { // No argument left!
251 messages
.insert(messages
.begin(),"Missing value for -"+short_name
+"!");
255 if(option_values
[value_no
].allow_cmdline
==true){
256 *(option_values
[value_no
].status
)=1;
257 *(option_values
[value_no
].target
)=argstring
.substr(pos
+1);
259 messages
.insert(messages
.end(),"Option value \"-"
260 +option_values
[value_no
].shortname
261 +"\" is not allowed on the command line!");
263 pos
=argstring
.length(); // Do not analyse other characters.
270 if (!short_found
) messages
.insert(messages
.begin(),"Unknown Option: -"+argstring
.substr(pos
,1)+"!");
274 if (!found
) { // Must be a free form parameter...
275 if (free_parms_count
<cmd_args
.size()){ // Space available
276 *(cmd_args
[free_parms_count
].target
)=argv
[arg_no
];
277 *(cmd_args
[free_parms_count
].status
)=1;
279 } else { // No more space for free form parameters!
280 messages
.insert(messages
.begin(),"Too many arguments!");
284 if (!messages
.empty()){
285 messages
.insert(messages
.begin(),"Error!");
286 messages
.insert(messages
.begin(),"");
293 *\brief Extract a value from a configuration file line or
294 * a command line argument
296 string
configuration_manager::analyse_string(const string
& line
){
298 unsigned int pos
=line
.find("=");
299 if (pos
!=string::npos
) result
=line
.substr(pos
+1);
304 *\brief Extract a boolean value out of a string, defaulting to true
306 * Used for commandline switches
308 bool configuration_manager::analyse_bool(const string
& data
){
309 if ((data
.find("false",0)!=string::npos
)||
310 (data
.find("0",0)!=string::npos
)||
311 (data
.find("no",0)!=string::npos
)) return false;
317 *\brief Extract a boolean value out of a string, defaulting to false
319 * Used for configuration file switches
321 bool configuration_manager::analyse_bool_false(const string
& data
){
322 if ((data
.find("true",0)!=string::npos
)||
323 (data
.find("1",0)!=string::npos
)||
324 (data
.find("yes",0)!=string::npos
)) return true;
330 *brief Read in and parse a configuration file.
331 *\arg file String containing the filename
332 *\return Empty Vector or Vector full of strings containing
333 * the error message(s).
335 vector
<string
> configuration_manager::read_file(string filename
){
336 vector
<string
>result
;
337 FILE * fp
=fopen(filename
.c_str(),"r");
339 result
.insert(result
.end(),"Could not open file: "+filename
);
342 while(fgets(buffer
,1000,fp
)){
343 if (buffer
[strlen(buffer
)-1]=='\n')// Cut trailing newline
344 buffer
[strlen(buffer
)-1]=0;
345 if (strlen (buffer
)){
346 char*l2
=buffer
+strspn(buffer
," \t");
349 unsigned int pos
=argstring
.find("=");
351 result
.insert(result
.end(),"In File "+filename
+": Line beginning with '='!");
356 // Look for long switches.
357 for (unsigned int switch_no
=0;switch_no
<option_switches
.size();switch_no
++){
358 string switch_name
=option_switches
[switch_no
].longname
;
359 if (argstring
.compare(0,switch_name
.length(),switch_name
,0,switch_name
.length())==0){
360 string value
=analyse_string(argstring
);
361 //result.insert(result.end(),"argstring:\""+argstring+"\"");
362 bool res
=analyse_bool_false(value
);
363 if(option_switches
[switch_no
].allow_conffile
==true){
364 *(option_switches
[switch_no
].status
)=res
;
366 result
.insert(result
.end(),"In File "+filename
+": Switch \""
367 +option_switches
[switch_no
].longname
368 +"\" is not allowed in config files!");
375 // Look for long values.
376 for (unsigned int value_no
=0;value_no
<option_values
.size();value_no
++){
377 string value_name
=option_values
[value_no
].longname
;
378 if (argstring
.compare(0,value_name
.length(),value_name
,0,value_name
.length())==0){
379 string value
=analyse_string(argstring
);
380 *(option_values
[value_no
].status
)=1;
382 if(option_values
[value_no
].allow_conffile
==true){
383 *(option_values
[value_no
].status
)=1;
384 *(option_values
[value_no
].target
)=value
;
386 result
.insert(result
.end(),"In File "+filename
+": Option value \""
387 +option_values
[value_no
].longname
388 +"\" is not allowed in config files!");
395 result
.insert(result
.end(),"In File "+filename
+": Unknown option: "+argstring
+"!");
402 } // fp==0 else branch
404 if (!result
.empty()){
405 result
.insert(result
.begin(),"Error!");
406 result
.insert(result
.begin(),"");
413 *\brief Generate help.
414 *\arg target Reference to a vector<string> to which lots of helpful
415 * strings are appended.
417 void configuration_manager::get_help(vector
<string
> & target
){
418 target
.insert(target
.end(),"");
419 string line
="Usage: "+app_name
;
421 for (vector
<opt_switch_t
>::iterator parm_p
=option_switches
.begin();parm_p
<option_switches
.end();parm_p
++){
422 string addstr
=" [-"+parm_p
->shortname
;
424 if (line
.length()+addstr
.length()>MAX_LINE_LENGTH
){
425 target
.insert(target
.end(),line
);
426 line
=string(7+app_name
.length(),' ');
431 for (vector
<opt_value_t
>::iterator parm_p
=option_values
.begin();parm_p
<option_values
.end();parm_p
++){
432 string addstr
=" [-"+parm_p
->shortname
;
433 addstr
+=parm_p
->placeholder
;
435 if (line
.length()+addstr
.length()>MAX_LINE_LENGTH
){
436 target
.insert(target
.end(),line
);
437 line
=string(7+app_name
.length(),' ');
442 for (vector
<cmd_arg_t
>::iterator parm_p
=cmd_args
.begin();parm_p
<cmd_args
.end();parm_p
++){
443 if (line
.length()+parm_p
->placeholder
.length()>MAX_LINE_LENGTH
){
444 target
.insert(target
.end(),line
);
445 line
=string(7+app_name
.length(),' ');
447 line
+=" ["+parm_p
->placeholder
+"]";
449 target
.insert(target
.end(),line
);
451 /* Here comes the documentation output. */
453 vector
<string
> left
,right
;
454 unsigned int max_width
;
456 /* Output switches? */
457 if (option_switches
.size()){
458 target
.insert(target
.end(),"");
459 target
.insert(target
.end(),"Switches:");
461 left
=vector
<string
>();
462 right
=vector
<string
>();
465 /* Now lets insert switches into left and right */
466 for (unsigned int sw
=0; sw
<option_switches
.size();sw
++){
467 opt_switch_t akt_sw
=option_switches
[sw
];
469 if (akt_sw
.allow_cmdline
) rline
+="c/";
471 if (akt_sw
.allow_conffile
) rline
+="f)";
473 rline
+=" "+akt_sw
.description
;
474 string lline
="-"+akt_sw
.shortname
+", --"+akt_sw
.longname
;
475 left
.insert(left
.end(),lline
);
476 right
.insert(right
.end(),rline
);
479 // Determine maximal width for left column
481 for (unsigned int c
=0; c
<left
.size();c
++)
482 if(left
[c
].length()>max_width
) max_width
=left
[c
].length();
484 /* output all the mess */
485 for (unsigned int c
=0; c
<left
.size();c
++){
486 string
nl(max_width
,' ');
487 nl
.replace(0,left
[c
].length(),left
[c
]);
489 while (nl
.length()>MAX_LINE_LENGTH
){ // Too long???
490 int limit
=nl
.find_last_of(' ',MAX_LINE_LENGTH
);
491 target
.insert(target
.end(),nl
.substr(0,limit
));
492 nl
=string(max_width
+2+6,' ')+nl
.substr(limit
+1);
494 target
.insert(target
.end(),nl
);
499 if (option_values
.size()){
500 target
.insert(target
.end(),"");
501 target
.insert(target
.end(),"Option values:");
503 left
=vector
<string
>();
504 right
=vector
<string
>();
507 for (unsigned int val
=0; val
<option_values
.size();val
++){
508 opt_value_t akt_val
=option_values
[val
];
510 if (akt_val
.allow_cmdline
) rline
+="c/";
512 if (akt_val
.allow_conffile
) rline
+="f)";
514 rline
+=" "+akt_val
.description
;
516 string lline
="-"+akt_val
.shortname
+akt_val
.placeholder
+", --"+
517 akt_val
.longname
+"="+akt_val
.placeholder
;
518 left
.insert(left
.end(),lline
);
519 right
.insert(right
.end(),rline
);
522 // Determine maximal width for left column
523 for (unsigned int c
=0; c
<left
.size();c
++)
524 if(left
[c
].length()>max_width
) max_width
=left
[c
].length();
525 /* output all the mess */
526 for (unsigned int c
=0; c
<left
.size();c
++){
527 string
nl(max_width
,' '); // Empty left side.
528 nl
.replace(0,left
[c
].length(),left
[c
]); // Print in left side.
529 nl
+=" "+right
[c
]; // Add right side.
531 while (nl
.length()>MAX_LINE_LENGTH
){ // Too long???
532 int limit
=nl
.find_last_of(' ',MAX_LINE_LENGTH
);
533 target
.insert(target
.end(),nl
.substr(0,limit
));
534 nl
=string(max_width
+2+6,' ')+nl
.substr(limit
+1);
536 target
.insert(target
.end(),nl
);
540 target
.insert(target
.end(),"");
541 target
.insert(target
.end(),"Legend (c/f):");
542 target
.insert(target
.end()," c: Allowed on command line.");
543 target
.insert(target
.end()," f: Allowed in configuration file.");
545 /* Output the Arguments */
546 if (cmd_args
.size()){
547 target
.insert(target
.end(),"");
548 target
.insert(target
.end(),"Arguments:");
550 left
=vector
<string
>();
551 right
=vector
<string
>();
554 for (unsigned int arg
=0; arg
<cmd_args
.size();arg
++){
555 cmd_arg_t akt_arg
=cmd_args
[arg
];
556 left
.insert(left
.end(),akt_arg
.placeholder
);
557 right
.insert(right
.end(),akt_arg
.description
);
560 // Determine maximal width for left column
562 for (unsigned int c
=0; c
<left
.size();c
++)
563 if(left
[c
].length()>max_width
) max_width
=left
[c
].length();
565 for (unsigned int c
=0; c
<left
.size();c
++){
566 string
nl(max_width
,' ');
567 nl
.replace(0,left
[c
].length(),left
[c
]);
569 while (nl
.length()>MAX_LINE_LENGTH
){ // Too long???
570 int limit
=nl
.find_last_of(' ',MAX_LINE_LENGTH
+1);
571 target
.insert(target
.end(),nl
.substr(0,limit
));
572 nl
=string(max_width
+2,' ')+nl
.substr(limit
+1);
574 target
.insert(target
.end(),nl
);
576 target
.insert(target
.end(),"");
581 *\brief Generate help.
582 *\return A vector containing many helpful strings for the user.
584 vector
<string
> configuration_manager::get_help(){
585 vector
<string
> result
;
591 /**************************************************/
594 configuration_manager::opt_value_t::opt_value_t(const string
& shortname
,
595 const string
& longname
,
596 const string
& description
,
599 const string
& placeholder
,
600 const bool & allow_conffile
,
601 const bool & allow_cmdline
603 this->shortname
=shortname
;
604 this->longname
=longname
;
605 this->description
=description
;
608 this->placeholder
=placeholder
;
609 this->allow_conffile
=allow_conffile
;
610 this->allow_cmdline
=allow_cmdline
;
611 if (status
) *status
=0;
615 configuration_manager::opt_switch_t::opt_switch_t(const string
& shortname
,
616 const string
& longname
,
617 const string
& description
,
619 const bool & allow_conffile
,
620 const bool & allow_cmdline
){
621 this->shortname
=shortname
;
622 this->longname
=longname
;
623 this->description
=description
;
626 this->placeholder
=placeholder
;
627 this->allow_conffile
=allow_conffile
;
628 this->allow_cmdline
=allow_cmdline
;
632 configuration_manager::cmd_arg_t::cmd_arg_t(const string
& placeholder
,
633 const string
& description
,
636 this->placeholder
=placeholder
;
637 this->description
=description
;