home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / cmdline.lha / cmdline / src / lib / cmdargs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-13  |  16.4 KB  |  651 lines

  1. //------------------------------------------------------------------------
  2. // ^FILE: cmdargs.c - implement the various predefined CmdArg subclasses
  3. //
  4. // ^DESCRIPTION:
  5. //    This file implements the CmdArg derived classes that are declared
  6. //    in <cmdargs.h>
  7. //
  8. // ^HISTORY:
  9. //    03/25/92    Brad Appleton    <brad@ssd.csd.harris.com>    Created
  10. //
  11. //    03/03/93    Brad Appleton    <brad@ssd.csd.harris.com>
  12. //    - Added exit_handler() and quit() member-functions to CmdLine
  13. //-^^---------------------------------------------------------------------
  14.  
  15. #include <stdlib.h>
  16. #include <iostream.h>
  17. #include <string.h>
  18. #include <ctype.h>
  19.  
  20. #include "cmdargs.h"
  21. #include "exits.h"
  22. #include "fifolist.h"
  23.  
  24.    // return values for operator()
  25. enum { SUCCESS = 0, FAILURE = -1 } ;
  26.  
  27.  
  28. //-----------------------------------------------------------------------------
  29. // ^FUNCTION: compile, operator() - handle an argument from the command-line
  30. //
  31. // ^SYNOPSIS:
  32. //    int  operator()(arg, cmd);
  33. //    int  compile(arg, cmd, value);
  34. //    int  compile(arg, cmd, value, default_value);
  35. //
  36. // ^PARAMETERS:
  37. //    const char * & arg;
  38. //    -- the prospective value for this command argument.
  39. //       upon returning this value should be updated to point to the first
  40. //       character of "arg" that was NOT used as part of the value for this
  41. //       argument (set "arg" to NULL if all of it was used).
  42. //
  43. //    CmdLine & cmd;
  44. //    -- the command that matched this argument on its command-line
  45. //
  46. //    <Type> & value;
  47. //    -- The internal value (of some appropriate type) that is "managed"
  48. //       by this command argument.
  49. //
  50. //    unsigned  default_value;
  51. //    -- What to assign to "value" if "arg" is NOT a value for this command
  52. //       argument.
  53. //
  54. // ^DESCRIPTION:
  55. //    These member functions are responsible for taking whatever action
  56. //    is appropriate when its corresponding command argument is matched
  57. //    on the command-line.  For argument-types that simply "compile"
  58. //    their argument into some kind of internal value, "compile()" does
  59. //    all the work and operator() merely calls compile() with the proper
  60. //    value as a reference parameter.
  61. //
  62. // ^REQUIREMENTS:
  63. //    The "arg_flags" data member of this command-argument must have been
  64. //    set appropriately (by "cmd") to indicate to us exactly how "arg" was
  65. //    specified on the command-line for this (and only this) occurrence of
  66. //    "arg".
  67. //
  68. // ^SIDE-EFFECTS:
  69. //    - If (cmd.flags() & QUIET) is NOT TRUE and FAILURE is to be returned,
  70. //      then error messages should be printed using cmd.error().
  71. //
  72. //    - arg is modified to be NULL of to point to the unused portion of itself.
  73. //      
  74. //    - If (cmd.flags() & TEMP) is TRUE and we need the value of "arg"
  75. //      to stick around, then storage is allocated in order to make
  76. //      a copy of "arg" (and the command-argument is responsible for
  77. //      de-allocating this storage).
  78. //
  79. // ^RETURN-VALUE:
  80. //    FAILURE (non-zero)  If something went wrong when performing the
  81. //                        desired actions for this command-argument.
  82. //                        A common problem would be that "arg" is
  83. //                        syntactically incorrect.
  84. //
  85. //    SUCCESS (zero)  If "arg" is NULL and/or we were able to succesfully
  86. //                    perform all desired actions for this command argument.
  87. //-^^--------------------------------------------------------------------------
  88.  
  89.  
  90. //-------------------------------------------------------------- Dummy Argument
  91.  
  92. CmdArgDummy::~CmdArgDummy(void)  {}
  93.  
  94. int
  95. CmdArgDummy::is_dummy(void)  { return  1; }
  96.  
  97.    // For a CmdArgDummy - operator() is a No-OP and should NEVER
  98.    // be called.
  99.    //
  100. int
  101. CmdArgDummy::operator()(const char * & , CmdLine & )
  102. {
  103.    return  SUCCESS;
  104. }
  105.  
  106. //-------------------------------------------------------------- Usage Argument
  107.  
  108. CmdArgUsage::~CmdArgUsage(void)  {}
  109.  
  110.    // Just need to call cmd.usage and exit.
  111.    //
  112. int
  113. CmdArgUsage::operator()(const char * & , CmdLine & cmd)
  114. {
  115.    cmd.usage(cmd.error(CmdLine::NOPRINT), CmdLine::VERBOSE_USAGE);
  116.    cmd.quit(e_USAGE);
  117.    return  SUCCESS;
  118. }
  119.  
  120. //----------------------------------------------------------- Integer Arguments
  121.  
  122. CmdArgIntCompiler::~CmdArgIntCompiler(void)  {}
  123.  
  124.    // Compile a string into an integer value.
  125. int
  126. CmdArgIntCompiler::compile(const char * & arg, CmdLine & cmd, int & value)
  127. {
  128.    const char * ptr = NULL ;
  129.    long  result = 0 ;
  130.  
  131.    if (arg == NULL) {
  132.       return  SUCCESS ;  // no value given - nothing to do
  133.    } else if (! *arg) {
  134.       if (! (cmd.flags() & CmdLine::QUIET)) {
  135.          cmd.error() << "empty integer value specified." << endl ;
  136.       }
  137.       return  FAILURE ;
  138.    }
  139.  
  140.    // compile the string into an integer
  141.    result = ::strtol(arg, (char **) &ptr, 0);  // watch out for -c0xa vs -axc0!
  142.    if (ptr == arg) {
  143.       // do we have a valid integer?
  144.       if (! (cmd.flags() & CmdLine::QUIET)) {
  145.          cmd.error() << "invalid integer value \"" << arg << "\"." << endl ;
  146.       }
  147.       return  FAILURE ;
  148.    }
  149.    value = (int) result;
  150.    arg = ptr;
  151.  
  152.    return  SUCCESS ;
  153. }
  154.  
  155.  
  156. CmdArgInt::~CmdArgInt(void)  {}
  157.  
  158. int
  159. CmdArgInt::operator()(const char * & arg, CmdLine & cmd)
  160. {
  161.    return  compile(arg, cmd, val);
  162. }
  163.  
  164.  
  165. ostream &
  166. operator<<(ostream & os, const CmdArgInt & int_arg)
  167. {
  168.    return  (os << (int) int_arg) ;
  169. }
  170.  
  171. //---------------------------------------------------- Floating-point Arguments
  172.  
  173. CmdArgFloatCompiler::~CmdArgFloatCompiler(void)  {}
  174.  
  175.    // Compile a string into a floating-point value.
  176. int
  177. CmdArgFloatCompiler::compile(const char * & arg, CmdLine & cmd, float & value)
  178. {
  179.    const char * ptr = NULL ;
  180.    double  result = 0 ;
  181.  
  182.    if (arg == NULL) {
  183.       return  SUCCESS ;  // no value given -- nothing to do
  184.    } else if (! *arg) {
  185.       if (! (cmd.flags() & CmdLine::QUIET)) {
  186.          cmd.error() << "empty floating-point value specified." << endl ;
  187.       }
  188.       return  FAILURE ;
  189.    }
  190.  
  191.    result = ::strtod(arg, (char **) &ptr);  // compile the string into a float
  192.    if (ptr == arg) {
  193.       // do we have a valid float?
  194.       if (! (cmd.flags() & CmdLine::QUIET)) {
  195.          cmd.error() << "invalid floating-point value \"" << arg << "\"."
  196.                      << endl ;
  197.       }
  198.       return  FAILURE ;
  199.    }
  200.    value = (float) result;
  201.    arg = ptr;
  202.  
  203.    return  SUCCESS ;
  204. }
  205.  
  206.  
  207. CmdArgFloat::~CmdArgFloat(void)  {}
  208.  
  209. int
  210. CmdArgFloat::operator()(const char * & arg, CmdLine & cmd)
  211. {
  212.    return  compile(arg, cmd, val);
  213. }
  214.  
  215.  
  216. ostream &
  217. operator<<(ostream & os, const CmdArgFloat & float_arg)
  218. {
  219.    return  (os << (float) float_arg) ;
  220. }
  221.  
  222. //--------------------------------------------------------- Character Argumrnts
  223.  
  224. CmdArgCharCompiler::~CmdArgCharCompiler(void)  {}
  225.  
  226. int
  227. CmdArgCharCompiler::compile(const char * & arg, CmdLine & cmd, char & value)
  228. {
  229.    if (arg == NULL) {
  230.       return  SUCCESS ;  // no value given - nothing to do
  231.    }
  232.  
  233.    // If "arg" contains more than 1 character, then the other characters
  234.    // are either extraneous, or they are options (bundled together).
  235.    //
  236.    if (*arg  &&  *(arg+1)  &&
  237.         ((! (flags() & CmdArg::OPTION)) || (flags() & CmdArg::VALSEP)))
  238.    {
  239.       if (! (cmd.flags() & CmdLine::QUIET)) {
  240.          cmd.error() << "invalid character value \"" << arg << "\"." << endl ;
  241.       }
  242.       return  FAILURE ;
  243.    }
  244.  
  245.    value = *arg;
  246.    if (*arg) {
  247.       ++arg;
  248.    } else {
  249.       arg = NULL;
  250.    }
  251.  
  252.    return  SUCCESS ;
  253. }
  254.  
  255.  
  256. CmdArgChar::~CmdArgChar(void)  {}
  257.  
  258. int
  259. CmdArgChar::operator()(const char * & arg, CmdLine & cmd)
  260. {
  261.    return  compile(arg, cmd, val);
  262. }
  263.  
  264. ostream &
  265. operator<<(ostream & os, const CmdArgChar & char_arg)
  266. {
  267.    return  (os << (char) char_arg) ;
  268. }
  269.  
  270. //------------------------------------------------------------ String Arguments
  271.  
  272. typedef  CmdArgStrCompiler::casc_string  CmdArgString ;
  273.  
  274. #ifndef __gplusplus
  275. CmdArgString::~casc_string(void)
  276. {
  277.    if (is_alloc)  delete [] (char *)str;
  278. }
  279. #endif 
  280.  
  281.    // Copy a string (allocating storage if necessary)
  282. void
  283. CmdArgString::copy(unsigned  is_temporary, const char * s)
  284. {
  285.    if (is_alloc)  delete [] (char *)str;
  286.    is_alloc = (is_temporary) ? 1 : 0;
  287.    str = s;
  288.    if (is_alloc && s) {
  289.       char * new_s = new char[::strlen(s) + 1] ;
  290.       (void) ::strcpy(new_s, s);
  291.       str = new_s;
  292.    }
  293. }
  294.  
  295.  
  296. CmdArgStrCompiler::~CmdArgStrCompiler(void)  {}
  297.  
  298. int
  299. CmdArgStrCompiler::compile(const char  * & arg,
  300.                            CmdLine       & cmd,
  301.                            CmdArgString  & value)
  302. {
  303.    if (arg == NULL) {
  304.       return  SUCCESS;  // no value given -- nothing to do
  305.    }
  306.  
  307.    value.copy((cmd.flags() & CmdLine::TEMP), arg);
  308.    arg = NULL;
  309.  
  310.    return  SUCCESS;
  311. }
  312.  
  313.  
  314. CmdArgStr::~CmdArgStr(void)  {}
  315.  
  316. int
  317. CmdArgStr::operator()(const char * & arg, CmdLine & cmd)
  318. {
  319.    return  compile(arg, cmd, val);
  320. }
  321.  
  322. ostream &
  323. operator<<(ostream & os, const CmdArgStrCompiler::casc_string & str)
  324. {
  325.    return  (os << str.str) ;
  326. }
  327.  
  328. ostream &
  329. operator<<(ostream & os, const CmdArgStr & str_arg)
  330. {
  331.    return  (os << (const char *) str_arg) ;
  332. }
  333.  
  334. //-------------------------------------------------------------- List Arguments
  335.  
  336.           //------------------- Integer List -------------------
  337.  
  338. DECLARE_FIFO_LIST(IntList, int);
  339.  
  340. struct CmdArgIntListPrivate {
  341.    IntList       list;
  342.    IntListArray  array;
  343.  
  344.    CmdArgIntListPrivate(void);
  345. } ;
  346.  
  347.  
  348. CmdArgIntListPrivate::CmdArgIntListPrivate(void)
  349.    : array(list)
  350. {
  351.    list.self_cleaning(1);
  352. }
  353.  
  354.    // Compile the argument into an integer and append it to the list
  355. int
  356. CmdArgIntList::operator()(const char * & arg, CmdLine & cmd)
  357. {
  358.    int  value;
  359.    const char * save_arg = arg;
  360.    int  rc = compile(arg, cmd, value);
  361.    if (save_arg && (rc == SUCCESS)) {
  362.       if (val == NULL)  val = new CmdArgIntListPrivate;
  363.       int * new_value = new int;
  364.       *new_value = value;
  365.       val->list.add(new_value);
  366.    }
  367.    return  rc;
  368. }
  369.  
  370. unsigned
  371. CmdArgIntList::count(void) const
  372. {
  373.    return  (val) ? val->list.count() : 0 ;
  374. }
  375.  
  376. int &
  377. CmdArgIntList::operator[](unsigned  index)
  378. {
  379.    return  val->array[index];
  380. }
  381.  
  382. CmdArgIntList::~CmdArgIntList(void) {}
  383.  
  384.  
  385.           //------------------- Float List -------------------
  386.  
  387.  
  388. DECLARE_FIFO_LIST(FloatList, float);
  389.  
  390. struct CmdArgFloatListPrivate {
  391.    FloatList       list;
  392.    FloatListArray  array;
  393.  
  394.    CmdArgFloatListPrivate(void);
  395. } ;
  396.  
  397. CmdArgFloatListPrivate::CmdArgFloatListPrivate(void)
  398.    : array(list)
  399. {
  400.    list.self_cleaning(1);
  401. }
  402.  
  403.  
  404.    // Compile the argument into a float and append it to the list
  405. int
  406. CmdArgFloatList::operator()(const char * & arg, CmdLine & cmd)
  407. {
  408.    float  value;
  409.    const char * save_arg = arg;
  410.    int  rc = compile(arg, cmd, value);
  411.    if (save_arg && (rc == SUCCESS)) {
  412.       if (val == NULL)  val = new CmdArgFloatListPrivate;
  413.       float * new_value = new float;
  414.       *new_value = value;
  415.       val->list.add(new_value);
  416.    }
  417.    return  rc;
  418. }
  419.  
  420. unsigned
  421. CmdArgFloatList::count(void) const
  422. {
  423.    return  (val) ? val->list.count() : 0 ;
  424. }
  425.  
  426. float &
  427. CmdArgFloatList::operator[](unsigned  index)
  428. {
  429.    return  val->array[index];
  430. }
  431.  
  432. CmdArgFloatList::~CmdArgFloatList(void) {}
  433.  
  434.           //------------------- String List -------------------
  435.  
  436. DECLARE_FIFO_LIST(StringList, CmdArgString);
  437.  
  438. struct CmdArgStrListPrivate {
  439.    StringList       list;
  440.    StringListArray  array;
  441.  
  442.    CmdArgStrListPrivate(void);
  443. } ;
  444.  
  445. CmdArgStrListPrivate::CmdArgStrListPrivate(void)
  446.    : array(list)
  447. {
  448.    list.self_cleaning(1);
  449. }
  450.  
  451. int
  452. CmdArgStrList::operator()(const char * & arg, CmdLine & cmd)
  453. {
  454.    CmdArgString * value = new CmdArgString ;
  455.    const char * save_arg = arg;
  456.    int  rc = compile(arg, cmd, *value);
  457.    if (save_arg && (rc == SUCCESS)) {
  458.       if (val == NULL)  val = new CmdArgStrListPrivate;
  459.       val->list.add(value);
  460.    } else {
  461.       delete  value;
  462.    }
  463.    return  rc;
  464. }
  465.  
  466. unsigned
  467. CmdArgStrList::count(void) const
  468. {
  469.    return  (val) ? val->list.count() : 0 ;
  470. }
  471.  
  472. CmdArgString &
  473. CmdArgStrList::operator[](unsigned  index)
  474. {
  475.    return  val->array[index];
  476. }
  477.  
  478. CmdArgStrList::~CmdArgStrList(void) {}
  479.  
  480. //----------------------------------------------------------- Boolean Arguments
  481.  
  482. CmdArgBoolCompiler::~CmdArgBoolCompiler(void)  {}
  483.  
  484. int
  485. CmdArgBoolCompiler::compile(const char  * & arg,
  486.                             CmdLine       & cmd,
  487.                             unsigned      & value,
  488.                             unsigned        default_value)
  489. {
  490.    if (arg == NULL) {
  491.          // if no argument was given use the default
  492.       value = default_value ;
  493.    } else {
  494.       char ch = *arg;
  495.       const char * kwd = arg++;
  496.  
  497.          // Map the argument to the corresponding value. We will accept
  498.          // the following (case insensitive):
  499.          //
  500.          //     "+", "1", "ON", or "YES"  means set the value
  501.          //     "-", "0", "OFF", or "NO"  means clear the value
  502.          //     "~", "^", or "!" means toggle the value
  503.          //
  504.          // Anything else is considered to be an argument that is NOT
  505.          // meant for us but for some other argument so we just use the
  506.          // default value that was supplied and return SUCCESS.
  507.          //
  508.       if (isupper(ch))  ch = tolower(ch);
  509.       switch(ch) {
  510.          case '1' :
  511.          case '+' : value = 1 ; break;
  512.  
  513.          case '0' :
  514.          case '-' : value = 0 ; break;
  515.  
  516.          case '~' :
  517.          case '^' :
  518.          case '!' : value = (! value) ; break;
  519.  
  520.          default:
  521.             if (flags() & CmdArg::KEYWORD) {
  522.                char ch2 = *arg;
  523.                arg = NULL;
  524.                if (cmd.strmatch(kwd, "yes") != CmdLine::str_NONE) {
  525.                   value = 1 ;
  526.                   return  SUCCESS ;
  527.                } else if (cmd.strmatch(kwd, "no") != CmdLine::str_NONE) {
  528.                   value = 0 ;
  529.                   return  SUCCESS ;
  530.                } else if (cmd.strmatch(kwd, "true") != CmdLine::str_NONE) {
  531.                   value = 1 ;
  532.                   return  SUCCESS ;
  533.                } else if (cmd.strmatch(kwd, "false") != CmdLine::str_NONE) {
  534.                   value = 0 ;
  535.                   return  SUCCESS ;
  536.                } else if ((ch == 'o') && (! ch2)) {
  537.                   // ambiguous - could be "ON" or "OFF"
  538.                   if (! (cmd.flags() & CmdLine::QUIET)) {
  539.                      cmd.error() << "ambiguous boolean value \"" << kwd
  540.                                  << "\"." << endl ;
  541.                   }
  542.                   return  FAILURE ;
  543.                } else if (cmd.strmatch(kwd, "on") != CmdLine::str_NONE) {
  544.                   value = 1 ;
  545.                   return  SUCCESS ;
  546.                } else if (cmd.strmatch(kwd, "off") != CmdLine::str_NONE) {
  547.                   value = 0 ;
  548.                   return  SUCCESS ;
  549.                } else {
  550.                   // unknown
  551.                   if (! (cmd.flags() & CmdLine::QUIET)) {
  552.                      cmd.error() << "unknown boolean value \"" << kwd
  553.                                  << "\"." << endl ;
  554.                   }
  555.                   return  FAILURE ;
  556.                }
  557.             } //if keyword
  558.             arg = kwd;  // no characters used!
  559.             value = default_value ;
  560.             break;
  561.       } //switch
  562.    } //else
  563.  
  564.    return  SUCCESS ;
  565. }
  566.  
  567. ostream &
  568. operator<<(ostream & os, const CmdArgBool & bool_arg)
  569. {
  570.    return  (os << ((int)bool_arg)) ;
  571. }
  572.  
  573. //------------------------------------------------------------------ CmdArgBool
  574.  
  575. CmdArgBool::~CmdArgBool(void)  {}
  576.  
  577. int
  578. CmdArgBool::operator()(const char * & arg, CmdLine & cmd)
  579. {
  580.    unsigned  value = val;
  581.    int  rc = compile(arg, cmd, value, 1);
  582.    val = value;
  583.    return  rc;
  584. }
  585.  
  586. //----------------------------------------------------------------- CmdArgClear
  587.  
  588. CmdArgClear::~CmdArgClear(void)  {}
  589.  
  590. int
  591. CmdArgClear::operator()(const char * & arg, CmdLine & cmd)
  592. {
  593.    unsigned  value = val;
  594.    int  rc = compile(arg, cmd, value, 0);
  595.    val = value;
  596.    return  rc;
  597. }
  598.  
  599. //---------------------------------------------------------------- CmdArgToggle
  600.  
  601. CmdArgToggle::~CmdArgToggle(void)  {}
  602.  
  603. int
  604. CmdArgToggle::operator()(const char * & arg, CmdLine & cmd)
  605. {
  606.    unsigned  value = val;
  607.    int  rc = compile(arg, cmd, value, (! value));
  608.    val = value;
  609.    return  rc;
  610. }
  611.  
  612. //--------------------------------------------------------------- CmdArgBoolRef
  613.  
  614. CmdArgBoolRef::~CmdArgBoolRef(void)  {}
  615.  
  616. int
  617. CmdArgBoolRef::operator()(const char * & arg, CmdLine & cmd)
  618. {
  619.    unsigned  val = ref;
  620.    int rc = ref.compile(arg, cmd, val, 1);
  621.    ref = val;
  622.    return  rc;
  623. }
  624.  
  625. //-------------------------------------------------------------- CmdArgClearRef
  626.  
  627. CmdArgClearRef::~CmdArgClearRef(void)  {}
  628.  
  629. int
  630. CmdArgClearRef::operator()(const char * & arg, CmdLine & cmd)
  631. {
  632.    unsigned  val = ref;
  633.    int rc = ref.compile(arg, cmd, val, 0);
  634.    ref = val;
  635.    return  rc;
  636. }
  637.  
  638. //------------------------------------------------------------- CmdArgToggleRef
  639.  
  640. CmdArgToggleRef::~CmdArgToggleRef(void)  {}
  641.  
  642. int
  643. CmdArgToggleRef::operator()(const char * & arg, CmdLine & cmd)
  644. {
  645.    unsigned  val = ref;
  646.    int rc = ref.compile(arg, cmd, val, (! val));
  647.    ref = val;
  648.    return  rc;
  649. }
  650.  
  651.