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

  1. //------------------------------------------------------------------------
  2. // ^FILE: cmdparse.c - implementation of the CmdParseCommand
  3. //
  4. // ^DESCRIPTION:
  5. //    This file implements the member functions of the CmdParseCommand
  6. //    class.
  7. //
  8. // ^HISTORY:
  9. //    04/26/92    Brad Appleton    <brad@ssd.csd.harris.com>    Created
  10. //
  11. //    03/01/93    Brad Appleton    <brad@ssd.csd.harris.com>
  12. //    - Added ALLOW_PLUS to list of CmdLine configuration flags
  13. //-^^---------------------------------------------------------------------
  14.  
  15. #include <stdlib.h>
  16. #include <iostream.h>
  17. #include <fstream.h>
  18. #include <strstream.h>
  19. #include <string.h>
  20. #include <ctype.h>
  21.  
  22. #include "argtypes.h"
  23. #include "cmdparse.h"
  24. #include "syntax.h"
  25. #include "quoted.h"
  26.  
  27. enum { SUCCESS = 0, FAILURE = -1 } ;
  28.  
  29. enum { MAX_IDENT_LEN = 64, MAX_DESCRIPTION_LEN = 1024 } ;
  30.  
  31.  
  32. extern "C" {
  33.    int  isatty(int fd);
  34. }
  35.  
  36. //------------------------------------------------------------------------ copy
  37.  
  38. //-------------------
  39. // ^FUNCTION: copy - copy a string
  40. //
  41. // ^SYNOPSIS:
  42. //    copy(dest, src)
  43. //
  44. // ^PARAMETERS:
  45. //    char * & dest;
  46. //    -- where to put the copy we make
  47. //
  48. //    const char * src;
  49. //    -- the string to copy
  50. //
  51. // ^DESCRIPTION:
  52. //    This function duplicates its second parameter to its first parameter.
  53. //
  54. // ^REQUIREMENTS:
  55. //    None.
  56. //
  57. // ^SIDE-EFFECTS:
  58. //    "dest" is modified to point to the newly allocated and copied result.
  59. //
  60. // ^RETURN-VALUE:
  61. //    None.
  62. //
  63. // ^ALGORITHM:
  64. //    Trivial.
  65. //-^^----------------
  66. static  void
  67. copy(char * & dest, const char * src)
  68. {
  69.    if (src == NULL)  return ;
  70.    dest = new char[::strlen(src) + 1] ;
  71.    if (dest)  ::strcpy(dest, src);
  72. }
  73.  
  74. //------------------------------------------------------------------ CmdArgVers
  75.  
  76. CmdArgVers::CmdArgVers(char opt, const char * kwd, const char * description)
  77.    : CmdArg(opt, kwd, description, CmdArg::isOPT)
  78. {
  79. }
  80.  
  81. CmdArgVers::~CmdArgVers(void)
  82. {
  83. }
  84.  
  85. int
  86. CmdArgVers::operator()(const char * & , CmdLine & cmd)
  87. {
  88.    cerr << cmd.name() << "\trelease " << cmd.release()
  89.         << " at patchlevel " << cmd.patchlevel() << endl ;
  90.    cmd.quit(e_VERSION);
  91.    return  0;  // shutup the compiler about not returning a value
  92. }
  93.  
  94. //------------------------------------------------------------- CmdParseCommand
  95.  
  96. //-------------------
  97. // ^FUNCTION: CmdParseCommand::parse_declarations - parse user arguments
  98. //
  99. // ^SYNOPSIS:
  100. //    CmdParseCommand::parse_declarations()
  101. //
  102. // ^PARAMETERS:
  103. //    None.
  104. //
  105. // ^DESCRIPTION:
  106. //    This routine will go through all the input sources that were supplied
  107. //    on the command-line. Each of these "input sources" is something that
  108. //    contains user argument declarations that need to be parsed.  If no
  109. //    input sources were given and cin is not connected to a terminal, then
  110. //    we try to read the declarations from cin.
  111. //
  112. //    If input sources were given, they are parsed in the following order:
  113. //       1) from a string
  114. //       2) from an environment variable
  115. //       3) from a file
  116. //
  117. //    If more than one input source is specified then they are processed in
  118. //    the above order and each argument is appended to the user's CmdLine
  119. //    object in the order that it was seen.
  120. //
  121. // ^REQUIREMENTS:
  122. //    This routine should be called by CmdParseCommand::operator() after
  123. //    the command-line has been parsed.
  124. //
  125. // ^SIDE-EFFECTS:
  126. //    If input comes from a file, then the file is read (until eof or an
  127. //    error condition occurs).
  128. //
  129. //    Any arguments found are "compiled" and appended to "usr_cmd", the user's
  130. //    CmdLine object.
  131. //
  132. // ^RETURN-VALUE:
  133. //    0 upon success, non-zero upon failure.
  134. //
  135. // ^ALGORITHM:
  136. //    Follow along - its pretty straightforward.
  137. //-^^----------------
  138. int
  139. CmdParseCommand::parse_declarations(void)
  140. {
  141.    const char * str = input_str ;
  142.    const char * varname = input_var ;
  143.    const char * filename = input_file ;
  144.  
  145.       // If no "input sources" were specified, try cin.
  146.    if ((str == NULL)  &&  (varname == NULL)  &&  (filename == NULL)) {
  147.       // Make sure cin is NOT interactive!
  148.       int fd = ((filebuf *)(cin.rdbuf()))->fd();
  149.       if (::isatty(fd)) {
  150.          error() << "Can't read argument declarations from a terminal."
  151.                  << endl ;
  152.          return  -1;
  153.       }
  154.       return  parse_declarations(cin);
  155.    }
  156.  
  157.    int  rc = 0;
  158.  
  159.       // First - parse from the string
  160.    if (str) {
  161.       rc += parse_declarations(str);
  162.    }
  163.  
  164.       // Second - parse from the environment variable
  165.    if (varname) {
  166.       const char * contents = ::getenv(varname);
  167.       if (contents) {
  168.          rc += parse_declarations(contents);
  169.       } else {
  170.          error() << varname << " is empty or is undefined." << endl ;
  171.          return  -1;
  172.       }
  173.    }
  174.  
  175.       // Third - parse from the file. If the filename is "-" then it
  176.       //         means that standard input should be used.
  177.       //
  178.    if (filename) {
  179.       if (::strcmp(filename, "-") == 0) {
  180.          rc += parse_declarations(cin);
  181.       } else {
  182.          ifstream  ifs(filename);
  183.          if (ifs) {
  184.             rc += parse_declarations(ifs);
  185.          } else {
  186.             error() << "Unable to read from " << filename << '.' << endl ;
  187.             return  -1;
  188.          }
  189.       }
  190.    }
  191.  
  192.    return  rc;
  193. }
  194.  
  195.  
  196. //-------------------
  197. // ^FUNCTION: CmdParseCommand::usr_append - add a user argument
  198. //
  199. // ^SYNOPSIS:
  200. //    CmdParseCommand::usr_append(type, varname, arg, description)
  201. //
  202. // ^PARAMETERS:
  203. //    const char * type;
  204. //    -- the name of the desired argument type (which should correspond
  205. //       to either CmdArgUsage, CmdArgDummy, or one of the types defined
  206. //       in "argtypes.h").
  207. //
  208. //    const char * varname;
  209. //    -- the name of the shell variable that will be receiving the value
  210. //       that was supplied to this argument on the command-line.
  211. //
  212. //    ArgSyntax & arg;
  213. //    -- the argument syntax corresponding to the "syntax-string" supplied
  214. //       by the user.
  215. //
  216. //    const char * description;
  217. //    -- the user's description of this argument.
  218. //
  219. // ^DESCRIPTION:
  220. //    This member function will create a corresponding instance of a derived
  221. //    class of CmdArg named by "type" and will append it to the user's CmdLine
  222. //    object (named usr_cmd).
  223. //
  224. //    "type" may be one of the following (the leading "CmdArg" prefix may be
  225. //    omitted):
  226. //
  227. //       CmdArgInt, CmdArgFloat, CmdArgChar, CmdArgStr, CmdArgBool,
  228. //       CmdArgSet, CmdArgClear, CmdArgToggle, CmdArgUsage, CMdArgDummy
  229. //
  230. //    It is NOT necessary to use the name of a "List" CmdArg type in order
  231. //    to indicate a list, that will have been inferred from the syntax string
  232. //    and the appropriate ShellCmdArg<Type> object that we create will know
  233. //    how to handle it.
  234. //
  235. // ^REQUIREMENTS:
  236. //    This function should be called after an argument declaration has been
  237. //    completely parsed.
  238. //
  239. // ^SIDE-EFFECTS:
  240. //    If "type" is invalid - an error is printed on cerr, otherwise
  241. //    we create an appopriate CmdArg<Type> object and append it to usr_cmd.
  242. //
  243. // ^RETURN-VALUE:
  244. //    0 for success; non-zero for failure.
  245. //
  246. // ^ALGORITHM:
  247. //    Trivial - there's just a lot of type-names to check for.
  248. //-^^----------------
  249. int
  250. CmdParseCommand::usr_append(const char * type,
  251.                             const char * varname,
  252.                             ArgSyntax  & arg,
  253.                             const char * description)
  254. {
  255.    char * name = NULL ;
  256.    char * kwd  = NULL ;
  257.    char * val  = NULL ;
  258.    char * desc = NULL ;
  259.    unsigned  flags = arg.syntax() ;
  260.    char  opt = arg.optchar() ;
  261.  
  262.       // Need to make copies of some things because we cant assume they
  263.       // will be sticking around.  We assume that ShellCmdArg::~ShellCmdArg
  264.       // will deallocate this storage.
  265.       //
  266.    ::copy(name, varname);
  267.    ::copy(kwd,  arg.keyword());
  268.    ::copy(val,  arg.value());
  269.    ::copy(desc, description);
  270.  
  271.        // Skip any leading "Cmd", "Arg", or "CmdArg" prefix in the type-name.
  272.    if (CmdLine::strmatch("Cmd", type, 3) == CmdLine::str_EXACT)  type += 3;
  273.    if (CmdLine::strmatch("Arg", type, 3) == CmdLine::str_EXACT)  type += 3;
  274.  
  275.        // Create an argument for the appropriate type and append it
  276.        // to usr_cmd.
  277.        //
  278.    if (CmdLine::strmatch("Usage", type) == CmdLine::str_EXACT) {
  279.       delete [] name ;
  280.       usr_cmd.append(new CmdArgUsage(opt, kwd, desc)) ;
  281.    }
  282.    else if (CmdLine::strmatch("Dummy", type) == CmdLine::str_EXACT) {
  283.       delete [] name ;
  284.       usr_cmd.append(new CmdArgDummy(opt, kwd, val, desc, flags));
  285.    }
  286.    else if (CmdLine::strmatch("Set", type) == CmdLine::str_EXACT) {
  287.       usr_cmd.append(new ShellCmdArgBool(name, opt, kwd, desc, flags));
  288.    }
  289.    else if (CmdLine::strmatch("Clear", type) == CmdLine::str_EXACT) {
  290.       usr_cmd.append(new ShellCmdArgClear(name, opt, kwd, desc, flags));
  291.    }
  292.    else if (CmdLine::strmatch("Toggle", type) == CmdLine::str_EXACT) {
  293.       usr_cmd.append(new ShellCmdArgToggle(name, opt, kwd, desc, flags));
  294.    }
  295.    else if (CmdLine::strmatch("Boolean", type) != CmdLine::str_NONE) {
  296.       usr_cmd.append(new ShellCmdArgBool(name, opt, kwd, desc, flags));
  297.    }
  298.    else if (CmdLine::strmatch("Integer", type) != CmdLine::str_NONE) {
  299.       usr_cmd.append(new ShellCmdArgInt(name, opt, kwd, val, desc, flags));
  300.    }
  301.    else if (CmdLine::strmatch("Float", type) != CmdLine::str_NONE) {
  302.       usr_cmd.append(new ShellCmdArgFloat(name, opt, kwd, val, desc, flags));
  303.    }
  304.    else if (CmdLine::strmatch("Character", type) != CmdLine::str_NONE) {
  305.       usr_cmd.append(new ShellCmdArgChar(name, opt, kwd, val, desc, flags));
  306.    }
  307.    else if (CmdLine::strmatch("String", type) != CmdLine::str_NONE) {
  308.       usr_cmd.append(new ShellCmdArgStr(name, opt, kwd, val, desc, flags));
  309.    }
  310.    else {
  311.       cerr << "Unknown argument type \"" << type << "\"." << endl ;
  312.       delete [] kwd ;
  313.       delete [] val ;
  314.       delete [] desc ;
  315.       return  FAILURE ;
  316.    }
  317.  
  318.    return  SUCCESS ;
  319. }
  320.  
  321.  
  322. //-------------------
  323. // ^FUNCTION: CmdParseCommand::parse_declarations - parse from a string
  324. //
  325. // ^SYNOPSIS:
  326. //    CmdParseCommand::parse_declarations(str);
  327. //
  328. // ^PARAMETERS:
  329. //    const char * str;
  330. //    -- the string containing the argument declarations.
  331. //
  332. // ^DESCRIPTION:
  333. //    Parse the user's argument declarations from an input string.
  334. //
  335. // ^REQUIREMENTS:
  336. //    This member function should only be called by parse_declarations(void).
  337. //
  338. // ^SIDE-EFFECTS:
  339. //    - modifies usr_cmd by appending to it any valid arguments that we parse.
  340. //
  341. // ^RETURN-VALUE:
  342. //    0 for success; non-zero for failure.
  343. //
  344. // ^ALGORITHM:
  345. //    Just turn the string into an instream and parse the instream.
  346. //-^^----------------
  347. int
  348. CmdParseCommand::parse_declarations(const char * str)
  349. {
  350.    int  rc = 0;
  351.    char * strbuf = new char[::strlen(str) + 1] ;
  352.    (void) ::strcpy(strbuf, str);
  353.    istrstream  iss(strbuf);
  354.    rc = parse_declarations(iss);
  355.    delete  strbuf ;
  356.    return  rc ;
  357. }
  358.  
  359.  
  360.  
  361. //-------------------
  362. // ^FUNCTION: CmdParseCommand::parse_declarations - parse from an instream
  363. //
  364. // ^SYNOPSIS:
  365. //    CmdParseCommand::parse_declarations(is);
  366. //
  367. // ^PARAMETERS:
  368. //    istream & is;
  369. //    -- the instream containing the argument declarations.
  370. //
  371. // ^DESCRIPTION:
  372. //    Parse the user's argument declarations from an input steam.
  373. //
  374. // ^REQUIREMENTS:
  375. //    This member function should only be called by parse_declarations(void).
  376. //
  377. // ^SIDE-EFFECTS:
  378. //    - modifies usr_cmd by appending to it any valid arguments that we parse.
  379. //
  380. // ^RETURN-VALUE:
  381. //    0 for success; non-zero for failure.
  382. //
  383. // ^ALGORITHM:
  384. //    while not eof do
  385. //       - read the type
  386. //       - read the name
  387. //       - read the syntax
  388. //       - read the description
  389. //       - convert (type, name, syntax, description) into something we can
  390. //           append to usr_cmd.
  391. //    done
  392. //-^^----------------
  393. int
  394. CmdParseCommand::parse_declarations(istream & is)
  395. {
  396.       // Keep track of the number of declarations that we parse.
  397.    unsigned  nargs = 0;
  398.  
  399.    if (is.eof())  return  SUCCESS;
  400.  
  401.    char  arg_type[MAX_IDENT_LEN];
  402.    char  arg_name[MAX_IDENT_LEN];
  403.    QuotedString  arg_description(MAX_DESCRIPTION_LEN);
  404.  
  405.    while (is) {
  406.       ++nargs;
  407.  
  408.          // Skip all non-alpha-numerics
  409.      int c = is.peek() ;
  410.      while ((c != EOF) && (c != '_') && (! isalnum(c))) {
  411.         (void) is.get();
  412.         c = is.peek();
  413.      }
  414.   
  415.          // First parse the argument type
  416.       is.width(sizeof(arg_type) - 1);
  417.       is >> arg_type ;
  418.       if (! is) {
  419.          if (is.eof()) {
  420.             return  SUCCESS;  // end of args
  421.          } else {
  422.             error() << "Unable to extract type for argument #" << nargs
  423.                     << '.' << endl ;
  424.             return  FAILURE;
  425.          }
  426.       }
  427.  
  428.          // Now parse the argument name
  429.       is.width(sizeof(arg_name) - 1);
  430.       is >> arg_name ;
  431.       if (! is) {
  432.          if (is.eof()) {
  433.             error() << "Premature end of input.\n"
  434.                     << "\texpecting a name for argument #" << nargs
  435.                     << '.' << endl ;
  436.          } else {
  437.             error() << "Unable to extract name of argument #" << nargs
  438.                     << '.' << endl ;
  439.          }
  440.          return  FAILURE;
  441.       }
  442.  
  443.          // Now parse the argument syntax
  444.       ArgSyntax  arg;
  445.       is >> arg;
  446.       if (! is) {
  447.          error() << "Unable to get syntax for \"" << arg_name << "\" argument."
  448.                  << endl ;
  449.          return  FAILURE ;
  450.       }
  451.  
  452.          // Now parse the argument description
  453.       is >> arg_description ;
  454.       if (! is) {
  455.          error() << "Unable to get description for \"" << arg_name
  456.                  << "\" argument." << endl ;
  457.          return  FAILURE ;
  458.       }
  459.  
  460.       if (usr_append(arg_type, arg_name, arg, arg_description)) {
  461.          error() << "Unable to append \"" << arg_name << "\" argument "
  462.                  << "to the list." << endl ;
  463.          return  FAILURE;
  464.       }
  465.    }
  466.    return  SUCCESS;
  467. }
  468.  
  469.  
  470. //-------------------
  471. // ^FUNCTION: CmdParseCommand::set_args - set the user's arguments.
  472. //
  473. // ^SYNOPSIS:
  474. //    CmdParseCommand::set_args(shell)
  475. //
  476. // ^PARAMETERS:
  477. //    UnixShell * shell;
  478. //    -- the command-interpreter (shell) that we need to output
  479. //       variable settings for.
  480. //
  481. // ^DESCRIPTION:
  482. //    For each argument that was given on the user's command-line, we need to
  483. //    output a variable setting using the sepcified shell's syntax to indicate
  484. //    the value that was specified.
  485. //
  486. // ^REQUIREMENTS:
  487. //    This member function should only be called by CmdParseCommand::operator()
  488. //
  489. // ^SIDE-EFFECTS:
  490. //    All the variable settings or sent to cout (standard output), the invoking
  491. //    user is responsible for evaluating what this member function outputs.
  492. //
  493. // ^RETURN-VALUE:
  494. //    None.
  495. //
  496. // ^ALGORITHM:
  497. //    For each of the user's command-argument objects
  498. //       - if the argument is a dummy, then skip it
  499. //       - if the argument corresponds to the positional parameters for
  500. //           this shell but was not given a value on the command-line then
  501. //           unset this shell's positional parameters.
  502. //       - if the argument was given then
  503. //           - if the argument took a value and no value was given, then
  504. //               set the variable <argname>_FLAG to be TRUE.
  505. //           - else set the corresponding shell variable.
  506. //           endif
  507. //       endif
  508. //    endfor
  509. //-^^----------------
  510. void
  511. CmdParseCommand::set_args(UnixShell * shell)
  512. {
  513.    unsigned  flags, syntax;
  514.    CmdLineCmdArgIter  iter(usr_cmd);
  515.  
  516.    for (CmdArg * cmdarg = iter() ; cmdarg ; cmdarg = iter()) {
  517.       flags  = cmdarg->flags();
  518.       syntax = cmdarg->syntax();
  519.  
  520.       if (cmdarg->is_dummy())  continue;
  521.  
  522.       ShellCmdArg * sh_cmdarg = (ShellCmdArg *)cmdarg;
  523.  
  524.       if ((syntax & CmdArg::isPOS) && (! (flags & CmdArg::VALGIVEN))) {
  525.          // if these are the positional-parameters then unset them!
  526.          if (shell->is_positionals(sh_cmdarg->name())) {
  527.             shell->unset_args(sh_cmdarg->name());
  528.          }
  529.       }
  530.  
  531.       if (! (flags & CmdArg::GIVEN))  continue;
  532.  
  533.       if ((syntax & CmdArg::isVALTAKEN) && (! (flags & CmdArg::VALGIVEN))) {
  534.          // flag was given without its value - we need to record that
  535.          char  var_name[256];
  536.          (void) ::strcpy(var_name, sh_cmdarg->name());
  537.          (void) ::strcat(var_name, suffix_str);
  538.          ShellVariable  sh_var(var_name);
  539.          sh_var.set(ShellCmdArgBool::True());
  540.          shell->set(sh_var);
  541.       } else {
  542.          // output the value
  543.          if (sh_cmdarg->is_array()) {
  544.             shell->set(sh_cmdarg->array(), array_variant);
  545.          } else {
  546.             shell->set(sh_cmdarg->variable());
  547.          }
  548.       }
  549.    } //for
  550. }
  551.  
  552.  
  553. //-------------------------------------------- CmdParseCommand::CmdParseCommand
  554.  
  555. CmdParseCommand::CmdParseCommand(const char * name)
  556.    : CmdLine(name),
  557.      anywhere('a', "anywhere",
  558.         "Allow options (and keywords) to follow positional parameters."
  559.      ),
  560.      anycase('i', "ignore-case",
  561.         "Ignore character case on options."
  562.      ),
  563.      no_abort('n', "noabort",
  564.         "Dont exit if bad syntax; try to continue parsing."
  565.      ),
  566.      no_guessing('g', "noguessing",
  567.         "Dont \"guess\" for unmatched options/keywords."
  568.      ),
  569.      prompt('p', "prompt",
  570.         "Prompt the user interactively for any missing required arguments."
  571.      ),
  572.      plus('+', "plus",
  573.         "Allow the string \"+\" to be used as a long-option prefix."
  574.      ),
  575.      opts_only('o', "options-only",
  576.         "Dont match keywords (long-options)."
  577.      ),
  578.      kwds_only('k', "keywords-only",
  579.         "Dont match options."
  580.      ),
  581.      quiet('q', "quiet",
  582.         "Dont print command-line syntax error messages."
  583.      ),
  584.      array_variant('A', "arrays",
  585.         "Use alternative syntax for arrays."
  586.      ),
  587.      usage('u', "usage",
  588.         "Print command-line usage and exit."
  589.      ),
  590.      version('v', "version",
  591.         "Print version information and exit."
  592.      ),
  593.      true_str('T', "true", "string",
  594.         "The string to use for boolean arguments that are turned ON \
  595. (default=\"TRUE\")."
  596.      ),
  597.      false_str('F', "false", "string",
  598.         "The string to use for boolean arguments that are turned OFF \
  599. (default=\"\")."
  600.      ),
  601.      suffix_str('S', "suffix", "string",
  602.         "The suffix to use for missing optional values. (default=\"_FLAG\")."
  603.      ),
  604.      usr_shell('s', "shell", "shellname",
  605.  
  606.         "Set program arguments using the syntax of the given shell \
  607. (default=\"sh\")."
  608.      ),
  609.      input_file('f', "file", "filename",
  610.         "The file from which program argument declarations are read."
  611.      ),
  612.      input_var('e', "env", "varname",
  613.         "The environment variable containing the program argument declarations."
  614.      ),
  615.      input_str('d', "decls", "string",
  616.         "The string that contains the program argument declarations."
  617.      ),
  618.      dummy_arg("--",
  619.         "Indicates the end of options/keywords."
  620.      ),
  621.      usr_prog('N', "name", "program-name",
  622.         "The name of the program whose arguments are to be parsed.",
  623.         (CmdArg::isPOS | CmdArg::isREQ | CmdArg::isVALREQ)
  624.      ),
  625.      usr_args("[arguments ...]",
  626.         "The program-arguments to be parsed"
  627.      )
  628. {
  629.       // Append options.
  630.    (*this) << anywhere << anycase << no_abort << no_guessing << prompt << plus
  631.            << opts_only << kwds_only << quiet << array_variant << usage
  632.            << version << true_str << false_str << suffix_str << usr_shell
  633.            << input_file << input_var << input_str << dummy_arg ;
  634.  
  635.       // Append positional parameters.
  636.    (*this) << usr_prog << usr_args ;
  637.  
  638.    set(CmdLine::KWDS_ONLY);
  639.  
  640.       // Set up defaults
  641.    usr_shell  = "sh" ;
  642.    true_str   = "TRUE" ;
  643.    false_str  = "" ;
  644.    suffix_str = "_FLAG" ;
  645. }
  646.  
  647. //------------------------------------------- CmdParseCommand::~CmdParseCommand
  648.  
  649. CmdParseCommand::~CmdParseCommand(void)
  650. {
  651.    CmdLineCmdArgIter  iter(usr_cmd);
  652.  
  653.    for (CmdArg * cmdarg = iter() ; cmdarg ; cmdarg = iter()) {
  654.       delete  cmdarg ;
  655.    }
  656. }
  657.  
  658.  
  659. //-------------------
  660. // ^FUNCTION: CmdParseCommand::operator()
  661. //
  662. // ^SYNOPSIS:
  663. //    CmdParseCommand::operator(iter)
  664. //
  665. // ^PARAMETERS:
  666. //    CmdLineArgIter & iter;
  667. //    -- an object to iterate over the arguments on the command-line.
  668. //
  669. // ^DESCRIPTION:
  670. //    This member function is the "guts" of a CmdParseCommand object.
  671. //    We perform all the actions necessary to read the user's argument
  672. //    declaratins, read the user's command-line, and set the corresponding
  673. //    shell variables.
  674. //
  675. // ^REQUIREMENTS:
  676. //    None.
  677. //
  678. // ^SIDE-EFFECTS:
  679. //    - Modifies all parts of the corresponding CmdParseCommand object.
  680. //    - prints variable settings on cout
  681. //    - prints usage/error messages on cerr
  682. //
  683. // ^RETURN-VALUE:
  684. //    e_SUCCESS   --  no errors
  685. //    e_USAGE     --  no errors - usage printed
  686. //    e_VERSION   --  no errors - version printed
  687. //    e_CMDSYNTAX --  command-line syntax error
  688. //    e_BADSHELL  --  invalid shell specified
  689. //    e_BADDECLS  --  invalid declaration(s) given
  690. //
  691. // ^ALGORITHM:
  692. //    It gets complicated so follow along.
  693. //-^^----------------
  694. int
  695. CmdParseCommand::operator()(CmdLineArgIter & iter)
  696. {
  697.       // Parse arguments
  698.    parse(iter);
  699.  
  700.       // Use the specified shell
  701.    UnixShell * shell = new UnixShell(usr_shell);
  702.    if (! shell->is_valid()) {
  703.       error() << "\"" << usr_shell
  704.               << "\" is not a known command interpreter." << endl ;
  705.       return  e_BADSHELL ;
  706.    }
  707.  
  708.       // Handle "-true" and "-false" options
  709.    if (true_str.flags()  & CmdArg::GIVEN)  ShellCmdArgBool::True(true_str);
  710.    if (false_str.flags() & CmdArg::GIVEN)  ShellCmdArgBool::False(false_str);
  711.  
  712.       // Intitialize user's command-line
  713.    usr_cmd.name(usr_prog);
  714.    if (parse_declarations())  return  e_BADDECLS ;
  715.  
  716.       // Set user parsing preferences
  717.    if (anywhere)     usr_cmd.clear(CmdLine::OPTS_FIRST);
  718.    if (anycase)      usr_cmd.set(CmdLine::ANY_CASE_OPTS);
  719.    if (no_abort)     usr_cmd.set(CmdLine::NO_ABORT);
  720.    if (no_guessing)  usr_cmd.set(CmdLine::NO_GUESSING);
  721.    if (prompt)       usr_cmd.set(CmdLine::PROMPT_USER);
  722.    if (plus)         usr_cmd.set(CmdLine::ALLOW_PLUS);
  723.    if (opts_only)    usr_cmd.set(CmdLine::OPTS_ONLY);
  724.    if (kwds_only)    usr_cmd.set(CmdLine::KWDS_ONLY);
  725.    if (quiet)        usr_cmd.set(CmdLine::QUIET);
  726.  
  727.       // Just print usage if thats all that is desired
  728.    if (usage) {
  729.       usr_cmd.usage(cout);
  730.       return  e_USAGE ;
  731.    }
  732.  
  733.       // Parse user's command-line
  734.    usr_cmd.prologue();
  735.    for (int i = 0 ; i < usr_args.count() ; i++) {
  736.       usr_cmd.parse_arg(usr_args[i]);
  737.    }
  738.    usr_cmd.epilogue();
  739.  
  740.       // Set user's variables
  741.    set_args(shell);
  742.  
  743.    delete  shell ;
  744.    return  0;
  745. }
  746.  
  747.