WvStreams
wvargs.cc
00001 /* -*- Mode: C++ -*-
00002  *   Copyright (C) 2004-2005 Net Integration Technologies, Inc.
00003  *
00004  * WvStreams interface for command-line argument processing
00005  */
00006 
00007 #include "wvargs.h"
00008 #include "wvscatterhash.h"
00009 
00010 // Some screwy defines that show up in _WIN32 and cause problems
00011 #undef error_t
00012 #undef __error_t_defined
00013 #undef argc
00014 #undef argv
00015 #undef __argc
00016 #undef __argv
00017 
00018 #include <argp.h>
00019 #include <limits.h>
00020 
00021 
00022 class WvArgsOption
00023 {
00024 public:
00025 
00026     int short_option;
00027     WvString long_option;
00028     WvString desc;
00029 
00030     WvArgsOption(int _short_option,
00031                  WvStringParm _long_option,
00032                  WvStringParm _desc)
00033         : short_option(_short_option), long_option(_long_option), desc(_desc)
00034     {
00035     }
00036 
00037     virtual ~WvArgsOption()
00038     {
00039     }
00040 
00041     virtual WvString process(WvStringParm arg)
00042     {
00043         return WvString::null;
00044     }
00045 
00046     virtual void add_to_argp(WvArgsData &data);
00047 };
00048 
00049 
00050 DeclareWvList(WvArgsOption);
00051 DeclareWvScatterDict(WvArgsOption, int, short_option);
00052 
00053 class WvArgsData
00054 {
00055 public:
00056     WvArgsData();
00057     ~WvArgsData();
00058 
00059     argp_option *argp() const;
00060     void *self() const;
00061 
00062     void add(WvArgsOption *option);
00063     void remove(char short_option, WvStringParm long_option);
00064     void zap();
00065 
00066     void add_required_arg();
00067     void subtract_required_arg();
00068     const WvStringList &args() const;
00069 
00070     static error_t parser(int key, char *arg, argp_state *state);
00071 
00072     unsigned int flags;
00073 
00074 protected:
00075     friend class WvArgsOption;
00076     friend class WvArgsArgOption;
00077     friend class WvArgs;
00078 
00079     void argp_build();
00080     bool argp_add(const char *name, int key, const char *arg, int flags,
00081                   const char *doc, int group);
00082 private:
00083     void argp_init(size_t size = 0);
00084 
00085     bool argp_add(const argp_option &option);
00086     bool argp_double();
00087 
00088     argp_option *argp_;
00089     size_t argp_index;          // Last element in the options array
00090     size_t argp_size;           // Size of the options array
00091 
00092     // I create two data-structures, only one of them actually owning
00093     // the objects, of course.  The List is for ordered construction
00094     // of argp_.  The Dict is for constant-time lookups when
00095     // process()ing options.
00096     WvArgsOptionList options_list; // An ordered list of WvArgsOptions
00097     WvArgsOptionDict options_dict; // A constant-time lookup of them
00098 
00099     WvStringList args_;         // Arguments after all options have been parsed
00100     size_t required_args;       // Number of these mandatory arguments.
00101     size_t maximum_args;        // Number of maximum arguments.
00102 
00103     int last_no_key;            // Last key for options with no short_option
00104 };
00105 
00106 
00107 void WvArgsOption::add_to_argp(WvArgsData &data)
00108 {
00109     data.argp_add(long_option, short_option, 0, 0, desc, 0);
00110 }
00111 
00112 
00113 class WvArgsNoArgOption : public WvArgsOption
00114 {
00115 
00116 public:
00117 
00118     WvArgsNoArgOption(int _short_option,
00119                       WvStringParm _long_option,
00120                       WvStringParm _desc)
00121         : WvArgsOption(_short_option, _long_option, _desc)
00122     {
00123     }
00124 };
00125 
00126 
00127 class WvArgsSetBoolOption : public WvArgsNoArgOption
00128 {
00129 
00130 private:
00131 
00132     bool &flag;
00133 
00134 public:
00135 
00136     WvArgsSetBoolOption(int _short_option,
00137                         WvStringParm _long_option,
00138                         WvStringParm _desc,
00139                         bool &_flag)
00140         : WvArgsNoArgOption(_short_option, _long_option, _desc),
00141           flag(_flag)
00142     {
00143     }
00144 
00145     virtual WvString process(WvStringParm arg)
00146     {
00147         flag = true;
00148         return WvString::null;
00149     }
00150 };
00151 
00152 
00153 class WvArgsResetBoolOption : public WvArgsNoArgOption
00154 {
00155 
00156 private:
00157 
00158     bool &flag;
00159 
00160 public:
00161 
00162     WvArgsResetBoolOption(int _short_option,
00163                           WvStringParm _long_option,
00164                           WvStringParm _desc,
00165                           bool &_flag)
00166         : WvArgsNoArgOption(_short_option, _long_option, _desc),
00167           flag(_flag)
00168     {
00169     }
00170 
00171     virtual WvString process(WvStringParm arg)
00172     {
00173         flag = false;
00174         return WvString::null;
00175     }
00176 };
00177 
00178 
00179 class WvArgsFlipBoolOption : public WvArgsNoArgOption
00180 {
00181 
00182 private:
00183 
00184     bool &flag;
00185 
00186 public:
00187 
00188     WvArgsFlipBoolOption(int _short_option,
00189                          WvStringParm _long_option,
00190                          WvStringParm _desc,
00191                          bool &_flag)
00192         : WvArgsNoArgOption(_short_option, _long_option, _desc),
00193           flag(_flag)
00194     {
00195     }
00196 
00197     virtual WvString process(WvStringParm arg)
00198     {
00199         flag = !flag;
00200         return WvString::null;
00201     }
00202 };
00203 
00204 
00205 class WvArgsIncIntOption : public WvArgsNoArgOption
00206 {
00207 private:
00208     int &val;
00209 
00210 public:
00211     WvArgsIncIntOption(int _short_option,
00212                        WvStringParm _long_option,
00213                        WvStringParm _desc,
00214                        int &_val)
00215         : WvArgsNoArgOption(_short_option, _long_option, _desc),
00216           val(_val)
00217     {
00218     }
00219 
00220     virtual WvString process(WvStringParm arg)
00221     {
00222         val++;
00223         return WvString::null;
00224     }
00225 };
00226 
00227 
00228 class WvArgsNoArgCallbackOption : public WvArgsNoArgOption
00229 {
00230 
00231 private:
00232 
00233     WvArgs::NoArgCallback cb;
00234     void *ud;
00235 
00236 public:
00237 
00238     WvArgsNoArgCallbackOption(int _short_option,
00239                               WvStringParm _long_option,
00240                               WvStringParm _desc,
00241                               WvArgs::NoArgCallback _cb,
00242                               void *_ud)
00243         : WvArgsNoArgOption(_short_option, _long_option, _desc),
00244           cb(_cb), ud(_ud)
00245     {
00246     }
00247 
00248     virtual WvString process(WvStringParm arg)
00249     {
00250         if (cb(ud))
00251             return WvString::null;
00252         else
00253             return WvString("invalid option `%s'", arg);
00254     }
00255 };
00256 
00257 
00258 class WvArgsArgOption : public WvArgsOption
00259 {
00260 private:
00261 
00262     WvString arg_desc;
00263 
00264 public:
00265 
00266     WvArgsArgOption(int _short_option,
00267                     WvStringParm _long_option,
00268                     WvStringParm _desc,
00269                     WvStringParm _arg_desc)
00270         : WvArgsOption(_short_option, _long_option, _desc),
00271           arg_desc(_arg_desc)
00272     {
00273     }
00274 
00275     virtual void add_to_argp(WvArgsData &data)
00276     {
00277         data.argp_add(long_option, short_option, arg_desc, 0, desc, 0);
00278     }
00279 };
00280 
00281 
00282 class WvArgsIntOption : public WvArgsArgOption
00283 {
00284 private:
00285 
00286     int &val;
00287 
00288 public:
00289 
00290     WvArgsIntOption(int _short_option,
00291                     WvStringParm _long_option,
00292                     WvStringParm _desc,
00293                     WvStringParm _arg_desc,
00294                     int &_val)
00295         : WvArgsArgOption(_short_option, _long_option, _desc, _arg_desc),
00296           val(_val)
00297     {
00298     }
00299 
00300     virtual WvString process(WvStringParm arg)
00301     {
00302         char *tailptr = NULL;
00303         errno = 0;
00304         long int tmp = strtol(arg, &tailptr, 10);
00305         if (errno == ERANGE || tmp > INT_MAX || tmp < INT_MIN )
00306         {
00307             // Out of range
00308             return WvString("`%s': invalid number.", arg);
00309         }
00310         else if (*tailptr)
00311         {
00312             // Invalid number
00313             return WvString("`%s': invalid number.", arg);
00314         }
00315         else
00316         {
00317             val = tmp;
00318             return WvString::null;
00319         }
00320     }
00321 };
00322 
00323 
00324 class WvArgsLongOption : public WvArgsArgOption
00325 {
00326 private:
00327 
00328     long &val;
00329 
00330 public:
00331 
00332     WvArgsLongOption(int _short_option,
00333                      WvStringParm _long_option,
00334                      WvStringParm _desc,
00335                      WvStringParm _arg_desc,
00336                      long &_val)
00337         : WvArgsArgOption(_short_option, _long_option, _desc, _arg_desc),
00338           val(_val)
00339     {
00340     }
00341 
00342     virtual WvString process(WvStringParm arg)
00343     {
00344         char *tailptr = NULL;
00345         errno = 0;
00346         long int tmp = strtol(arg, &tailptr, 10);
00347         if (errno == ERANGE)
00348         {
00349             // Out of range
00350             return WvString("`%s': invalid number.", arg);
00351         }
00352         else if (*tailptr)
00353         {
00354             // Invalid number
00355             return WvString("`%s': invalid number.", arg);
00356         }
00357         else
00358         {
00359             val = tmp;
00360             return WvString::null;
00361         }
00362     }
00363 };
00364 
00365 
00366 class WvArgsFloatOption : public WvArgsArgOption
00367 {
00368 private:
00369 
00370     float &val;
00371 
00372 public:
00373 
00374     WvArgsFloatOption(int _short_option,
00375                       WvStringParm _long_option,
00376                       WvStringParm _desc,
00377                       WvStringParm _arg_desc,
00378                       float &_val)
00379         : WvArgsArgOption(_short_option, _long_option, _desc, _arg_desc),
00380           val(_val)
00381     {
00382     }
00383 
00384     virtual WvString process(WvStringParm arg)
00385     {
00386         char *tailptr = NULL;
00387         errno = 0;
00388         float tmp = strtof(arg, &tailptr);
00389         if (errno == ERANGE)
00390         {
00391             // Out of range
00392             return WvString("`%s': invalid number.", arg);
00393         }
00394         else if (*tailptr)
00395         {
00396             // Invalid number
00397             return WvString("`%s': invalid number.", arg);
00398         }
00399         else
00400         {
00401             val = tmp;
00402             return WvString::null;
00403         }
00404     }
00405 };
00406 
00407 
00408 class WvArgsDoubleOption : public WvArgsArgOption
00409 {
00410 private:
00411 
00412     double &val;
00413 
00414 public:
00415 
00416     WvArgsDoubleOption(int _short_option,
00417                        WvStringParm _long_option,
00418                        WvStringParm _desc,
00419                        WvStringParm _arg_desc,
00420                        double &_val)
00421         : WvArgsArgOption(_short_option, _long_option, _desc, _arg_desc),
00422           val(_val)
00423     {
00424     }
00425 
00426     virtual WvString process(WvStringParm arg)
00427     {
00428         char *tailptr = NULL;
00429         errno = 0;
00430         double tmp = strtod(arg, &tailptr);
00431         if (errno == ERANGE)
00432         {
00433             // Out of range
00434             return WvString("`%s': invalid number.", arg);
00435         }
00436         else if (*tailptr)
00437         {
00438             // Invalid number
00439             return WvString("`%s': invalid number.", arg);
00440         }
00441         else
00442         {
00443             val = tmp;
00444             return WvString::null;
00445         }
00446     }
00447 };
00448 
00449 
00450 class WvArgsStringOption : public WvArgsArgOption
00451 {
00452 private:
00453 
00454     WvString &val;
00455 
00456 public:
00457 
00458     WvArgsStringOption(int _short_option,
00459                        WvStringParm _long_option,
00460                        WvStringParm _desc,
00461                        WvStringParm _arg_desc,
00462                        WvString &_val)
00463         : WvArgsArgOption(_short_option, _long_option, _desc, _arg_desc),
00464           val(_val)
00465     {
00466     }
00467 
00468     virtual WvString process(WvStringParm arg)
00469     {
00470         val = arg;
00471         return WvString::null;
00472     }
00473 };
00474 
00475 
00476 class WvArgsStringListAppendOption : public WvArgsArgOption
00477 {
00478 private:
00479 
00480     WvStringList &val;
00481 
00482 public:
00483 
00484     WvArgsStringListAppendOption(int _short_option,
00485                                  WvStringParm _long_option,
00486                                  WvStringParm _desc,
00487                                  WvStringParm _arg_desc,
00488                                  WvStringList &_val)
00489         : WvArgsArgOption(_short_option, _long_option, _desc, _arg_desc),
00490           val(_val)
00491     {
00492     }
00493 
00494     virtual WvString process(WvStringParm arg)
00495     {
00496         val.append(arg);
00497         return WvString::null;
00498     }
00499 };
00500 
00501 
00502 class WvArgsArgCallbackOption : public WvArgsArgOption
00503 {
00504 private:
00505 
00506     WvArgs::ArgCallback cb;
00507     void *ud;
00508 
00509 public:
00510 
00511     WvArgsArgCallbackOption(int _short_option,
00512                             WvStringParm _long_option,
00513                             WvStringParm _desc,
00514                             WvStringParm _arg_desc,
00515                             WvArgs::ArgCallback _cb,
00516                             void *_ud)
00517         : WvArgsArgOption(_short_option, _long_option, _desc, _arg_desc),
00518           cb(_cb), ud(_ud)
00519     {
00520     }
00521 
00522     virtual WvString process(WvStringParm arg)
00523     {
00524         if (cb(arg, ud))
00525             return WvString::null;
00526         else
00527             return WvString("invalid option: `%s'", arg);
00528     }
00529 };
00530 
00531 
00532 WvArgsData::WvArgsData()
00533     : flags(0), argp_(NULL), argp_index(0), argp_size(0),
00534       required_args(0), maximum_args(0), last_no_key(-1)
00535 {
00536 }
00537 
00538 
00539 WvArgsData::~WvArgsData()
00540 {
00541     if (argp_)
00542         free(argp_);
00543 }
00544 
00545 
00546 argp_option *WvArgsData::argp() const
00547 {
00548     return argp_;
00549 }
00550 
00551 
00552 void *WvArgsData::self() const
00553 {
00554     return (void *)this;
00555 }
00556 
00557 
00558 void WvArgsData::add(WvArgsOption *option)
00559 {
00560     if (!option)
00561         return;
00562 
00563     if (!option->short_option)
00564         option->short_option = last_no_key--;
00565 
00566     options_list.append(option, true);
00567     options_dict.add(option, false);
00568 }
00569 
00570 
00571 // This method removes both short_option and long_option from the
00572 // options_* structures.  Completely.
00573 void WvArgsData::remove(char short_option, WvStringParm long_option)
00574 {
00575     // First, look through options_list, and remove them from
00576     // options_dict once we find them.
00577     WvArgsOptionList::Iter i(options_list);
00578     for (i.rewind(); i.next(); )
00579     {
00580         bool matches_short = false;
00581         bool matches_long = false;
00582 
00583         if (short_option != '\0' && i->short_option == short_option)
00584             matches_short = true;
00585         if (!long_option.isnull() && i->long_option == long_option)
00586             matches_long = true;
00587 
00588         if (matches_short && matches_long
00589             || matches_short && i->long_option.isnull()
00590             || matches_long && i->short_option == '\0')
00591         {
00592             // Delete this item from the data-structures
00593             options_dict.remove(i.ptr());
00594             i.xunlink();
00595             if (argp_)
00596             {
00597                 free(argp_);
00598                 argp_ = NULL;
00599             }
00600         }
00601         else if (matches_short)
00602         {
00603             // Update the short description and change how it's filed
00604             // in the dictionary.
00605             i->short_option = '\0';
00606             options_dict.remove(i.ptr());
00607             options_dict.add(i.ptr(), false);
00608         }
00609         else if (matches_long)
00610         {
00611             // Update the long description only
00612             i->long_option = WvString::null;
00613         }
00614     }
00615 }
00616 
00617 
00618 void WvArgsData::zap()
00619 {
00620     options_dict.zap();
00621     options_list.zap();
00622 
00623     if (argp_)
00624     {
00625         free(argp_);
00626         argp_ = NULL;
00627     }
00628 }
00629 
00630 
00631 void WvArgsData::argp_init(size_t size)
00632 {
00633     argp_size = size;
00634     if (argp_size < 1)
00635         argp_size = 1;
00636 
00637     // I'm sorry to use malloc(), but this argp is a C library
00638     argp_ = (argp_option *)malloc(argp_size * sizeof(argp_option));
00639     // Terminate the empty array
00640     memset(argp_, 0, sizeof(argp_option));
00641 }
00642 
00643 
00644 void WvArgsData::argp_build()
00645 {
00646     if (!argp_)
00647         argp_init(options_list.count() + 2);
00648 
00649     WvArgsOptionList::Iter i(options_list);
00650     for (i.rewind(); i.next(); )
00651         i->add_to_argp(*this);
00652 }
00653 
00654 
00655 bool WvArgsData::argp_add(const argp_option &option)
00656 {
00657     if (argp_index >= (argp_size - 1))
00658     {
00659         if (!argp_double())
00660             return false;
00661     }
00662 
00663     // Make a copy of the option that we're building.
00664     memcpy(argp_ + argp_index, &option, sizeof(argp_option));
00665     // Terminate the array.
00666     ++argp_index;
00667     memset(argp_ + argp_index, 0, sizeof(argp_option));
00668     return true;
00669 }
00670 
00671 
00672 bool WvArgsData::argp_add(const char *name, int key, const char *arg,
00673                           int flags, const char *doc, int group)
00674 {
00675     if (argp_index >= (argp_size - 1))
00676     {
00677         if (!argp_double())
00678             return false;
00679     }
00680 
00681     // Set the elements.
00682     argp_option *option = argp_ + argp_index;
00683     option->name = name;
00684     option->key = key;
00685     option->arg = arg;
00686     option->flags = flags;
00687     option->doc = doc;
00688     option->group = group;
00689     // Terminate the array.
00690     ++argp_index;
00691     memset(argp_ + argp_index, 0, sizeof(argp_option));
00692     return true;
00693 }
00694 
00695 
00696 bool WvArgsData::argp_double()
00697 {
00698     // We won't be able to fit the next entry into the array
00699     void *tmp = realloc(argp_, 2 * argp_size * sizeof(argp_option));
00700     if (!tmp)
00701         return false;
00702 
00703     argp_ = (argp_option *)tmp;
00704     argp_size *= 2;
00705     return true;
00706 }
00707 
00708 
00709 void WvArgsData::add_required_arg()
00710 {
00711     ++required_args;
00712 }
00713 
00714 
00715 void WvArgsData::subtract_required_arg()
00716 {
00717     --required_args;
00718 }
00719 
00720 
00721 const WvStringList &WvArgsData::args() const
00722 {
00723     return args_;
00724 }
00725 
00726 
00727 error_t WvArgsData::parser(int key, char *arg, struct argp_state *state)
00728 {
00729     WvArgsData *data = (WvArgsData *)state->input;
00730 
00731     switch (key)
00732     {
00733     case ARGP_KEY_ARG:
00734         if (state->arg_num >= data->maximum_args)
00735         {
00736             // Too many arguments
00737             argp_usage(state);
00738         }
00739         data->args_.append(arg);
00740         break;
00741 
00742     case ARGP_KEY_NO_ARGS:
00743     case ARGP_KEY_END:
00744         if (state->arg_num < data->required_args)
00745         {
00746             // Too few arguments
00747             argp_usage(state);
00748         }
00749         break;
00750 
00751     default:
00752         WvArgsOption *option = data->options_dict[key];
00753         if (option)
00754         {
00755             WvString error = option->process(arg);
00756             if (!error.isnull())
00757             {
00758                 argp_failure(state, argp_err_exit_status, 0,
00759                              "%s", error.cstr());
00760                 return EINVAL;
00761             }
00762         }
00763         else
00764             return ARGP_ERR_UNKNOWN;
00765     }
00766 
00767     return 0;
00768 }
00769 
00770 
00771 WvArgs::WvArgs()
00772     : data(new WvArgsData())
00773 {
00774 }
00775 
00776 
00777 WvArgs::~WvArgs()
00778 {
00779     if (data)
00780         delete data;
00781 }
00782 
00783 
00784 bool WvArgs::process(int argc, char **argv, WvStringList *remaining_args)
00785 {
00786     if (!data->argp())
00787         data->argp_build();
00788 
00789     // Setup --help headers and footers
00790     WvString prog_doc;
00791     if (header && footer)
00792         prog_doc = WvString("%s\v%s", header, footer);
00793     else if (header)
00794         prog_doc = WvString("%s", header);
00795     else if (footer)
00796         prog_doc = WvString(" \v%s", footer);
00797 
00798     // Setup the constant version number and e-mail address
00799     argp_program_version = version;
00800     argp_program_bug_address = email;
00801 
00802     struct argp argp = { data->argp(), &WvArgsData::parser, args_doc, prog_doc,
00803                          0, 0, 0 };
00804 
00805     bool error = argp_parse(&argp, argc, argv, data->flags, 0, data->self());
00806 
00807     if (remaining_args)
00808     {
00809         remaining_args->zap();
00810         WvStringList::Iter i(data->args());
00811         for (i.rewind(); i.next(); )
00812             remaining_args->add(new WvString(*i), true);
00813     }
00814 
00815     return !error;
00816 }
00817 
00818 
00819 void WvArgs::set_version(WvStringParm version)
00820 {
00821     this->version = version;
00822 }
00823 
00824 
00825 void WvArgs::set_email(WvStringParm email)
00826 {
00827     this->email = email;
00828 }
00829 
00830 
00831 void WvArgs::set_help_header(WvStringParm header)
00832 {
00833     this->header = header;
00834 }
00835 
00836 
00837 void WvArgs::set_help_footer(WvStringParm footer)
00838 {
00839     this->footer = footer;
00840 }
00841 
00842 
00843 void WvArgs::print_usage(int argc, char **argv)
00844 {
00845     struct argp argp = { data->argp(), 0, 0, 0, 0, 0, 0 };
00846     argp_help(&argp, stdout, ARGP_HELP_STD_USAGE, argv[0]);
00847 }
00848 
00849 
00850 void WvArgs::print_help(int argc, char **argv)
00851 {
00852     struct argp argp = { data->argp(), 0, 0, 0, 0, 0, 0 };
00853     argp_help(&argp, stdout, ARGP_HELP_STD_HELP, argv[0]);
00854 }
00855 
00856 void WvArgs::add_set_bool_option(char short_option, WvStringParm long_option,
00857                                  WvStringParm desc, bool &val)
00858 {
00859     data->remove(short_option, long_option);
00860     data->add(new WvArgsSetBoolOption(short_option, long_option, desc, val));
00861 }
00862 
00863 
00864 void WvArgs::add_reset_bool_option(char short_option, WvStringParm long_option,
00865                                    WvStringParm desc, bool &val)
00866 {
00867     data->remove(short_option, long_option);
00868     data->add(new WvArgsResetBoolOption(short_option, long_option, desc, val));
00869 }
00870 
00871 
00872 void WvArgs::add_flip_bool_option(char short_option, WvStringParm long_option,
00873                                   WvStringParm desc, bool &val)
00874 {
00875     data->remove(short_option, long_option);
00876     data->add(new WvArgsFlipBoolOption(short_option, long_option, desc, val));
00877 }
00878 
00879 
00880 void WvArgs::add_option(char short_option, WvStringParm long_option,
00881                         WvStringParm desc, NoArgCallback cb, void *ud)
00882 {
00883     data->remove(short_option, long_option);
00884     data->add(new WvArgsNoArgCallbackOption(short_option, long_option, desc,
00885                                             cb, ud));
00886 }
00887 
00888 void WvArgs::add_option(char short_option, WvStringParm long_option,
00889                         WvStringParm desc, WvStringParm arg_desc, int &val)
00890 {
00891     data->remove(short_option, long_option);
00892     data->add(new WvArgsIntOption(short_option, long_option, desc, arg_desc,
00893                                   val));
00894 }
00895 
00896 void WvArgs::add_option(char short_option, WvStringParm long_option,
00897                         WvStringParm desc, WvStringParm arg_desc, long &val)
00898 {
00899     data->remove(short_option, long_option);
00900     data->add(new WvArgsLongOption(short_option, long_option, desc, arg_desc,
00901                                    val));
00902 }
00903 
00904 void WvArgs::add_option(char short_option, WvStringParm long_option,
00905                         WvStringParm desc, WvStringParm arg_desc, float &val)
00906 {
00907     data->remove(short_option, long_option);
00908     data->add(new WvArgsFloatOption(short_option, long_option, desc, arg_desc,
00909                                     val));
00910 }
00911 
00912 void WvArgs::add_option(char short_option, WvStringParm long_option,
00913                         WvStringParm desc, WvStringParm arg_desc, double &val)
00914 {
00915     data->remove(short_option, long_option);
00916     data->add(new WvArgsDoubleOption(short_option, long_option, desc,
00917                                      arg_desc, val));
00918 }
00919 
00920 void WvArgs::add_option(char short_option, WvStringParm long_option,
00921                         WvStringParm desc, WvStringParm arg_desc,
00922                         WvString &val)
00923 {
00924     data->remove(short_option, long_option);
00925     data->add(new WvArgsStringOption(short_option, long_option, desc,
00926                                      arg_desc, val));
00927 }
00928 
00929 void WvArgs::add_option(char short_option, WvStringParm long_option,
00930                         WvStringParm desc, WvStringParm arg_desc,
00931                         WvStringList &val)
00932 {
00933     data->remove(short_option, long_option);
00934     data->add(new WvArgsStringListAppendOption(short_option, long_option,
00935                                                desc, arg_desc, val));
00936 }
00937 
00938 void WvArgs::add_option(char short_option, WvStringParm long_option,
00939                         WvStringParm desc, WvStringParm arg_desc,
00940                         ArgCallback cb, void *ud)
00941 {
00942     data->remove(short_option, long_option);
00943     data->add(new WvArgsArgCallbackOption(short_option, long_option, desc,
00944                                           arg_desc, cb, ud));
00945 }
00946 
00947 
00948 void WvArgs::remove_option(char short_option)
00949 {
00950     data->remove(short_option, WvString::null);
00951 }
00952 
00953 
00954 void WvArgs::remove_option(WvStringParm long_option)
00955 {
00956     data->remove(0, long_option);
00957 }
00958 
00959 
00960 void WvArgs::remove_all_options()
00961 {
00962     data->zap();
00963 }
00964 
00965 
00966 void WvArgs::add_required_arg(WvStringParm desc, bool multiple)
00967 {
00968     data->add_required_arg();
00969     if (!!args_doc)
00970         args_doc.append(" ");
00971     args_doc.append(desc);
00972     if (multiple)
00973     {
00974         args_doc.append("...");
00975         data->maximum_args = LONG_MAX;
00976     }
00977     else if (data->maximum_args < LONG_MAX)
00978         ++(data->maximum_args);
00979 }
00980 
00981 
00982 void WvArgs::add_optional_arg(WvStringParm desc, bool multiple)
00983 {
00984     // an optional arg is a required arg without the requirement :-)
00985     add_required_arg(WvString("[%s]", desc), multiple);
00986     data->subtract_required_arg();
00987 }
00988 
00989 
00990 bool WvArgs::get_flag(const flags_t flag) const
00991 {
00992     switch (flag)
00993     {
00994     case NO_EXIT_ON_ERRORS:
00995         return data->flags & ARGP_NO_EXIT;
00996     default:
00997         return false;
00998     }
00999 }
01000 
01001 
01002 void WvArgs::set_flag(const flags_t flag, const bool value)
01003 {
01004     printf("set_flag(%d, %d)\n", flag, value);
01005     unsigned int mask;
01006     switch (flag)
01007     {
01008     case NO_EXIT_ON_ERRORS:
01009         mask = ARGP_NO_EXIT;
01010         break;
01011     default:
01012         return;
01013     }
01014 
01015     if (value)
01016         data->flags |= mask;
01017     else
01018         data->flags &= ~mask;
01019 
01020     printf("set_flag(%d, %d) = %d\n", flag, value, data->flags);
01021 }