core/vul/vul_arg.cxx
Go to the documentation of this file.
00001 // This is core/vul/vul_arg.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 // Note that even though this file defines instances of a templated
00008 // class, it is a .cxx file and not a .txx file because it does not
00009 // supply a class definition for use by clients.
00010 //
00011 // If you need to define your own vul_arg<T>, you should #include vul_arg.h
00012 // ONLY, in your source file (myarg.cxx, say), define these three global
00013 // functions (which can by static if you like) in myarg.cxx
00014 // \code
00015 //   void settype(vul_arg<T> &);
00016 //   void print_value(vul_arg<T> const &, vcl_ostream &);
00017 //   int  parse(vul_arg<T>*, char**);
00018 // \endcode
00019 // and then instantiate the class vul_arg<T> as usual (in myarg.cxx).
00020 
00021 #include "vul_arg.h"
00022 
00023 #include <vcl_cassert.h>
00024 #include <vcl_algorithm.h>
00025 #include <vcl_iostream.h>
00026 #include <vcl_sstream.h>
00027 #include <vcl_cstring.h>
00028 #include <vcl_cstdlib.h> // exit()
00029 #include <vcl_cmath.h>   // floor()
00030 #include <vcl_vector.h>
00031 #include <vcl_list.h>
00032 
00033 #include <vul/vul_sprintf.h>
00034 #include <vul/vul_string.h>
00035 #include <vul/vul_reg_exp.h>
00036 #include <vul/vul_printf.h>
00037 
00038 //------------------------------------------------------------------------------
00039 
00040 // definition: used in constructor of vul_arg for required flags
00041 vul_arg_base::required_option_type vul_arg_base::is_required;
00042 
00043 
00044 char const* vul_arg_base::option()
00045 { return option_.c_str(); }
00046 
00047 char const* vul_arg_base::help()
00048 { return help_.c_str(); }
00049 
00050 //: Parse the list of arguments....
00051 void vul_arg_parse(int& argc, char **& argv,
00052                    bool warn_about_unrecognized_arguments)
00053 {
00054   vul_arg_base::parse_deprecated(argc, argv,
00055                                  warn_about_unrecognized_arguments);
00056 }
00057 
00058 //: Add an externally supplied list of args to the global list.
00059 void vul_arg_include(vul_arg_info_list& l)
00060 {
00061   vul_arg_base::include_deprecated(l);
00062 }
00063 
00064 //: Print all args, and usage messages.
00065 void vul_arg_display_usage_and_exit(char const* msg)
00066 {
00067   vul_arg_base::display_usage_and_exit(msg);
00068 }
00069 
00070 
00071 //: Returns true if arg was set on the command line.
00072 bool vul_arg_base::set() const
00073 { return set_; }
00074 
00075 static vul_arg_info_list& current_list() // instance "method"
00076 {
00077   static vul_arg_info_list list;
00078   return list;
00079 }
00080 
00081 //: Add another vul_arg_info_list to the current one.
00082 // This allows for the inclusion of different sets of arguments into the
00083 // main program, from different libraries.
00084 void vul_arg_base::include_deprecated(vul_arg_info_list& l)
00085 {
00086   current_list().include(l);
00087 }
00088 
00089 //
00090 void vul_arg_base::add_to_current(vul_arg_base* a)
00091 {
00092   current_list().add(a);
00093 }
00094 
00095 //: The main static method.
00096 void vul_arg_base::parse_deprecated(int& argc, char **& argv, bool warn_about_unrecognized_arguments)
00097 {
00098   current_list().parse(argc, argv, warn_about_unrecognized_arguments);
00099 }
00100 
00101 void vul_arg_base::set_help_option(char const* str)
00102 {
00103   current_list().set_help_option( str);
00104 }
00105 
00106 void vul_arg_base::set_help_precis(char const* str)
00107 {
00108   current_list().set_help_precis( str);
00109 }
00110 
00111 void vul_arg_base::set_help_description(char const* str)
00112 {
00113   current_list().set_help_description( str);
00114 }
00115 
00116 void vul_arg_base::display_usage(char const* msg)
00117 {
00118   if (msg) vcl_cerr << "** WARNING ** " << msg << vcl_endl;
00119   current_list().display_help("");
00120 }
00121 
00122 void vul_arg_base::display_usage_and_exit(char const* msg)
00123 {
00124   if (msg) vcl_cerr << "** ERROR ** " << msg << vcl_endl;
00125   current_list().display_help("");
00126   vcl_exit(-1);
00127 }
00128 
00129 // vul_arg_base constructors
00130 
00131 vul_arg_base::vul_arg_base(vul_arg_info_list& l, char const* option_string, char const* helpstring,  bool required)
00132 : set_(false),
00133   required_(required),
00134   option_(option_string?option_string:"\0"),
00135   help_(helpstring?helpstring:"\0")
00136 {
00137   l.add(this);
00138 }
00139 
00140 vul_arg_base::vul_arg_base(char const* option_string, char const* helpstring, bool required )
00141     : set_(false),
00142       required_(required),
00143   option_(option_string?option_string:"\0"),
00144   help_(helpstring?helpstring:"\0")
00145 {
00146   current_list().add(this);
00147 }
00148 
00149 //------------------------------------------------------------------------------
00150 
00151 //: Change the help operator (defaults to -?)
00152 void vul_arg_info_list::set_help_option(char const* str)
00153 {
00154   // check that the operator isn't already being used
00155   for (unsigned int i=0; i<args_.size(); i++) {
00156     if (vcl_strcmp(args_[i]->option(),str) == 0) {
00157       vcl_cerr << "vul_arg_info_list: WARNING: requested help operator already assigned\n";
00158       return;
00159     }
00160   }
00161 
00162   help_ = str;
00163 }
00164 
00165 
00166 //: Add an argument to the list.
00167 void vul_arg_info_list::add(vul_arg_base* argmt)
00168 {
00169   if ( argmt->option() && help_ == argmt->option() )
00170     vcl_cerr << "vul_arg_info_list: WARNING: '-" << help_
00171              << "' option reserved and will be ignored\n";
00172   else
00173     args_.push_back(argmt);
00174 }
00175 
00176 //: Append another list.  The other list is not copied, just pointed to.
00177 void vul_arg_info_list::include(vul_arg_info_list& l)
00178 {
00179   assert(&l != this);
00180 
00181   for (unsigned int i = 0; i < l.args_.size(); ++i)
00182     add(l.args_[i]);
00183 }
00184 
00185 //: Display help about each option in the arg list.
00186 // Note that this function does not exit at the end.
00187 void vul_arg_info_list::display_help( char const*progname)
00188 {
00189   if (progname)
00190     vcl_cerr << "Usage: " << progname << ' ';
00191   else
00192     vcl_cerr << "Usage: <prog_name> ";
00193 
00194   // Print "prog [-a int] string string"
00195 
00196   for (unsigned int i=0; i< args_.size(); i++) {
00197     if (! args_[i]->option_.empty()) {
00198       if (!args_[i]->required_) vcl_cerr << '[';
00199       vcl_cerr << args_[i]->option();
00200       if (vcl_strlen(args_[i]->type_)> 0)
00201         vcl_cerr << ' ' << args_[i]->type_;
00202       if (!args_[i]->required_) vcl_cerr << ']';
00203       vcl_cerr << ' ';
00204     }
00205     else {
00206       // options without switches are required.
00207       vcl_cerr << args_[i]->type_ << ' ';
00208     }
00209   }
00210 
00211   vcl_cerr << vcl_endl << command_precis_ << vcl_endl;
00212 
00213   // Find longest option, type name, or default
00214   vcl_size_t maxl_option  = vcl_max(vcl_size_t(8), help_.size()); // Length of "REQUIRED" or help option
00215   vcl_size_t maxl_type = 4; // Length of "Type", minimum "bool"
00216   //  int maxl_default = 0;
00217   for (unsigned int i=0; i< args_.size(); i++)
00218     if (!args_[i]->help_.empty()) {
00219       if (!args_[i]->option_.empty()) {
00220         vcl_size_t l = vcl_strlen(args_[i]->option());
00221         if (l > maxl_option) maxl_option = l;
00222       }
00223       vcl_size_t l = vcl_strlen(args_[i]->type_);
00224       if (l > maxl_type) maxl_type = l;
00225     }
00226 
00227   // Print long form of args
00228   vcl_string fmtbuf = vul_sprintf("%%%ds %%-%ds %%s ", maxl_option, maxl_type);
00229 
00230   // Do required args first
00231   vul_printf(vcl_cerr, "REQUIRED:\n");
00232   for (unsigned int i=0; i< args_.size(); i++)  // First required without option string
00233     if (!args_[i]->help_.empty())
00234         if (args_[i]->option_.empty()&& !(args_[i]->required_)) {
00235           vul_printf(vcl_cerr, fmtbuf.c_str(), "", args_[i]->type_, args_[i]->help_.c_str());
00236           vcl_cerr << " ["; args_[i]->print_value(vcl_cerr); vcl_cerr << "]\n"; // default
00237         }
00238   for (unsigned int i=0; i< args_.size(); i++) // Then required with option string
00239     if (!args_[i]->help_.empty())
00240         if (args_[i]->required_  && !args_[i]->option_.empty()) {
00241           vul_printf(vcl_cerr, fmtbuf.c_str(), args_[i]->option(), args_[i]->type_, args_[i]->help_.c_str());
00242           vcl_cerr << '\n'; // ["; args_[i]->print_value(vcl_cerr); vcl_cerr << "]\n"; // default
00243         }
00244 
00245   vcl_cerr << vcl_endl;
00246 
00247   // Then others
00248   vul_printf(vcl_cerr, "Optional:\n");
00249   vul_printf(vcl_cerr, fmtbuf.c_str(), "Switch", "Type", "Help [default value]") << vcl_endl << vcl_endl;
00250   for (unsigned int i=0; i< args_.size(); i++)
00251     if (!args_[i]->help_.empty())
00252       if (!args_[i]->option_.empty() && !(args_[i]->required_) ) {
00253         vul_printf(vcl_cerr, fmtbuf.c_str(), args_[i]->option(), args_[i]->type_, args_[i]->help_.c_str());
00254         vcl_cerr << " ["; args_[i]->print_value(vcl_cerr); vcl_cerr << "]\n"; // default
00255       }
00256   vul_printf(vcl_cerr, fmtbuf.c_str(), help_.c_str(), "bool", "Print this message\n");
00257 
00258   if (!description_.empty()) vcl_cerr << '\n' << description_;
00259 }
00260 
00261 //: Parse the command line, using the current list of args.
00262 //  Remove all recognised arguments from the command line by modifying argc and argv.
00263 void vul_arg_info_list::parse(int& argc, char **& argv, bool warn_about_unrecognized_arguments)
00264 {
00265   vcl_vector<bool> done_once(args_.size(), false);
00266 
00267   // 0. Check that there are no duplicate switches, O(n^2) as n is tiny.
00268   for (unsigned int i = 0; i < args_.size(); ++i)
00269     if (!args_[i]->option_.empty())
00270       for (unsigned int j = i+1; j < args_.size(); ++j)
00271         if (args_[i]->option_ == args_[j]->option_)
00272           vcl_cerr << "vul_arg_info_list: WARNING: repeated switch ["
00273                    << args_[j]->option_ << "]\n";
00274 
00275   // 0a. Clear "set" flags on args
00276   for (unsigned int i = 0; i < args_.size(); ++i)
00277     args_[i]->set_ = false;
00278 
00279   // Generate shorter command name
00280   char * cmdname = argv[0]+vcl_strlen(argv[0]);
00281   while (cmdname > argv[0] && *cmdname != '/' && *cmdname != '\\') --cmdname ;
00282   if (*cmdname == '\\' || *cmdname == '/') cmdname++;
00283 
00284 
00285   // 1. Collect option arguments (i.e. ones with "-"),
00286   // and squeeze them out of argv.
00287   // Make sure to do things sequentially
00288 
00289   char ** my_argv = argv + 1; // Skip program name
00290   while (*my_argv) {
00291     char* argmt = *my_argv;
00292     bool eaten = false;
00293     for (unsigned int i = 0; i < args_.size(); ++i) {
00294       if (!args_[i]->option_.empty()) {
00295         if ( help_ == argmt ) { // look for the '-?' operator (i.e. HELP)
00296           display_help(cmdname);
00297           vcl_exit(1);
00298         }
00299 
00300         if (args_[i]->option_==argmt) {
00301           done_once[i] = true;
00302           int advance = args_[i]->parse(my_argv + 1);
00303           args_[i]->set_ = true;
00304           if (advance >= 0) {
00305             // Pull down remaining args
00306             for (char ** av = my_argv; *(av + advance); ++av)
00307               *av = *(av + advance + 1);
00308 
00309             eaten = true;
00310             break;
00311           }
00312         }
00313       }
00314     }
00315     if (!eaten)
00316       ++my_argv;
00317   }
00318 
00319   if (verbose_) {
00320     vcl_cerr << "args remaining:";
00321     for (char ** av = argv; *av; ++av)
00322       vcl_cerr << " [" << *av << ']';
00323     vcl_cerr << vcl_endl;
00324   }
00325 
00326 
00327   // 2. Just take from the list to fill the non-option arguments
00328   my_argv = argv + 1;
00329   int num_satisfied = 0;
00330   for (unsigned int i = 0; i < args_.size(); ++i)
00331     if (args_[i]->option_.empty()) {
00332       if (*my_argv) {
00333         done_once[i] = true;
00334         int advance = args_[i]->parse(my_argv);
00335         args_[i]->set_ = true;
00336         my_argv += advance;
00337         ++num_satisfied;
00338       }
00339       else {
00340         display_help(cmdname);
00341 
00342         vcl_cerr << "\nargParse::ERROR: Required arg " << (num_satisfied+1)
00343                  << " not supplied\n\n";
00344         vcl_exit(1);
00345       }
00346     }
00347 
00348 
00349   // 3. Move my_argv down to first unused arg, and reset argc
00350   argc = 1;
00351   for (char ** av = my_argv; *av; ++av)
00352     ++argc;
00353   for (int i = 1; i < argc; ++i)
00354     argv[i] = my_argv[i-1];
00355   argv[argc] = 0;
00356 
00357   // 4. Error checking.
00358   //
00359   // 4.2 Sometimes it's bad if all args weren't used (i.e. trailing args)
00360   if (autonomy_ == all) {
00361     vcl_cerr << "vul_arg_info_list: Some arguments were unused: ";
00362     for (char ** av = argv; *av; ++av)
00363       vcl_cerr << ' ' << *av;
00364     vcl_cerr << vcl_endl;
00365     display_help(cmdname);
00366   }
00367 
00368   // 4.3 It's often bad if a switch was not recognized.
00369   if (warn_about_unrecognized_arguments)
00370     for (char ** av = argv; *av; ++av)
00371       if (**av == '-') {
00372         display_help(cmdname);
00373         vcl_cerr << "vul_arg_info_list: WARNING: Unparsed switch [" << *av << "]\n";
00374       }
00375 
00376   // 4.3 This is required arguments (including option) have been set
00377   for (unsigned int i = 0; i < args_.size(); ++i)
00378       if (args_[i]->required_ && ! (args_[i]->set_) ) {
00379          display_help(cmdname);
00380 
00381          vcl_cerr << "\nargParse::ERROR: Required arg " << args_[i]->option_
00382                   << " not supplied\n\n";
00383          vcl_exit(1);
00384       }
00385 
00386 
00387   // 5. Some people like a chatty program.
00388 #ifdef DEBUG //fsm: do not print outcome - it looks like an error message.
00389   if (verbose_) {
00390     // Print outcome
00391     for (unsigned int i = 0; i < args_.size(); ++i)
00392       if (args[i]->option_) {
00393         vcl_cerr << "Switch " << args_[i]->option_ << ": "
00394                  << (!done_once[i] ? "not " : "") << "done, value [";
00395         args[i]->print_value(vcl_cerr);
00396         vcl_cerr << "]\n";
00397       }
00398 
00399     for (unsigned int i = 0; i < args.size(); ++i)
00400       if (!args[i]->option_) {
00401         vcl_cerr << "Trailer: ";
00402         args_[i]->print_value(vcl_cerr);
00403         vcl_cerr << vcl_endl;
00404       }
00405 
00406     vcl_cerr << "args remaining [argc = " << argc << "]:";
00407     for (char ** av = argv; *av; ++av)
00408       vcl_cerr << ' ' << *av;
00409     vcl_cerr << "\n--------------\n";
00410   }
00411 #endif
00412 }
00413 
00414 
00415 //------------------------------------------------------------------------------
00416 
00417 //: function to parse matlab or UNIX style integer ranges.
00418 // eg. 1:3 is matlab for 1,2,3 and 1-3 is UNIX for 1,2,3
00419 //
00420 // parsed as follows:
00421 //   any character other than '-' and ':' is considered a list separator
00422 //   simple ranges can be written as 1:3 or 1-3 (=1,2,3) or 3:1 (=3,2,1)
00423 //   complete ranges can be written as 1:2:5 or 1-2-5 (=1,3,5)
00424 //   negative numbers are handled 'transparently'
00425 //   (e.g. -1:-3 or -1--3 or even -1--1--3 ...:).
00426 //
00427 // Returns 1 on success and 0 on failure.
00428 //
00429 static int list_parse(vcl_list<int> &out, char ** argv)
00430 {
00431   out.clear();
00432 
00433   // Empty list specified as the last argument.
00434   if ( !argv[0] ) return 0; // failure
00435 
00436   vcl_string str(argv[0]);
00437 
00438 #define REGEXP_INTEGER "\\-?[0123456789]+"
00439 
00440   vul_reg_exp range_regexp("(" REGEXP_INTEGER ")"      // int
00441                            "([:-]" REGEXP_INTEGER ")?" // :int [optional]
00442                            "([:-]" REGEXP_INTEGER ")?" // :int [optional]
00443                           );
00444 
00445   while (str.length() > 0 && range_regexp.find(str)) {
00446     // the start/end positions (ref from 0) of the
00447     //    current ',' separated token.
00448     vcl_ptrdiff_t start= range_regexp.start(0);
00449     vcl_ptrdiff_t endp = range_regexp.end(0);
00450     if (start != 0) {
00451       vcl_cerr << "vul_arg<vcl_list<int> >: Bad argument [" << argv[0] << "]\n";
00452       return 0; // failure
00453     }
00454 
00455 #ifdef DEBUG
00456     // this is the current token.
00457     vcl_string token = str.substr(start, endp);
00458     vcl_cerr << "token = " << token << '\n';
00459 #endif
00460     vcl_string match1 = range_regexp.match(1);
00461 #ifdef DEBUG
00462     vcl_cerr << "match1 = " << match1 << '\n';
00463 #endif
00464     vcl_string match2 = range_regexp.match(2);
00465 #ifdef DEBUG
00466     vcl_cerr << "match2 = " << match2 << '\n';
00467 #endif
00468     vcl_string match3 = range_regexp.match(3);
00469 #ifdef DEBUG
00470     vcl_cerr << "match3 = " << match3 << '\n';
00471 #endif
00472 
00473     // Remove this match from the front of string.
00474     str.erase(0, endp);
00475     if (!str.empty() && str[0] == ',') str.erase(0, 1);
00476 
00477 #if 0
00478     vcl_cerr << "Range regexp matched [" << token <<  "]: parts ["
00479              << match1<<"] ["<<match2<<"] ["<<match3<<"]\n"
00480              << "  str->[" << str << "]\n";
00481 #endif
00482 
00483     bool matched2 = range_regexp.match(2).size() > 0;
00484     bool matched3 = range_regexp.match(3).size() > 0;
00485 
00486     int s = vul_string_atoi(match1);
00487     int d = 1;
00488     int e = s;
00489     if (matched3) {
00490       // "1:2:10"
00491       d = vul_string_atoi(match2.substr(1));
00492       e = vul_string_atoi(match3.substr(1));
00493     }
00494     else if (matched2)
00495       e = vul_string_atoi(match2.substr(1));
00496 
00497 #ifdef DEBUG
00498     vcl_cerr << "  " << s << ':' << d << ':' << e << '\n';
00499 #endif
00500     if (e >= s) {
00501       if (d < 0) {
00502         vcl_cerr << "WARNING: d < 0\n";
00503         d = -d;
00504       }
00505       for (int i = s; i <= e; i += d)
00506         out.push_back(i);
00507     }
00508     else {
00509       if (d > 0) {
00510         vcl_cerr << "WARNING: d > 0\n";
00511         d = -d;
00512       }
00513       for (int i = s; i >= e; i += d)
00514         out.push_back(i);
00515     }
00516   }
00517 
00518   if (str.empty())
00519     return 1; // success
00520 
00521   vcl_cerr << "vul_arg<vcl_list<int> >: Bad argument fragment  [" << str << "]\n";
00522   return 0;
00523 }
00524 
00525 //------------------------------------------------------------------------------
00526 
00527 // specializations for specific types.
00528 // In emacs, C-s for "//: unsigned" to find the implementation for vul_arg<unsigned>
00529 // In vi: "/^\/\/: unsigned"
00530 
00531 #if 1
00532 # define VDS VCL_DEFINE_SPECIALIZATION
00533 #else
00534 # define VDS /* template <> */
00535 #endif
00536 
00537 //: bool
00538 VDS void settype(vul_arg<bool> &argmt) { argmt.type_ = "bool"; }
00539 
00540 VDS void print_value(vcl_ostream &s, vul_arg<bool> const &argmt)
00541 { s << (argmt() ? "set" : "not set"); }
00542 
00543 VDS int parse(vul_arg<bool>* argmt, char ** /*argv*/)
00544 {
00545   argmt->value_ = true;
00546   return 0; // bool sucks zero args, most others take one.
00547 }
00548 
00549 template class vul_arg<bool>;
00550 
00551 //: int
00552 VDS void settype(vul_arg<int> &argmt) { argmt.type_ = "integer"; }
00553 
00554 VDS void print_value(vcl_ostream  &s, vul_arg<int> const &argmt)
00555 { s << argmt(); }
00556 
00557 VDS int parse(vul_arg<int>* argmt, char ** argv)
00558 {
00559   if ( !argv ||  !argv[0] ) {
00560     // no input
00561     vcl_cerr << "vul_arg_parse: Expected integer, none is provided.\n";
00562     return -1;
00563   }
00564 
00565   char* endptr = 0;
00566   double v = vcl_strtod(argv[0], &endptr);
00567   if (*endptr != '\0') {
00568     // There is junk after the number, or no number was found
00569     vcl_cerr << "vul_arg_parse: WARNING: Attempt to parse \"" << *argv << "\" as int\n";
00570     return -1;
00571   }
00572   if (v != vcl_floor(v)) {
00573     vcl_cerr << "vul_arg_parse: Expected integer: saw " << argv[0] << vcl_endl;
00574     return -1;
00575   }
00576   argmt->value_ = int(v);
00577   return 1;
00578 }
00579 
00580 template class vul_arg<int>;
00581 
00582 //: int64
00583 #if VXL_HAS_INT_64
00584 VDS void settype(vul_arg<vxl_int_64> &argmt) { argmt.type_ = "integer64"; }
00585 
00586 VDS void print_value(vcl_ostream  &s, vul_arg<vxl_int_64> const &argmt)
00587 { s << argmt(); }
00588 
00589 VDS int parse(vul_arg<vxl_int_64>* argmt, char ** argv)
00590 {
00591   if ( !argv ||  !argv[0] )
00592   {
00593     // no input
00594     vcl_cerr << "vul_arg_parse: Expected integer, none is provided.\n";
00595     return -1;
00596   }
00597 
00598   // Ensure only digits are present allowing for the special case of an l or L suffix
00599   unsigned long len = (unsigned long)vcl_strlen(argv[0]);
00600   for (unsigned long i=0; i<len; ++i)
00601   {
00602     char tmp = argv[0][i];
00603     if (tmp < '0' || tmp > '9' || // Make sure the number only contains valid digits
00604         ((tmp == 'l' || tmp == 'L') && i+1 != len) || // Or the trailing l or L suffix
00605         (tmp=='-' && i != 0L && len <= 2L)) // Or a leading minus sign
00606     {
00607       vcl_cerr << "vul_arg_parse: WARNING: Attempt to parse \"" << *argv << "\" as int64\n";
00608       return -1;
00609     }
00610   }
00611 
00612   vcl_stringstream ss;
00613   ss << argv[0];
00614   ss >> argmt->value_;
00615 
00616   return 1;
00617 }
00618 
00619 template class vul_arg<vxl_int_64>;
00620 #endif
00621 
00622 //: unsigned
00623 VDS void settype(vul_arg<unsigned> &argmt) { argmt.type_ = "integer"; }
00624 
00625 VDS void print_value(vcl_ostream &s, vul_arg<unsigned> const &argmt)
00626 { s << argmt(); }
00627 
00628 VDS int parse(vul_arg<unsigned>* argmt, char ** argv)
00629 {
00630   if ( !argv ||  !argv[0] ) {
00631     // no input
00632     vcl_cerr << "vul_arg_parse: Expected integer, none is provided.\n";
00633     return -1;
00634   }
00635 
00636   char* endptr = 0;
00637   double v = vcl_strtod(argv[0], &endptr);
00638   if (*endptr != '\0') {
00639     // There is junk after the number, or no number was found
00640     vcl_cerr << "vul_arg_parse: WARNING: Attempt to parse " << *argv << " as int\n";
00641     return -1;
00642   }
00643   if (v != vcl_floor(v)) {
00644     vcl_cerr << "vul_arg_parse: Expected integer: saw " << argv[0] << vcl_endl;
00645     return -1;
00646   }
00647   argmt->value_ = unsigned(v);
00648   return 1;
00649 }
00650 
00651 template class vul_arg<unsigned>;
00652 
00653 //: float
00654 VDS void settype(vul_arg<float> &argmt) { argmt.type_ = "float"; }
00655 
00656 VDS void print_value(vcl_ostream &s, vul_arg<float> const &argmt)
00657 { s << argmt(); }
00658 
00659 VDS int parse(vul_arg<float>* argmt, char ** argv)
00660 {
00661   if ( !argv ||  !argv[0] ) {
00662     // no input
00663     vcl_cerr << "vul_arg_parse: Expected floating number, none is provided.\n";
00664     return -1;
00665   }
00666 
00667   char* endptr = 0;
00668   argmt->value_ = (float)vcl_strtod(argv[0], &endptr);
00669   if (*endptr == '\0')
00670     return 1;
00671   // There is junk after the number, or no number was found
00672   vcl_cerr << "vul_arg_parse: WARNING: Attempt to parse " << *argv << " as float\n";
00673   return -1;
00674 }
00675 
00676 template class vul_arg<float>;
00677 
00678 //: double
00679 VDS void settype(vul_arg<double> &argmt) { argmt.type_ = "float"; }
00680 
00681 VDS void print_value(vcl_ostream &s, vul_arg<double> const &argmt)
00682 { s << argmt(); }
00683 
00684 VDS int parse(vul_arg<double>* argmt, char ** argv)
00685 {
00686   if ( !argv ||  !argv[0] ) {
00687     // no input
00688     vcl_cerr << "vul_arg_parse: Expected floating number, none is provided.\n";
00689     return -1;
00690   }
00691 
00692   char* endptr = 0;
00693   argmt->value_ = vcl_strtod(argv[0], &endptr);
00694   if (*endptr == '\0')
00695     return 1;
00696   // There is junk after the number, or no number was found
00697   vcl_cerr << "vul_arg_parse: WARNING: Attempt to parse " << *argv << " as double\n";
00698   return -1;
00699 }
00700 
00701 template class vul_arg<double>;
00702 
00703 //: char *
00704 VDS void settype(vul_arg<char *> &argmt) { argmt.type_ = "string"; }
00705 
00706 VDS void print_value(vcl_ostream &s, vul_arg<char *> const &argmt)
00707 { s << '\'' << (argmt()?argmt():"(null)") << '\''; }
00708 
00709 VDS int parse(vul_arg<char*>* argmt, char ** argv)
00710 {
00711   argmt->value_ = argv[0]; // argv is valid till the end of the program so
00712   return 1;                // it's ok to just grab the pointer.
00713 }
00714 
00715 template class vul_arg<char*>;
00716 
00717 //: char const *
00718 VDS void settype(vul_arg<char const *> &argmt) { argmt.type_ = "string"; }
00719 
00720 VDS void print_value(vcl_ostream &s, vul_arg<char const *> const &argmt)
00721 { s << '\'' << (argmt()?argmt():"(null)") << '\''; }
00722 
00723 VDS int parse(vul_arg<char const *>* argmt, char ** argv)
00724 {
00725   if ( !argv ||  !argv[0] ) {
00726     // no input
00727     vcl_cerr << "vul_arg_parse: Expected string, none is provided.\n";
00728     return -1;
00729   }
00730 
00731   argmt->value_ = argv[0]; // argv is valid till the end of the program so
00732   return 1;                // it's ok to just grab the pointer.
00733 }
00734 
00735 template class vul_arg<char const*>;
00736 
00737 //: vcl_string
00738 VDS void settype(vul_arg<vcl_string> &argmt) { argmt.type_ = "string"; }
00739 
00740 VDS void print_value(vcl_ostream &s, vul_arg<vcl_string> const &argmt)
00741 { s << '\'' << argmt() << '\''; }
00742 
00743 VDS int parse(vul_arg<vcl_string>* argmt, char ** argv)
00744 {
00745   if ( !argv ||  !argv[0] ) {
00746     // no input
00747     vcl_cerr << "vul_arg_parse: Expected string, none is provided.\n";
00748     return -1;
00749   }
00750 
00751   if (argv[0]) {
00752     argmt->value_ = argv[0];
00753     return 1;
00754   }
00755   else {
00756     vcl_cerr << __FILE__ ": no argument to string option\n";
00757     return 0;
00758   }
00759 }
00760 
00761 template class vul_arg<vcl_string>;
00762 
00763 //: vcl_list<int>
00764 VDS void settype(vul_arg<vcl_list<int> > &argmt) { argmt.type_ = "integer list"; }
00765 
00766 VDS void print_value(vcl_ostream &s, vul_arg<vcl_list<int> > const &argmt)
00767 {
00768   for (vcl_list<int>::const_iterator i=argmt().begin(); i!=argmt().end(); ++i)
00769     s << ' ' << *i;
00770 }
00771 
00772 VDS int parse(vul_arg<vcl_list<int> >* argmt, char ** argv)
00773 {
00774   return list_parse(argmt->value_,argv);
00775 }
00776 
00777 template class vul_arg<vcl_list<int> >;
00778 
00779 //: vcl_vector<int>
00780 VDS void settype(vul_arg<vcl_vector<int> > &argmt) { argmt.type_ = "integer list"; }
00781 
00782 VDS void print_value(vcl_ostream &s, vul_arg<vcl_vector<int> > const &argmt)
00783 {
00784   for (unsigned int i=0; i<argmt().size(); ++i)
00785     s << ' ' << argmt()[i];
00786 }
00787 
00788 VDS int parse(vul_arg<vcl_vector<int> >* argmt, char ** argv)
00789 {
00790   vcl_list<int> tmp;
00791   int retval = list_parse(tmp,argv);
00792   // Defaults should be cleared when the user supplies a value
00793   argmt->value_.clear();
00794   for (vcl_list<int>::iterator i=tmp.begin(); i!=tmp.end(); ++i)
00795     argmt->value_.push_back( *i );
00796   return retval;
00797 }
00798 
00799 template class vul_arg<vcl_vector<int> >;
00800 
00801 //: vcl_vector<unsigned>
00802 VDS void settype(vul_arg<vcl_vector<unsigned> > &argmt) { argmt.type_="integer list"; }
00803 
00804 VDS void print_value(vcl_ostream &s, vul_arg<vcl_vector<unsigned> > const &argmt)
00805 {
00806   for (unsigned int i=0; i<argmt().size(); ++i)
00807     s << ' ' << argmt()[i];
00808 }
00809 
00810 VDS int parse(vul_arg<vcl_vector<unsigned> >* argmt, char ** argv)
00811 {
00812   vcl_list<int> tmp;
00813   int retval = list_parse(tmp,argv);
00814   // Defaults should be cleared when the user supplies a value
00815   argmt->value_.clear();
00816   for (vcl_list<int>::iterator i=tmp.begin(); i!=tmp.end(); ++i)
00817     argmt->value_.push_back( unsigned(*i) );
00818   return retval;
00819 }
00820 
00821 template class vul_arg<vcl_vector<unsigned> >;
00822 
00823 //: vcl_vector<double>
00824 VDS void settype(vul_arg<vcl_vector<double> > &argmt) {argmt.type_ = "double list";}
00825 
00826 VDS void print_value(vcl_ostream &s, vul_arg<vcl_vector<double> > const &argmt)
00827 {
00828   for (unsigned int i=0; i<argmt().size(); ++i)
00829     s << ' ' << argmt()[i];
00830 }
00831 
00832 VDS int parse(vul_arg<vcl_vector<double> >* argmt, char ** argv)
00833 {
00834   if ( !argv ||  !argv[0] ) {
00835     // no input
00836     vcl_cerr << "vul_arg_parse: Expected a vector of floating number, none is provided.\n";
00837     return -1;
00838   }
00839 
00840   // if true don't treat space separator as leading to another double.
00841   bool found_at_least_one_comma = false;
00842 
00843   int sucked = 0;
00844   // Defaults should be cleared when the user supplies a value
00845   argmt->value_.clear();
00846   char *current = argv[0];
00847   while (current) {
00848     char* endptr = 0;
00849     double tmp = vcl_strtod(current, &endptr);
00850     //argmt->value_
00851     if (*endptr == '\0') {
00852       argmt->value_.push_back(tmp);
00853       ++ sucked;
00854       ++ argv;
00855       if (found_at_least_one_comma) return sucked;
00856       current = argv[0];
00857     }
00858     else if (*endptr == ',')
00859     {
00860       found_at_least_one_comma = true;
00861       argmt->value_.push_back(tmp);
00862       current = endptr+1;
00863     }
00864     else if (endptr == current)
00865       break; // OK. end of list of doubles.
00866     else {
00867       // There is junk after the number, or no number was found
00868       vcl_cerr << "vul_arg_parse: WARNING: Attempt to parse " << current << " as double\n";
00869       return -1;
00870     }
00871   }
00872   return sucked;
00873 }
00874 
00875 template class vul_arg<vcl_vector<double> >;