comparison defical-c/src/basic/Argument_helper.cpp @ 0:ebed2bd0d300

Initial import from svn. History be damned.
author Edho P. Arief <me@myconan.net>
date Fri, 02 Apr 2010 23:11:57 +0700
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:ebed2bd0d300
1 /*
2 *
3 * Argument Helper
4 *
5 * Daniel Russel drussel@alumni.princeton.edu
6 * Stanford University
7 *
8 *
9 * This software is not subject to copyright protection and is in the
10 * public domain. Neither Stanford nor the author assume any
11 * responsibility whatsoever for its use by other parties, and makes no
12 * guarantees, expressed or implied, about its quality, reliability, or
13 * any other characteristic.
14 *
15 */
16
17 #include "Argument_helper.h"
18
19
20 #include <iostream>
21 #include <cstdlib>
22 #include <cstdio>
23 //#include <limits>
24 #include <cassert>
25
26
27
28 namespace dsr {
29
30 bool verbose=false, VERBOSE=false;
31
32
33
34 // This is a base class for representing one argument value.
35 /*
36 This is inherited by many classes and which represent the different types.
37 */
38 class Argument_helper::Argument_target {
39 public:
40 char key;
41 std::string long_name;
42 std::string description;
43 std::string arg_description;
44
45 Argument_target(char k, const std::string lname,
46 const std::string descr,
47 const std::string arg_descr) {
48 key=k;
49 long_name=lname;
50 description=descr;
51 arg_description=arg_descr;
52 }
53 Argument_target(const std::string descr,
54 const std::string arg_descr) {
55 key=0;
56 long_name="";
57 description=descr;
58 arg_description=arg_descr;
59 }
60 virtual bool process(int &, const char **&)=0;
61 virtual void write_name(std::ostream &out) const;
62 virtual void write_value(std::ostream &out) const=0;
63 virtual void write_usage(std::ostream &out) const;
64 virtual ~Argument_target(){}
65 };
66
67 void Argument_helper::Argument_target::write_name(std::ostream &out) const {
68 if (key != 0) out << '-' << key;
69 else if (!long_name.empty()) out << "--" << long_name;
70 else out << arg_description;
71 }
72
73
74 void Argument_helper::Argument_target::write_usage(std::ostream &out) const {
75 if (key != 0) {
76 out << '-' << key;
77 out << "/--" << long_name;
78 }
79 out << ' ' << arg_description;
80 out << "\t" << description;
81 out << " Value: ";
82 write_value(out);
83 out << std::endl;
84 }
85
86 class Argument_helper::FlagTarget: public Argument_helper::Argument_target{
87 public:
88 bool &val;
89 FlagTarget(char k, const char *lname,
90 const char *descr,
91 bool &b): Argument_target(k, std::string(lname), std::string(descr),
92 std::string()), val(b){}
93 virtual bool process(int &, const char **&){
94 val= !val;
95 return true;
96 }
97 virtual void write_value(std::ostream &out) const {
98 out << val;
99 }
100
101 virtual void write_usage(std::ostream &out) const {
102 if (key != 0) {
103 out << '-' << key;
104 out << "/--" << long_name;
105 }
106 out << "\t" << description;
107 out << " Value: ";
108 write_value(out);
109 out << std::endl;
110 }
111 virtual ~FlagTarget(){}
112 };
113
114 class Argument_helper::DoubleTarget: public Argument_target{
115 public:
116 double &val;
117 DoubleTarget(char k, const char *lname,
118 const char *arg_descr,
119 const char *descr, double &b): Argument_target(k, std::string(lname),
120 std::string(descr),
121 std::string(arg_descr)), val(b){}
122 DoubleTarget(const char *arg_descr,
123 const char *descr, double &b): Argument_target(std::string(descr),
124 std::string(arg_descr)), val(b){}
125 virtual bool process(int &argc, const char **&argv){
126 if (argc==0){
127 std::cerr << "Missing value for argument." << std::endl;
128 return false;
129 }
130 if (my_sscanf(argv[0], "%le", &val) ==1){
131 --argc;
132 ++argv;
133 return true;
134 } else {
135 std::cerr << "Double not found at " << argv[0] << std::endl;
136 return false;
137 }
138 }
139 virtual void write_value(std::ostream &out) const {
140 out << val;
141 }
142 virtual ~DoubleTarget(){}
143 };
144
145 class Argument_helper::IntTarget: public Argument_target{
146 public:
147 int &val;
148 IntTarget(const char *arg_descr,
149 const char *descr, int &b): Argument_target(0, std::string(),
150 std::string(descr),
151 std::string(arg_descr)),
152 val(b){}
153 IntTarget(char k, const char *lname,
154 const char *arg_descr,
155 const char *descr, int &b): Argument_target(k, std::string(lname),
156 std::string(descr),
157 std::string(arg_descr)),
158 val(b){}
159 virtual bool process(int &argc, const char **&argv){
160 if (argc==0){
161 std::cerr << "Missing value for argument." << std::endl;
162 return false;
163 }
164 if (my_sscanf(argv[0], "%d", &val) ==1){
165 --argc;
166 ++argv;
167 return true;
168 } else {
169 std::cerr << "Integer not found at " << argv[0] << std::endl;
170 return false;
171 }
172 }
173 virtual void write_value(std::ostream &out) const {
174 out << val;
175 }
176 virtual ~IntTarget(){}
177 };
178
179 class Argument_helper::UIntTarget: public Argument_target{
180 public:
181 unsigned int &val;
182 UIntTarget(const char *arg_descr,
183 const char *descr, unsigned int &b): Argument_target(0, std::string(),
184 std::string(descr),
185 std::string(arg_descr)),
186 val(b){}
187 UIntTarget(char k, const char *lname,
188 const char *arg_descr,
189 const char *descr, unsigned int &b): Argument_target(k, std::string(lname),
190 std::string(descr),
191 std::string(arg_descr)),
192 val(b){}
193 virtual bool process(int &argc, const char **&argv){
194 if (argc==0){
195 std::cerr << "Missing value for argument." << std::endl;
196 return false;
197 }
198 if (my_sscanf(argv[0], "%ud", &val) ==1){
199 --argc;
200 ++argv;
201 return true;
202 } else {
203 std::cerr << "Unsigned integer not found at " << argv[0] << std::endl;
204 return false;
205 }
206 }
207 virtual void write_value(std::ostream &out) const {
208 out << val;
209 }
210 virtual ~UIntTarget(){}
211 };
212
213
214 class Argument_helper::CharTarget: public Argument_target{
215 public:
216 char &val;
217 CharTarget(char k, const char *lname,
218 const char *arg_descr,
219 const char *descr, char &b): Argument_target(k, std::string(lname),
220 std::string(descr),
221 std::string(arg_descr)), val(b){}
222 CharTarget(const char *arg_descr,
223 const char *descr, char &b): Argument_target(std::string(descr),
224 std::string(arg_descr)), val(b){}
225 virtual bool process(int &argc, const char **&argv){
226 if (argc==0){
227 std::cerr << "Missing value for argument." << std::endl;
228 return false;
229 }
230 if (my_sscanf(argv[0], "%c", &val) ==1){
231 --argc;
232 ++argv;
233 return true;
234 } else {
235 std::cerr << "Character not found at " << argv[0] << std::endl;
236 return false;
237 }
238 }
239 virtual void write_value(std::ostream &out) const {
240 out << val;
241 }
242 virtual ~CharTarget(){}
243 };
244
245
246 class Argument_helper::StringTarget: public Argument_target{
247 public:
248 std::string &val;
249 StringTarget(const char *arg_descr,
250 const char *descr, std::string &b): Argument_target(0, std::string(),
251 descr,
252 arg_descr),
253 val(b){}
254
255 StringTarget(char k, const char *lname, const char *arg_descr,
256 const char *descr, std::string &b): Argument_target(k, lname, descr,
257 arg_descr),
258 val(b){}
259
260 virtual bool process(int &argc, const char **&argv){
261 if (argc==0){
262 std::cerr << "Missing string argument." << std::endl;
263 return false;
264 }
265 val= argv[0];
266 --argc;
267 ++argv;
268 return true;
269 }
270 virtual void write_value(std::ostream &out) const {
271 out << val;
272 }
273 virtual ~StringTarget(){}
274 };
275
276
277 class Argument_helper::StringVectorTarget: public Argument_target{
278 public:
279 std::vector<std::string> &val;
280
281 StringVectorTarget(char k, const char *lname, const char *arg_descr,
282 const char *descr, std::vector<std::string> &b): Argument_target(k, lname, descr,
283 arg_descr),
284 val(b){}
285
286 virtual bool process(int &argc, const char **&argv){
287 while (argc >0 && argv[0][0] != '-'){
288 val.push_back(argv[0]);
289 --argc;
290 ++argv;
291 }
292 return true;
293 }
294 virtual void write_value(std::ostream &out) const {
295 for (unsigned int i=0; i< val.size(); ++i){
296 out << val[i] << " ";
297 }
298 }
299 virtual ~StringVectorTarget(){}
300 };
301
302
303
304
305 Argument_helper::Argument_helper(){
306 author_="Someone";
307 description_= "This program does something.";
308 date_= "A long long time ago.";
309 version_=-1;
310 extra_arguments_=NULL;
311 seen_end_named_=false;
312 new_flag('v', "verbose", "Whether to print extra information", verbose);
313 new_flag('V', "VERBOSE", "Whether to print lots of extra information", VERBOSE);
314 }
315
316
317
318 void Argument_helper::set_string_vector(const char *arg_description,
319 const char *description,
320 std::vector<std::string> &dest){
321 assert(extra_arguments_==NULL);
322 extra_arguments_descr_= description;
323 extra_arguments_arg_descr_= arg_description;
324 extra_arguments_= &dest;
325 }
326
327 void Argument_helper::set_author(const char *author){
328 author_=author;
329 }
330
331 void Argument_helper::set_description(const char *descr){
332 description_= descr;
333 }
334
335 void Argument_helper::set_name(const char *descr){
336 name_= descr;
337 }
338
339 void Argument_helper::set_version(float v){
340 version_=v;
341 }
342
343 void Argument_helper::set_version(const char *s){
344 std::stringstream f;
345 f << s;
346 f >> version_;
347 }
348
349 void Argument_helper::set_build_date(const char *date){
350 date_=date;
351 }
352
353 void Argument_helper::new_argument_target(Argument_target *t) {
354 assert(t!= NULL);
355 if (t->key != 0){
356 if (short_names_.find(t->key) != short_names_.end()){
357 std::cerr << "Two arguments are defined with the same character key, namely" << std::endl;
358 short_names_[t->key]->write_usage(std::cerr);
359 std::cerr << "\n and \n";
360 t->write_usage(std::cerr);
361 std::cerr << std::endl;
362 }
363 short_names_[t->key]= t;
364 }
365 if (!t->long_name.empty()){
366 if (long_names_.find(t->long_name) != long_names_.end()){
367 std::cerr << "Two arguments are defined with the same long key, namely" << std::endl;
368 long_names_[t->long_name]->write_usage(std::cerr);
369 std::cerr << "\n and \n";
370 t->write_usage(std::cerr);
371 std::cerr << std::endl;
372 }
373 long_names_[t->long_name]= t;
374 }
375 all_arguments_.push_back(t);
376 }
377
378 void Argument_helper::new_flag(char key, const char *long_name, const char *description,bool &dest){
379 Argument_target *t= new FlagTarget(key, long_name, description, dest);
380 new_argument_target(t);
381 };
382
383
384
385 void Argument_helper::new_string(const char *arg_description, const char *description,
386 std::string &dest){
387 Argument_target *t= new StringTarget(arg_description, description, dest);
388 unnamed_arguments_.push_back(t);
389 all_arguments_.push_back(t);
390 };
391 void Argument_helper::new_optional_string(const char *arg_description, const char *description,
392 std::string &dest){
393 Argument_target *t= new StringTarget(arg_description, description, dest);
394 optional_unnamed_arguments_.push_back(t);
395 };
396 void Argument_helper::new_named_string(char key, const char *long_name,
397 const char *arg_description, const char *description,
398 std::string &dest){
399 Argument_target *t= new StringTarget(key, long_name, arg_description, description, dest);
400 new_argument_target(t);
401 };
402
403
404 void Argument_helper::new_named_string_vector(char key, const char *long_name,
405 const char *arg_description, const char *description,
406 std::vector<std::string> &dest){
407 Argument_target *t= new StringVectorTarget(key, long_name, arg_description, description, dest);
408 new_argument_target(t);
409 };
410
411
412
413 void Argument_helper::new_int(const char *arg_description, const char *description,
414 int &dest){
415 Argument_target *t= new IntTarget(arg_description, description, dest);
416 unnamed_arguments_.push_back(t);
417 all_arguments_.push_back(t);
418 };
419 void Argument_helper::new_optional_int(const char *arg_description, const char *description,
420 int &dest){
421 Argument_target *t= new IntTarget(arg_description, description, dest);
422 optional_unnamed_arguments_.push_back(t);
423 };
424 void Argument_helper::new_named_int(char key, const char *long_name,
425 const char *arg_description, const char *description,
426 int &dest){
427 Argument_target *t= new IntTarget(key, long_name, arg_description, description, dest);
428 new_argument_target(t);
429 };
430
431 void Argument_helper::new_unsigned_int(const char *arg_description, const char *description,
432 unsigned int &dest){
433 Argument_target *t= new UIntTarget(arg_description, description, dest);
434 unnamed_arguments_.push_back(t);
435 all_arguments_.push_back(t);
436 };
437 void Argument_helper::new_optional_unsigned_int(const char *arg_description, const char *description,
438 unsigned int &dest){
439 Argument_target *t= new UIntTarget(arg_description, description, dest);
440 optional_unnamed_arguments_.push_back(t);
441 };
442 void Argument_helper::new_named_unsigned_int(char key, const char *long_name,
443 const char *arg_description, const char *description,
444 unsigned int &dest){
445 Argument_target *t= new UIntTarget(key, long_name, arg_description, description, dest);
446 new_argument_target(t);
447 };
448
449
450 void Argument_helper::new_double(const char *arg_description, const char *description,
451 double &dest){
452 Argument_target *t= new DoubleTarget(arg_description, description, dest);
453 unnamed_arguments_.push_back(t);
454 all_arguments_.push_back(t);
455 };
456 void Argument_helper::new_optional_double(const char *arg_description, const char *description,
457 double &dest){
458 Argument_target *t= new DoubleTarget(arg_description, description, dest);
459 optional_unnamed_arguments_.push_back(t);
460 };
461 void Argument_helper::new_named_double(char key, const char *long_name,
462 const char *arg_description, const char *description,
463 double &dest){
464 Argument_target *t= new DoubleTarget(key, long_name, arg_description, description, dest);
465 new_argument_target(t);
466 };
467
468 void Argument_helper::new_char(const char *arg_description, const char *description,
469 char &dest){
470 Argument_target *t= new CharTarget(arg_description, description, dest);
471 unnamed_arguments_.push_back(t);
472 all_arguments_.push_back(t);
473 };
474 void Argument_helper::new_optional_char(const char *arg_description, const char *description,
475 char &dest){
476 Argument_target *t= new CharTarget(arg_description, description, dest);
477 optional_unnamed_arguments_.push_back(t);
478 };
479 void Argument_helper::new_named_char(char key, const char *long_name,
480 const char *arg_description, const char *description,
481 char &dest){
482 Argument_target *t= new CharTarget(key, long_name, arg_description, description, dest);
483 new_argument_target(t);
484 };
485
486
487
488 void Argument_helper::write_usage(std::ostream &out) const {
489 out << name_ << " version " << version_ << ", by " << author_ << std::endl;
490 out << description_ << std::endl;
491 out << "Compiled on " << date_ << std::endl << std::endl;
492 out << "Usage: " << name_ << " ";
493 for (UVect::const_iterator it= unnamed_arguments_.begin(); it != unnamed_arguments_.end(); ++it){
494 (*it)->write_name(out);
495 out << " ";
496 }
497 for (UVect::const_iterator it= optional_unnamed_arguments_.begin();
498 it != optional_unnamed_arguments_.end(); ++it){
499 out << "[";
500 (*it)->write_name(out);
501 out << "] ";
502 }
503 if (extra_arguments_ != NULL) {
504 out << "[" << extra_arguments_arg_descr_ << "]";
505 }
506
507 out << std::endl << std::endl;
508 out << "All arguments:\n";
509 for (UVect::const_iterator it= unnamed_arguments_.begin(); it != unnamed_arguments_.end(); ++it){
510 (*it)->write_usage(out);
511 }
512 for (UVect::const_iterator it= optional_unnamed_arguments_.begin();
513 it != optional_unnamed_arguments_.end(); ++it){
514 (*it)->write_usage(out);
515 }
516
517 //out << extra_arguments_arg_descr_ << ": " << extra_arguments_descr_ << std::endl;
518 for (SMap::const_iterator it= short_names_.begin(); it != short_names_.end(); ++it){
519 (it->second)->write_usage(out);
520 }
521 }
522
523
524
525 void Argument_helper::write_values(std::ostream &out) const {
526 for (UVect::const_iterator it= unnamed_arguments_.begin(); it != unnamed_arguments_.end(); ++it){
527 out << (*it)->description;
528 out << ": ";
529 (*it)->write_value(out);
530 out << std::endl;
531 }
532 for (UVect::const_iterator it= optional_unnamed_arguments_.begin();
533 it != optional_unnamed_arguments_.end(); ++it){
534 out << (*it)->description;
535 out << ": ";
536 (*it)->write_value(out);
537 out << std::endl;
538 }
539 if (extra_arguments_!=NULL){
540 for (std::vector<std::string>::const_iterator it= extra_arguments_->begin();
541 it != extra_arguments_->end(); ++it){
542 out << *it << " ";
543 }
544 }
545
546 for (SMap::const_iterator it= short_names_.begin(); it != short_names_.end(); ++it){
547 out << it->second->description;
548 out << ": ";
549 it->second->write_value(out);
550 out << std::endl;
551 }
552 }
553
554 Argument_helper::~Argument_helper(){
555 for (std::vector<Argument_target*>::iterator it= all_arguments_.begin();
556 it != all_arguments_.end(); ++it){
557 delete *it;
558 }
559 }
560
561
562 void Argument_helper::process(int argc, const char **argv){
563 name_= argv[0];
564 ++argv;
565 --argc;
566
567 current_unnamed_= unnamed_arguments_.begin();
568 current_optional_unnamed_= optional_unnamed_arguments_.begin();
569
570 for ( int i=0; i< argc; ++i){
571 if (strcmp(argv[i], "--help") == 0){
572 write_usage(std::cout);
573 exit(0);
574 }
575 }
576
577 while (argc != 0){
578
579 const char* cur_arg= argv[0];
580 if (cur_arg[0]=='-' && !seen_end_named_){
581 --argc; ++argv;
582 if (cur_arg[1]=='-'){
583 if (cur_arg[2] == '\0') {
584 //std::cout << "Ending flags " << std::endl;
585 seen_end_named_=true;
586 } else {
587 // long argument
588 LMap::iterator f= long_names_.find(cur_arg+2);
589 if ( f != long_names_.end()){
590 if (!f->second->process(argc, argv)) {
591 handle_error();
592 }
593 } else {
594 std::cerr<< "Invalid long argument "<< cur_arg << ".\n";
595 handle_error();
596 }
597 }
598 } else {
599 if (cur_arg[1]=='\0') {
600 std::cerr << "Invalid argument " << cur_arg << ".\n";
601 handle_error();
602 }
603 SMap::iterator f= short_names_.find(cur_arg[1]);
604 if ( f != short_names_.end()){
605 if (!f->second->process(argc, argv)) {
606 handle_error();
607 }
608 } else {
609 std::cerr<< "Invalid short argument "<< cur_arg << ".\n";
610 handle_error();
611 }
612 }
613 } else {
614 if (current_unnamed_ != unnamed_arguments_.end()){
615 Argument_target *t= *current_unnamed_;
616 t->process(argc, argv);
617 ++current_unnamed_;
618 } else if (current_optional_unnamed_ != optional_unnamed_arguments_.end()){
619 Argument_target *t= *current_optional_unnamed_;
620 t->process(argc, argv);
621 ++current_optional_unnamed_;
622 } else if (extra_arguments_!= NULL){
623 extra_arguments_->push_back(cur_arg);
624 --argc;
625 ++argv;
626 } else {
627 std::cerr << "Invalid extra argument " << argv[0] << std::endl;
628 handle_error();
629 }
630 }
631 }
632
633 if (current_unnamed_ != unnamed_arguments_.end()){
634 std::cerr << "Missing required arguments:" << std::endl;
635 for (; current_unnamed_ != unnamed_arguments_.end(); ++current_unnamed_){
636 (*current_unnamed_)->write_name(std::cerr);
637 std::cerr << std::endl;
638 }
639 std::cerr << std::endl;
640 handle_error();
641 }
642
643 if (VERBOSE) verbose=true;
644 }
645
646 void Argument_helper::handle_error() const {
647 write_usage(std::cerr);
648 exit(1);
649 }
650 }
651