418beab22d3f4c69f7a2052d627621520cf9c836
[h316.git] / pc-tools / ldc2 / src / configuration_manager.cpp
1 #include "configuration_manager.hh"
2 #include <stdio.h>
3
4 #define MAX_LINE_LENGTH 80
5
6 /*!
7 *\brief Constructor.
8 *
9 * This constructor makes a new configuration_manager ready to use.
10 *\arg name Name of the application as mentioned in the
11 * "Use: <appname> ..." help message.
12 */
13 configuration_manager::configuration_manager(string name){
14 app_name=name;
15 }
16
17
18 /*!
19 *\brief Add a new configuration value to be searched for.
20 *\param shortname A character for the short form.
21 * For example the o in -o
22 *\param longname The double dash longname. For example
23 * output_file in --output_file=
24 *\param description A detailed description of the value.
25 *\param status Pointer to an integer. Will be set to 1 if arg found.
26 *\target Pointer to string to put the value in.
27 *\placeholder A placeholder for the documentation.
28 * For example <filename> in -f<filename>
29 */
30 void configuration_manager::add_option_value (const string & shortname,
31 const string & longname,
32 const string & description,
33 int * status,
34 string * target,
35 const string & placeholder,
36 const bool & allow_cmdline,
37 const bool & allow_conffile
38 ){
39
40 if(status!=NULL) if (target!=NULL)
41 option_values.insert(option_values.end(),
42 opt_value_t(shortname,
43 longname,
44 description,
45 status,
46 target,
47 placeholder,
48 allow_cmdline,
49 allow_conffile
50 )
51 );
52 }
53
54
55
56 /*!
57 *\brief Add a new configuration switch to be searched for.
58 *\param shortname A character for the short form.
59 * For example the h in -h
60 *\param longname The double dash longname. For example
61 * help in --help
62 *\param description A detailed description of the value.
63 *\param status Pointer to an integer. Will be set to 1 if arg found.
64 *\param allow_cmdline Specifies whether the switch is acceptable on the
65 * command line.
66 *\param allow_conffile Specifies whether the switch is acceptable
67 * in a configuration file.
68 */
69 void configuration_manager::add_option_switch (const string & shortname,
70 const string & longname,
71 const string & description,
72 int * status,
73 const bool & allow_cmdline,
74 const bool & allow_conffile
75 ){
76
77 if(status!=NULL)
78 option_switches.insert(option_switches.end(),
79 opt_switch_t(shortname,
80 longname,
81 description,
82 status,
83 allow_cmdline,
84 allow_conffile)
85 );
86 }
87
88 /*!
89 *\brief Add an accepted argument to the argument reader.
90 *\param placeholder Something like "<input-file>".
91 *\param description Text describing the argument.
92 *\param status A pointer to a status variable. Will be set to 0 by default.
93 * If the argument is filled in, it will be set to 1.
94 *\param target A pointer to a c++ string where the argument goes to.
95 *
96 *\note Arguments are filled in the order of adding them to the
97 * argument reader.
98 * There would be no other way to determine the order.
99 */
100 void configuration_manager::add_argument(const string & description,
101 int * status,
102 string * target,
103 const string & placeholder){
104
105
106
107 if (target!=NULL) if(status!=NULL)
108 cmd_args.insert(cmd_args.end(),cmd_arg_t(placeholder,
109 description,
110 status,
111 target));
112 }
113
114
115 /*!
116 *\Read in the args passed to main().
117 *\returns empty vector on success or the error messages to be output.
118 */
119 vector<string> configuration_manager::read_args(int argc, char ** args){
120
121 vector<string> messages;
122 vector<string> argv;
123
124 // First we make a C++ string vector out of the **argv.
125 for (char ** akt=args+1; *akt ;akt++) argv.insert(argv.end(),string(*akt));
126
127 // Counter for the free command line parameters.
128 unsigned int free_parms_count=0;
129
130 // Loop through the command line arguments
131 for (unsigned int arg_no=0;arg_no<argv.size();arg_no++){
132 bool found=false;
133 string argstring;
134
135 // Look for long parameters.
136 if ((argv[arg_no].substr(0,2)=="--")&&(free_parms_count==0)){
137 argstring=argv[arg_no].substr(2);
138
139 // Look for long switches.
140 for (unsigned int switch_no=0;switch_no<option_switches.size();switch_no++){
141 string switch_name=option_switches[switch_no].longname;
142 if (argstring.compare(0,switch_name.length(),switch_name,0,switch_name.length())==0){
143 string value=analyse_string(argstring);
144 bool result=analyse_bool(value);
145 *(option_switches[switch_no].status)=result;
146 found=true;
147 }
148 }
149
150 // Look for long values.
151 for (unsigned int value_no=0;value_no<option_values.size();value_no++){
152 string value_name=option_values[value_no].longname;
153 if (argstring.compare(0,value_name.length(),value_name,0,value_name.length())==0){
154 string value=analyse_string(argstring);
155 *(option_values[value_no].status)=1;
156 *(option_values[value_no].target)=value;
157 found=true;
158 }
159 }
160 if (! found) {
161 messages.insert(messages.begin(),"Unknown option: --"+argstring+"!");
162 found=true; // Oh!
163 }
164 }
165
166 // Look for short parameters
167 if ((argv[arg_no].substr(0,1)=="-")&&(free_parms_count==0)&&(!found)){ // Short parameters
168 found=true;
169 argstring=argv[arg_no].substr(1); // Reassign, with one more character now
170 for (unsigned int pos=0;pos < argstring.length();pos++){
171 bool short_found=false;
172
173 // First, find short switches
174 for (unsigned int switch_no=0;switch_no<option_switches.size();switch_no++){
175 string short_name=option_switches[switch_no].shortname;
176 if (short_name.compare(0,short_name.length(),argstring,pos,short_name.length())==0){
177 *(option_switches[switch_no].status)=1;
178 short_found=true;
179 pos+=short_name.length()-1;
180 }
181 }
182
183 // Now, find short values
184 if (!short_found){
185 for (unsigned int value_no=0;value_no<option_values.size();value_no++){
186 string short_name=option_values[value_no].shortname;
187
188 if (short_name.compare(0,short_name.length(),argstring,pos,short_name.length())==0){
189 if (pos==argstring.length()-1){ // Last character, where's the value?
190 if (arg_no<argv.size()-1){ // Take next complete argument as value!
191 *(option_values[value_no].status)=1;
192 *(option_values[value_no].target)=argv[arg_no+1];
193 arg_no+=1; // Consume the next argument
194 short_found=true;
195 } else { // No argument left!
196 messages.insert(messages.begin(),"Missing value for -"+short_name+"!");
197 short_found=true;
198 }
199 } else {
200 *(option_values[value_no].status)=1;
201 *(option_values[value_no].target)=argstring.substr(pos+1);
202 pos=argstring.length(); // Do not analyse other characters.
203 short_found=true;
204 }
205 }
206 }
207 }
208 if (!short_found) messages.insert(messages.begin(),"Unknown Option: -"+argstring.substr(pos,1)+"!");
209 }
210 }
211
212 if (!found) { // Must be a free form parameter...
213 if (free_parms_count<cmd_args.size()){ // Space available
214 *(cmd_args[free_parms_count].target)=argv[arg_no];
215 *(cmd_args[free_parms_count].status)=1;
216 free_parms_count++;
217 } else { // No more space for free form parameters!
218 messages.insert(messages.begin(),"Too many arguments!");
219 }
220 }
221 }
222 if (!messages.empty()){
223 messages.insert(messages.begin(),"Error!");
224 messages.insert(messages.begin(),"");
225 }
226 return messages;
227 }
228
229 /*!
230 *\brief Extract a value from a configuration file line or
231 * a command line argument
232 */
233 string configuration_manager::analyse_string(const string & line){
234 string result="";
235 unsigned int pos=line.find("=");
236 if (pos!=string::npos) result=line.substr(pos+1);
237 return result;
238 }
239
240 /*!
241 *\brief Extract a boolean value out of a string.
242 */
243 bool configuration_manager::analyse_bool(const string & data){
244 if ((data=="false")||(data=="0")||(data=="no")) return false;
245 return true;
246 }
247
248 /*!
249 *\brief Generate help.
250 *\arg target Reference to a vector<string> to which lots of helpful
251 * strings are appended.
252 */
253 void configuration_manager::get_help(vector<string> & target){
254 target.insert(target.end(),"");
255 string line="Usage: "+app_name;
256
257 for (vector<opt_switch_t>::iterator parm_p=option_switches.begin();parm_p<option_switches.end();parm_p++){
258 string addstr=" [-"+parm_p->shortname;
259 addstr+="]";
260 if (line.length()+addstr.length()>MAX_LINE_LENGTH){
261 target.insert(target.end(),line);
262 line=string(7+app_name.length(),' ');
263 }
264 line+=addstr;
265 }
266
267 for (vector<opt_value_t>::iterator parm_p=option_values.begin();parm_p<option_values.end();parm_p++){
268 string addstr=" [-"+parm_p->shortname;
269 addstr+=parm_p->placeholder;
270 addstr+="]";
271 if (line.length()+addstr.length()>MAX_LINE_LENGTH){
272 target.insert(target.end(),line);
273 line=string(7+app_name.length(),' ');
274 }
275 line+=addstr;
276 }
277
278 for (vector<cmd_arg_t>::iterator parm_p=cmd_args.begin();parm_p<cmd_args.end();parm_p++){
279 if (line.length()+parm_p->placeholder.length()>MAX_LINE_LENGTH){
280 target.insert(target.end(),line);
281 line=string(7+app_name.length(),' ');
282 }
283 line+=" ["+parm_p->placeholder+"]";
284 }
285 target.insert(target.end(),line);
286
287 /* Here comes the documentation output. */
288
289 vector<string> left,right;
290 unsigned int max_width;
291
292 /* Output switches? */
293 if (option_switches.size()){
294 target.insert(target.end(),"");
295 target.insert(target.end(),"Switches:");
296
297 left=vector<string>();
298 right=vector<string>();
299 max_width=0;
300
301 /* Now lets insert switches into left and right */
302 for (unsigned int sw=0; sw<option_switches.size();sw++){
303 opt_switch_t akt_sw=option_switches[sw];
304 string rline=akt_sw.description;
305 string lline="-"+akt_sw.shortname+", --"+akt_sw.longname;
306 left.insert(left.end(),lline);
307 right.insert(right.end(),rline);
308 }
309
310 // Determine maximal width for left column
311 max_width=0;
312 for (unsigned int c=0; c<left.size();c++)
313 if(left[c].length()>max_width) max_width=left[c].length();
314
315 /* output all the mess */
316 for (unsigned int c=0; c<left.size();c++){
317 string nl(max_width,' ');
318 nl.replace(0,left[c].length(),left[c]);
319 nl+=" "+right[c];
320 while (nl.length()>80){ // Too long???
321 int limit=nl.find_last_of(' ',MAX_LINE_LENGTH+1);
322 target.insert(target.end(),nl.substr(0,limit));
323 nl=string(max_width+2,' ')+nl.substr(limit+1);
324 }
325 target.insert(target.end(),nl);
326 }
327 }
328
329 // Output values
330 if (option_values.size()){
331 target.insert(target.end(),"");
332 target.insert(target.end(),"Option values:");
333
334 left=vector<string>();
335 right=vector<string>();
336 max_width=0;
337
338 for (unsigned int val=0; val<option_values.size();val++){
339 opt_value_t akt_val=option_values[val];
340 string rline=akt_val.description;
341 string lline=" -"+akt_val.shortname+akt_val.placeholder+", --"+
342 akt_val.longname+akt_val.placeholder;
343 left.insert(left.end(),lline);
344 right.insert(right.end(),rline);
345 }
346
347 // Determine maximal width for left column
348 for (unsigned int c=0; c<left.size();c++)
349 if(left[c].length()>max_width) max_width=left[c].length();
350 /* output all the mess */
351 for (unsigned int c=0; c<left.size();c++){
352 string nl(max_width,' ');
353 nl.replace(0,left[c].length(),left[c]);
354 nl+=" "+right[c];
355 while (nl.length()>80){ // Too long???
356 int limit=nl.find_last_of(' ',MAX_LINE_LENGTH+1);
357 target.insert(target.end(),nl.substr(0,limit));
358 nl=string(max_width+2,' ')+nl.substr(limit+1);
359 }
360 target.insert(target.end(),nl);
361 }
362 }
363
364 /* Output the Arguments */
365 if (cmd_args.size()){
366 target.insert(target.end(),"");
367 target.insert(target.end(),"Arguments:");
368
369 left=vector<string>();
370 right=vector<string>();
371 max_width=0;
372
373 for (unsigned int arg=0; arg<cmd_args.size();arg++){
374 cmd_arg_t akt_arg=cmd_args[arg];
375 left.insert(left.end(),akt_arg.placeholder);
376 right.insert(right.end(),akt_arg.description);
377 }
378
379 // Determine maximal width for left column
380 max_width=0;
381 for (unsigned int c=0; c<left.size();c++)
382 if(left[c].length()>max_width) max_width=left[c].length();
383
384 for (unsigned int c=0; c<left.size();c++){
385 string nl(max_width,' ');
386 nl.replace(0,left[c].length(),left[c]);
387 nl+=" "+right[c];
388 while (nl.length()>MAX_LINE_LENGTH){ // Too long???
389 int limit=nl.find_last_of(' ',MAX_LINE_LENGTH+1);
390 // printf("limit:%i\n",limit);
391 target.insert(target.end(),nl.substr(0,limit));
392 nl=string(max_width+2,' ')+nl.substr(limit+1);
393 }
394 target.insert(target.end(),nl);
395 }
396 target.insert(target.end(),"");
397 }
398 }
399
400 /*!
401 *\brief Generate help.
402 *\return A vector containing many helpful strings for the user.
403 */
404 vector<string> configuration_manager::get_help(){
405 vector<string> result;
406 get_help(result);
407 return result;
408 }
409
410
411 /**************************************************/
412
413
414 configuration_manager::opt_value_t::opt_value_t(const string & shortname,
415 const string & longname,
416 const string & description,
417 int * status,
418 string * target,
419 const string & placeholder,
420 const bool & allow_conffile,
421 const bool & allow_cmdline
422 ){
423 this->shortname=shortname;
424 this->longname=longname;
425 this->description=description;
426 this->status=status;
427 this->target=target;
428 this->placeholder=placeholder;
429 this->allow_conffile=allow_conffile;
430 this->allow_cmdline=allow_cmdline;
431 if (status) *status=0;
432 }
433
434
435 configuration_manager::opt_switch_t::opt_switch_t(const string & shortname,
436 const string & longname,
437 const string & description,
438 int * status,
439 const bool & allow_conffile,
440 const bool & allow_cmdline){
441 this->shortname=shortname;
442 this->longname=longname;
443 this->description=description;
444 this->status=status;
445 this->target=target;
446 this->placeholder=placeholder;
447 this->allow_conffile=allow_conffile;
448 this->allow_cmdline=allow_cmdline;
449 if (status) *status=0;
450 }
451
452
453 configuration_manager::cmd_arg_t::cmd_arg_t(const string & placeholder,
454 const string & description,
455 int * status,
456 string * target){
457 this->placeholder=placeholder;
458 this->description=description;
459 this->status=status;
460 this->target=target;
461 if (this->status) *(this->status)=0;
462 }