98a377822a76a3116cf9cef65675bf3254ecfc38
1 /******************************************************************************
5 * $Date: 2007/06/15 12:46:04 $
8 * $Log: configuration_manager.cpp,v $
9 * Revision 2.2 2007/06/15 12:46:04 hachti
10 * Some small changes in configuration_manager output - added (c/f) info.
11 * Changed order in tool.hh:add_unique....
13 * Revision 2.1 2007-03-26 04:05:37 hachti
14 * *** empty log message ***
16 * Revision 2.0 2007-03-26 01:00:38 hachti
17 * *** empty log message ***
20 ******************************************************************************/
22 #include "configuration_manager.hh"
27 #define MAX_LINE_LENGTH 80
32 * This constructor makes a new configuration_manager ready to use.
33 *\arg name Name of the application as mentioned in the
34 * "Use: <appname> ..." help message.
36 configuration_manager::configuration_manager(string name
){
42 *\brief Add a new configuration value to be searched for.
43 *\param shortname A character for the short form.
44 * For example the o in -o
45 *\param longname The double dash longname. For example
46 * output_file in --output_file=
47 *\param description A detailed description of the value.
48 *\param status Pointer to an integer. Will be set to 1 if arg found.
49 *\param target Pointer to string to put the value in.
50 *\param placeholder A placeholder for the documentation.
51 * For example <filename> in -f<filename>
52 *\param allow_cmdline Specifies if this value may be specified on the
54 *\param allow_conffile Specifies if this value may be specified in a
58 void configuration_manager::add_option_value (const string
& shortname
,
59 const string
& longname
,
60 const string
& description
,
63 const string
& placeholder
,
64 const bool & allow_cmdline
,
65 const bool & allow_conffile
68 if(status
!=NULL
) if (target
!=NULL
)
69 option_values
.insert(option_values
.end(),
70 opt_value_t(shortname
,
85 *\brief Add a new configuration switch to be searched for.
86 *\param shortname A character for the short form.
87 * For example the h in -h
88 *\param longname The double dash longname. For example
90 *\param description A detailed description of the value.
91 *\param status Pointer to an integer. Will be set to 1 if arg found.
92 *\param allow_cmdline Specifies whether the switch is acceptable on the
94 *\param allow_conffile Specifies whether the switch is acceptable
95 * in a configuration file.
97 void configuration_manager::add_option_switch (const string
& shortname
,
98 const string
& longname
,
99 const string
& description
,
101 const bool & allow_cmdline
,
102 const bool & allow_conffile
106 option_switches
.insert(option_switches
.end(),
107 opt_switch_t(shortname
,
117 *\brief Add an accepted argument to the argument reader.
118 *\param placeholder Something like "<input-file>".
119 *\param description Text describing the argument.
120 *\param status A pointer to a status variable. Will be set to 0 by default.
121 * If the argument is filled in, it will be set to 1.
122 *\param target A pointer to a c++ string where the argument goes to.
124 *\note Arguments are filled in the order of adding them to the
126 * There would be no other way to determine the order.
128 void configuration_manager::add_argument(const string
& description
,
131 const string
& placeholder
){
135 if (target
!=NULL
) if(status
!=NULL
)
136 cmd_args
.insert(cmd_args
.end(),cmd_arg_t(placeholder
,
144 *\brief Read in the args passed to main().
145 *\returns empty vector on success or the error messages to be output.
147 vector
<string
> configuration_manager::read_args(int argc
, char ** args
){
149 vector
<string
> messages
;
152 // First we make a C++ string vector out of the **argv.
153 for (char ** akt
=args
+1; *akt
;akt
++) argv
.insert(argv
.end(),string(*akt
));
155 // Counter for the free command line parameters.
156 unsigned int free_parms_count
=0;
158 // Loop through the command line arguments
159 for (unsigned int arg_no
=0;arg_no
<argv
.size();arg_no
++){
163 // Look for long parameters.
164 // if ((argv[arg_no].substr(0,2)=="--")&&(free_parms_count==0)){
165 if ((argv
[arg_no
].substr(0,2)=="--")){ // Changed for comfort.
166 argstring
=argv
[arg_no
].substr(2);
168 // Look for long switches.
169 for (unsigned int switch_no
=0;switch_no
<option_switches
.size();switch_no
++){
170 string switch_name
=option_switches
[switch_no
].longname
;
171 if (argstring
.compare(0,switch_name
.length(),switch_name
,0,switch_name
.length())==0){
172 string value
=analyse_string(argstring
);
173 bool result
=analyse_bool(value
);
174 if(option_switches
[switch_no
].allow_cmdline
==true){
175 *(option_switches
[switch_no
].status
)=result
;
177 messages
.insert(messages
.end(),"Switch \"--"
178 +option_switches
[switch_no
].longname
179 +"\" is not allowed on the command line!");
186 // Look for long values.
187 for (unsigned int value_no
=0;value_no
<option_values
.size();value_no
++){
188 string value_name
=option_values
[value_no
].longname
;
189 if (argstring
.compare(0,value_name
.length(),value_name
,0,value_name
.length())==0){
190 string value
=analyse_string(argstring
);
191 if(option_values
[value_no
].allow_cmdline
==true){
192 *(option_values
[value_no
].status
)=1;
193 *(option_values
[value_no
].target
)=value
;
195 messages
.insert(messages
.end(),"Option value \"--"
196 +option_values
[value_no
].longname
197 +"\" is not allowed on the command line!");
204 messages
.insert(messages
.begin(),"Unknown option: --"+argstring
+"!");
209 // Look for short parameters
210 // if ((argv[arg_no].substr(0,1)=="-")&&(free_parms_count==0)&&(!found)){ // Short parameters
211 if ((argv
[arg_no
].substr(0,1)=="-")&&(!found
)){ // Changed for comfort.
213 argstring
=argv
[arg_no
].substr(1); // Reassign, with one more character now
214 for (unsigned int pos
=0;pos
< argstring
.length();pos
++){
215 bool short_found
=false;
217 // First, find short switches
218 for (unsigned int switch_no
=0;switch_no
<option_switches
.size();switch_no
++){
219 string short_name
=option_switches
[switch_no
].shortname
;
220 if (short_name
.compare(0,short_name
.length(),argstring
,pos
,short_name
.length())==0){
221 if(option_switches
[switch_no
].allow_cmdline
==true){
222 *(option_switches
[switch_no
].status
)=1;
224 messages
.insert(messages
.end(),"Switch \"-"
225 +option_switches
[switch_no
].shortname
226 +"\" is not allowed on the command line!");
229 pos
+=short_name
.length()-1;
234 // Now, find short values
236 for (unsigned int value_no
=0;value_no
<option_values
.size();value_no
++){
237 string short_name
=option_values
[value_no
].shortname
;
239 if (short_name
.compare(0,short_name
.length(),argstring
,pos
,short_name
.length())==0){
240 if (pos
==argstring
.length()-1){ // Last character, where's the value?
241 if (arg_no
<argv
.size()-1){ // Take next complete argument as value!
242 *(option_values
[value_no
].status
)=1;
243 *(option_values
[value_no
].target
)=argv
[arg_no
+1];
244 arg_no
+=1; // Consume the next argument
246 } else { // No argument left!
247 messages
.insert(messages
.begin(),"Missing value for -"+short_name
+"!");
251 if(option_values
[value_no
].allow_cmdline
==true){
252 *(option_values
[value_no
].status
)=1;
253 *(option_values
[value_no
].target
)=argstring
.substr(pos
+1);
255 messages
.insert(messages
.end(),"Option value \"-"
256 +option_values
[value_no
].shortname
257 +"\" is not allowed on the command line!");
259 pos
=argstring
.length(); // Do not analyse other characters.
266 if (!short_found
) messages
.insert(messages
.begin(),"Unknown Option: -"+argstring
.substr(pos
,1)+"!");
270 if (!found
) { // Must be a free form parameter...
271 if (free_parms_count
<cmd_args
.size()){ // Space available
272 *(cmd_args
[free_parms_count
].target
)=argv
[arg_no
];
273 *(cmd_args
[free_parms_count
].status
)=1;
275 } else { // No more space for free form parameters!
276 messages
.insert(messages
.begin(),"Too many arguments!");
280 if (!messages
.empty()){
281 messages
.insert(messages
.begin(),"Error!");
282 messages
.insert(messages
.begin(),"");
289 *\brief Extract a value from a configuration file line or
290 * a command line argument
292 string
configuration_manager::analyse_string(const string
& line
){
294 unsigned int pos
=line
.find("=");
295 if (pos
!=string::npos
) result
=line
.substr(pos
+1);
300 *\brief Extract a boolean value out of a string, defaulting to true
302 * Used for commandline switches
304 bool configuration_manager::analyse_bool(const string
& data
){
305 if ((data
.find("false",0)!=string::npos
)||
306 (data
.find("0",0)!=string::npos
)||
307 (data
.find("no",0)!=string::npos
)) return false;
313 *\brief Extract a boolean value out of a string, defaulting to false
315 * Used for configuration file switches
317 bool configuration_manager::analyse_bool_false(const string
& data
){
318 if ((data
.find("true",0)!=string::npos
)||
319 (data
.find("1",0)!=string::npos
)||
320 (data
.find("yes",0)!=string::npos
)) return true;
326 *brief Read in and parse a configuration file.
327 *\arg file String containing the filename
328 *\return Empty Vector or Vector full of strings containing
329 * the error message(s).
331 vector
<string
> configuration_manager::read_file(string filename
){
332 vector
<string
>result
;
333 FILE * fp
=fopen(filename
.c_str(),"r");
335 result
.insert(result
.end(),"Could not open file: "+filename
);
338 while(fgets(buffer
,1000,fp
)){
339 if (buffer
[strlen(buffer
)-1]=='\n')// Cut trailing newline
340 buffer
[strlen(buffer
)-1]=0;
341 if (strlen (buffer
)){
342 char*l2
=buffer
+strspn(buffer
," \t");
345 unsigned int pos
=argstring
.find("=");
347 result
.insert(result
.end(),"In File "+filename
+": Line beginning with '='!");
352 // Look for long switches.
353 for (unsigned int switch_no
=0;switch_no
<option_switches
.size();switch_no
++){
354 string switch_name
=option_switches
[switch_no
].longname
;
355 if (argstring
.compare(0,switch_name
.length(),switch_name
,0,switch_name
.length())==0){
356 string value
=analyse_string(argstring
);
357 //result.insert(result.end(),"argstring:\""+argstring+"\"");
358 bool res
=analyse_bool_false(value
);
359 if(option_switches
[switch_no
].allow_conffile
==true){
360 *(option_switches
[switch_no
].status
)=res
;
362 result
.insert(result
.end(),"In File "+filename
+": Switch \""
363 +option_switches
[switch_no
].longname
364 +"\" is not allowed in config files!");
371 // Look for long values.
372 for (unsigned int value_no
=0;value_no
<option_values
.size();value_no
++){
373 string value_name
=option_values
[value_no
].longname
;
374 if (argstring
.compare(0,value_name
.length(),value_name
,0,value_name
.length())==0){
375 string value
=analyse_string(argstring
);
376 *(option_values
[value_no
].status
)=1;
378 if(option_values
[value_no
].allow_conffile
==true){
379 *(option_values
[value_no
].status
)=1;
380 *(option_values
[value_no
].target
)=value
;
382 result
.insert(result
.end(),"In File "+filename
+": Option value \""
383 +option_values
[value_no
].longname
384 +"\" is not allowed in config files!");
391 result
.insert(result
.end(),"In File "+filename
+": Unknown option: "+argstring
+"!");
398 } // fp==0 else branch
400 if (!result
.empty()){
401 result
.insert(result
.begin(),"Error!");
402 result
.insert(result
.begin(),"");
409 *\brief Generate help.
410 *\arg target Reference to a vector<string> to which lots of helpful
411 * strings are appended.
413 void configuration_manager::get_help(vector
<string
> & target
){
414 target
.insert(target
.end(),"");
415 string line
="Usage: "+app_name
;
417 for (vector
<opt_switch_t
>::iterator parm_p
=option_switches
.begin();parm_p
<option_switches
.end();parm_p
++){
418 string addstr
=" [-"+parm_p
->shortname
;
420 if (line
.length()+addstr
.length()>MAX_LINE_LENGTH
){
421 target
.insert(target
.end(),line
);
422 line
=string(7+app_name
.length(),' ');
427 for (vector
<opt_value_t
>::iterator parm_p
=option_values
.begin();parm_p
<option_values
.end();parm_p
++){
428 string addstr
=" [-"+parm_p
->shortname
;
429 addstr
+=parm_p
->placeholder
;
431 if (line
.length()+addstr
.length()>MAX_LINE_LENGTH
){
432 target
.insert(target
.end(),line
);
433 line
=string(7+app_name
.length(),' ');
438 for (vector
<cmd_arg_t
>::iterator parm_p
=cmd_args
.begin();parm_p
<cmd_args
.end();parm_p
++){
439 if (line
.length()+parm_p
->placeholder
.length()>MAX_LINE_LENGTH
){
440 target
.insert(target
.end(),line
);
441 line
=string(7+app_name
.length(),' ');
443 line
+=" ["+parm_p
->placeholder
+"]";
445 target
.insert(target
.end(),line
);
447 /* Here comes the documentation output. */
449 vector
<string
> left
,right
;
450 unsigned int max_width
;
452 /* Output switches? */
453 if (option_switches
.size()){
454 target
.insert(target
.end(),"");
455 target
.insert(target
.end(),"Switches:");
457 left
=vector
<string
>();
458 right
=vector
<string
>();
461 /* Now lets insert switches into left and right */
462 for (unsigned int sw
=0; sw
<option_switches
.size();sw
++){
463 opt_switch_t akt_sw
=option_switches
[sw
];
465 if (akt_sw
.allow_cmdline
) rline
+="c/";
467 if (akt_sw
.allow_conffile
) rline
+="f)";
469 rline
+=" "+akt_sw
.description
;
470 string lline
="-"+akt_sw
.shortname
+", --"+akt_sw
.longname
;
471 left
.insert(left
.end(),lline
);
472 right
.insert(right
.end(),rline
);
475 // Determine maximal width for left column
477 for (unsigned int c
=0; c
<left
.size();c
++)
478 if(left
[c
].length()>max_width
) max_width
=left
[c
].length();
480 /* output all the mess */
481 for (unsigned int c
=0; c
<left
.size();c
++){
482 string
nl(max_width
,' ');
483 nl
.replace(0,left
[c
].length(),left
[c
]);
485 while (nl
.length()>MAX_LINE_LENGTH
){ // Too long???
486 int limit
=nl
.find_last_of(' ',MAX_LINE_LENGTH
);
487 target
.insert(target
.end(),nl
.substr(0,limit
));
488 nl
=string(max_width
+2+6,' ')+nl
.substr(limit
+1);
490 target
.insert(target
.end(),nl
);
495 if (option_values
.size()){
496 target
.insert(target
.end(),"");
497 target
.insert(target
.end(),"Option values:");
499 left
=vector
<string
>();
500 right
=vector
<string
>();
503 for (unsigned int val
=0; val
<option_values
.size();val
++){
504 opt_value_t akt_val
=option_values
[val
];
506 if (akt_val
.allow_cmdline
) rline
+="c/";
508 if (akt_val
.allow_conffile
) rline
+="f)";
510 rline
+=" "+akt_val
.description
;
512 string lline
="-"+akt_val
.shortname
+akt_val
.placeholder
+", --"+
513 akt_val
.longname
+"="+akt_val
.placeholder
;
514 left
.insert(left
.end(),lline
);
515 right
.insert(right
.end(),rline
);
518 // Determine maximal width for left column
519 for (unsigned int c
=0; c
<left
.size();c
++)
520 if(left
[c
].length()>max_width
) max_width
=left
[c
].length();
521 /* output all the mess */
522 for (unsigned int c
=0; c
<left
.size();c
++){
523 string
nl(max_width
,' '); // Empty left side.
524 nl
.replace(0,left
[c
].length(),left
[c
]); // Print in left side.
525 nl
+=" "+right
[c
]; // Add right side.
527 while (nl
.length()>MAX_LINE_LENGTH
){ // Too long???
528 int limit
=nl
.find_last_of(' ',MAX_LINE_LENGTH
);
529 target
.insert(target
.end(),nl
.substr(0,limit
));
530 nl
=string(max_width
+2+6,' ')+nl
.substr(limit
+1);
532 target
.insert(target
.end(),nl
);
536 target
.insert(target
.end(),"");
537 target
.insert(target
.end(),"Legend (c/f):");
538 target
.insert(target
.end()," c: Allowed on command line.");
539 target
.insert(target
.end()," f: Allowed in configuration file.");
541 /* Output the Arguments */
542 if (cmd_args
.size()){
543 target
.insert(target
.end(),"");
544 target
.insert(target
.end(),"Arguments:");
546 left
=vector
<string
>();
547 right
=vector
<string
>();
550 for (unsigned int arg
=0; arg
<cmd_args
.size();arg
++){
551 cmd_arg_t akt_arg
=cmd_args
[arg
];
552 left
.insert(left
.end(),akt_arg
.placeholder
);
553 right
.insert(right
.end(),akt_arg
.description
);
556 // Determine maximal width for left column
558 for (unsigned int c
=0; c
<left
.size();c
++)
559 if(left
[c
].length()>max_width
) max_width
=left
[c
].length();
561 for (unsigned int c
=0; c
<left
.size();c
++){
562 string
nl(max_width
,' ');
563 nl
.replace(0,left
[c
].length(),left
[c
]);
565 while (nl
.length()>MAX_LINE_LENGTH
){ // Too long???
566 int limit
=nl
.find_last_of(' ',MAX_LINE_LENGTH
+1);
567 target
.insert(target
.end(),nl
.substr(0,limit
));
568 nl
=string(max_width
+2,' ')+nl
.substr(limit
+1);
570 target
.insert(target
.end(),nl
);
572 target
.insert(target
.end(),"");
577 *\brief Generate help.
578 *\return A vector containing many helpful strings for the user.
580 vector
<string
> configuration_manager::get_help(){
581 vector
<string
> result
;
587 /**************************************************/
590 configuration_manager::opt_value_t::opt_value_t(const string
& shortname
,
591 const string
& longname
,
592 const string
& description
,
595 const string
& placeholder
,
596 const bool & allow_conffile
,
597 const bool & allow_cmdline
599 this->shortname
=shortname
;
600 this->longname
=longname
;
601 this->description
=description
;
604 this->placeholder
=placeholder
;
605 this->allow_conffile
=allow_conffile
;
606 this->allow_cmdline
=allow_cmdline
;
607 if (status
) *status
=0;
611 configuration_manager::opt_switch_t::opt_switch_t(const string
& shortname
,
612 const string
& longname
,
613 const string
& description
,
615 const bool & allow_conffile
,
616 const bool & allow_cmdline
){
617 this->shortname
=shortname
;
618 this->longname
=longname
;
619 this->description
=description
;
622 this->placeholder
=placeholder
;
623 this->allow_conffile
=allow_conffile
;
624 this->allow_cmdline
=allow_cmdline
;
628 configuration_manager::cmd_arg_t::cmd_arg_t(const string
& placeholder
,
629 const string
& description
,
632 this->placeholder
=placeholder
;
633 this->description
=description
;