home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume31 / cmdline / part04 < prev    next >
Encoding:
Text File  |  1992-07-26  |  56.7 KB  |  2,131 lines

  1. Newsgroups: comp.sources.misc
  2. From: brad@hcx1.ssd.csd.harris.com (Brad Appleton)
  3. Subject:  v31i051:  cmdline - C++ Library for parsing command-line arguments, Part04/07
  4. Message-ID: <1992Jul27.020604.29355@sparky.imd.sterling.com>
  5. X-Md4-Signature: d89dbcd0655937b4d01cf818483f864a
  6. Date: Mon, 27 Jul 1992 02:06:04 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: brad@hcx1.ssd.csd.harris.com (Brad Appleton)
  10. Posting-number: Volume 31, Issue 51
  11. Archive-name: cmdline/part04
  12. Environment: C++
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then unpack
  16. # it by saving it into a file and typing "sh file".  To overwrite existing
  17. # files, type "sh file -c".  You can also feed this as standard input via
  18. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  19. # will see the following message at the end:
  20. #        "End of archive 4 (of 7)."
  21. # Contents:  doc/classes.man src/cmd/shells.c src/cmd/shells.h
  22. #   src/cmd/syntax.c
  23. # Wrapped by brad@hcx1 on Mon Jul 20 10:41:30 1992
  24. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  25. if test -f 'doc/classes.man' -a "${1}" != "-c" ; then 
  26.   echo shar: Will not clobber existing file \"'doc/classes.man'\"
  27. else
  28. echo shar: Extracting \"'doc/classes.man'\" \(13264 characters\)
  29. sed "s/^X//" >'doc/classes.man' <<'END_OF_FILE'
  30. X.SH CLASS DEFINITIONS
  31. X.ds CI \f4CmdLineArgIter\fP
  32. X.ds CA \f4CmdArg\fP
  33. X.ds CL \f4CmdLine\fP
  34. X.de Ss
  35. X.br
  36. X\fB\s-1\&\\$1:\s+1\fR
  37. X.br
  38. X..
  39. X.de UL
  40. X.if n \\$1
  41. X.if n .br
  42. X..
  43. X.de CS
  44. X.  ft 4
  45. X.  nf
  46. X..
  47. X.de CE
  48. X.  fi
  49. X.  ft R
  50. X..
  51. X.PP
  52. XFor the most "up to date" explanation of each class (and of its members),
  53. Xplease refer to the relevant include files (which are thoroughly commented)
  54. Xmentioned in the \s-1\fBFILES\fP\s+1 section. The most common facilities
  55. Xof the most commonly used classes are described in the following subsections.
  56. X.\"-----------------------------------------------
  57. X.SS "\s+1Class \*(CI\s-1"
  58. X.RS
  59. XClass \*(CI is an abstract base class for iterating over string
  60. Xarguments from the command-line (or from some other input source).
  61. XIt has two member functions (both of which are pure virtual):
  62. X
  63. X.IP "\f4const char * operator()(void);\fP"
  64. XThis member function returns the current string argument and then
  65. Xadvances to the next string argument. If no arguments are left then
  66. X\f4NULL\fP is returned.
  67. X
  68. X.IP "\f4int  is_temporary(void)  const;\fP"
  69. XThis member function is used to indicate the "type" of storage that is
  70. Xused for the values returned by \f4operator()\fP. Some iterators will
  71. Xhave \f4operator()\fP return values that will stay around at least as
  72. Xlong as the iterator itself; if this is the case, then this member
  73. Xfunction will return 0. Other iterators may reuse the same storage
  74. Xon successive calls to \f4operator()\fP; if this is the case, this
  75. Xthis member function will return a non-zero value.
  76. X
  77. X.PP
  78. XThere are three predefined subclasses of \*(CI: \f4CmdArgvIter\fP,
  79. X\f4CmdStrtokIter\fP, and \f4CmdIstreamIter\fP.
  80. X
  81. X.CS
  82. Xclass CmdArgvIter : public CmdLineArgIter {
  83. Xpublic:
  84. X   CmdArgvIter(const char * const argv[]);
  85. X
  86. X   CmdArgvIter(int argc, const char * const argv[]);
  87. X
  88. X      // Restart using a different string array.
  89. X   void  reset(const char * const argv[]);
  90. X   void  reset(int argc, const char * const argv[]);
  91. X
  92. X   const char * operator()(void);
  93. X
  94. X   int  is_temporary(void)  const;
  95. X} ;
  96. X.CE
  97. X
  98. XThis class iterates over string arguments that originate from a NULL
  99. Xterminated vector of strings (such as \f4argv\fP), and may be  constructed
  100. Xwith just an array, or with an array and an item count.
  101. X
  102. X.CS
  103. Xclass  CmdStrTokIter : public CmdLineArgIter {
  104. Xpublic:
  105. X   CmdStrTokIter(const char * tokens, const char * delimiters =NULL);
  106. X
  107. X      // Reset using a new token-string and delimiter set.
  108. X   void  reset(const char * tokens, const char * delimiters =NULL);
  109. X
  110. X      // Get the current delimiter set
  111. X   const char *  delimiters(void)  const;
  112. X
  113. X      // Change the current delimiter set
  114. X   void  delimiters(const char * new_delimiters);
  115. X
  116. X   const char * operator()(void);
  117. X
  118. X   int  is_temporary(void)  const;
  119. X} ;
  120. X.CE
  121. X
  122. XThis class iterates over string arguments that come from a single string
  123. Xthat contains multiple tokens which are delimited by one or more characters
  124. Xfrom the given delimiter set. The \f4strtok(3C)\fP library function is 
  125. Xused to extract tokens from the string. If a delimiter set of \f4NULL\fP
  126. Xis given then whitespace will be assumed.
  127. X
  128. X.CS
  129. Xclass  CmdIstreamIter : public CmdLineArgIter {
  130. Xpublic:
  131. X   CmdIstreamIter(istream & input);
  132. X
  133. X   const char * operator()(void);
  134. X
  135. X   int  is_temporary(void)  const;
  136. X} ;
  137. X.CE
  138. X
  139. XThis class iterates over string arguments that come from an input stream.
  140. XEach line of the input stream is considered to be a set of white-space
  141. Xseparated tokens. If the the first non-white character on a line is `#'
  142. X(`!' for VMS systems) then the line is considered a comment and is ignored.
  143. XIf a line is more than 1022 characters in length then we treat it as if
  144. Xit were several lines of length 1022 or less.
  145. X
  146. X.RE
  147. X.\"-----------------------------------------------
  148. X.SS "\s+1Class \*(CA\s-1"
  149. X.RS
  150. XA \*(CA is an abstract command-line argument.
  151. XAt this level (being the base class), all a command argument
  152. Xcontains is the "interface" (on the command-line) of the
  153. Xargument, and some information (after the command-line has
  154. Xbeen parsed) that says "how" the argument appeared (if it
  155. Xwas specified).
  156. X
  157. XThe interface of a \*(CA consists of the following:
  158. X
  159. X.RS
  160. X.IP "\(bu" 3
  161. Xa character name
  162. X.IP "\(bu" 3
  163. Xa keyword name
  164. X.IP "\(bu" 3
  165. Xa value name (if the argument takes a value)
  166. X.IP "\(bu" 3
  167. Xan argument description
  168. X.IP "\(bu" 3
  169. Xa set of flags describing the syntax of the argument.
  170. X.IP "\(bu" 3
  171. Xa set of flags to record how (and if) the argument
  172. Xappeared on the command-line.
  173. X.RE
  174. X
  175. XWhen constructing a \*(CA, the most common syntax-flags can be
  176. Xinferred from the syntax used in the argument description,
  177. Xand the argument value name.  If the first non-white character
  178. Xof the argument description is a semicolon (`;'), then the argument
  179. Xis considered to be "secret" and is NOT printed in usage messages.
  180. XWhen specifying a value name, one may enclose the value name in between
  181. Xsquare brackets (`[' and `]') to indicate the value is optional. Also,
  182. Xone may follow the actual value name with an ellipsis ("\0.\^.\^.")
  183. Xto indicate that the value corresponds to a LIST of values.
  184. X
  185. XOther more esoteric syntax flags may be specified explicitly by using
  186. Xone or more of the bitmasks of type \f4CmdArg::CmdArgSyntax\fP as
  187. Xthe last argument to the constructor; if these syntax-flags are NOT supplied,
  188. Xthen reasonable defaults will be used.
  189. X
  190. XThe different types of constructors for a \*(CA are as follows:
  191. X
  192. X.CS
  193. X   // Create an option that takes a value.
  194. X   //
  195. X   // The default flags are to assume that the argument is
  196. X   // optional and that the value is required.
  197. X   //
  198. X   // Examples:
  199. X   //    //  [\-c number]  or  [\*(--count number]
  200. X   //    CmdArg('c', "count", "number",
  201. X   //              "specify the # of copies to use);
  202. X   //
  203. X   //    //  [\-d [level]]  or  [\*(--debug [level]]
  204. X   //    CmdArg('d', "debug", "[level]",
  205. X   //              "turn on debugging and optionally"
  206. X   //              "specify the debug level");
  207. X   //
  208. X   //    //  [\-l items ...]  or  [\*(--list items ...]
  209. X   //    CmdArg('l', "list", "items ...",
  210. X   //              "specify a list of items.");
  211. X   //
  212. XCmdArg(char         optchar,
  213. X       const char * keyword,
  214. X       const char * value,
  215. X       const char * description,
  216. X       unsigned     syntax_flags =CmdArg::isOPTVALREQ);
  217. X
  218. X   // Create an option that takes no value.
  219. X   //
  220. X   // The default syntax-flags are to assume that the
  221. X   // argument is optional.
  222. X   //
  223. X   // Example:
  224. X   //    //  -m  or  \*(--mode
  225. X   //    CmdArg('m', "mode", "turn on this mode");
  226. X   //
  227. XCmdArg(char         optchar,
  228. X       const char * keyword,
  229. X       const char * description,
  230. X       unsigned     syntax_flags =CmdArg::isOPT);
  231. X
  232. X   // Create a positional argument.
  233. X   //
  234. X   // The default flags are to assume that the argument is
  235. X   // positional and that the argument value is required.
  236. X   //
  237. X   // Examples:
  238. X   //    CmdArg("file", "file to read");
  239. X   //
  240. X   //    CmdArg("[file]", "optional file to read");
  241. X   //
  242. X   //    CmdArg("file ...", "list of files to read");
  243. X   //
  244. X   //    CmdArg("[file ...]", "optional list of files to read");
  245. X   //
  246. XCmdArg(const char * value,
  247. X       const char * description,
  248. X       unsigned     syntax_flags =CmdArg::isPOSVALREQ);
  249. X.CE
  250. X
  251. XAfter a command-argument has been declared, you may wish to ask several
  252. Xquestions regarding how (and if) it was specified. For example: was the
  253. Xargument given? If it was given, was a value supplied?  These questions
  254. X(and others) may answered using the \f4flags()\fP member function:
  255. X
  256. X.CS
  257. X     unsigned  CmdArg::flags(void)  const;
  258. X.CE
  259. X
  260. XThis member function returns a set of bitmasks of type
  261. X\f4CmdArg::CmdArgFlags\fP which are defined in \f4<cmdline.h>\fP.
  262. XThe most common flags are \f4CmdArg::GIVEN\fP (which is set if the
  263. Xargument was given) and \f4CmdArg::VALGIVEN\fP (which is set if a
  264. Xvalue was supplied for the argument).
  265. X
  266. XThere are other member functions to return each of the attributes that
  267. Xa \*(CA was constructed with.  These member functions (and others) are
  268. Xdiscussed in \f4<cmdline.h>\fP.
  269. X
  270. XClasses that are derived from \*(CA will not have all three of the above 
  271. Xdestructors. Some derived classes (such as \f4CmdArgBool\fP) only
  272. Xcorrespond to non-positional arguments that take no value. Other derived
  273. Xclasses (such as \f4CmdArgInt\fP and \f4CmdArgStr\fP) always permit
  274. Xa value to be given.
  275. XSome predefined subclasses of \*(CA which represent the most commonly used
  276. Xtypes of command-line arguments may be found in \f4<cmdargs.h>\fP.
  277. X
  278. X.RE
  279. X.\"-----------------------------------------------
  280. X.SS "\s+1Class \*(CL\s-1"
  281. X.RS
  282. XClass \*(CL is the class that represents a command-line object.
  283. XA command-line object is a parsing machine (with machine states),
  284. Xwhose parsing behavior may be configured at run-time by specifying
  285. Xvarious flags of type \f4CmdLine::CmdFlags\fP.
  286. XA command-line object also contains a command-name and a list of
  287. X\*(CA objects that correspond to the various arguments that are
  288. Xallowed to occur on the command-line.
  289. X
  290. X.Ss "Constructing a \*(CL Object"
  291. X.UL "------------------------------"
  292. XIt is not necessary to supply a command-name at construction
  293. Xtime, but one SHOULD be specified before parsing a command-line
  294. Xor printing a usage message.
  295. X
  296. XSimilarly, \*(CAs are not required at construction time and may
  297. Xeven be added on the fly. All desired arguments should be added
  298. Xbefore any parsing happens and before printing usage.
  299. X
  300. XThe order in which \*(CAs are added to a \*(CL is important
  301. Xbecause for positional parameters, this specifies the order in
  302. Xwhich they are expected to appear on the command-line.
  303. X
  304. XThe constructors for a \*(CL are as follows (those constructors that
  305. Xtake a variable number of parameters must have \f4NULL\fP specified
  306. Xas the final parameter):
  307. X
  308. X.CS
  309. X        // construct a command (and optionally specify a name)
  310. X     CmdLine(const char * name =NULL);
  311. X
  312. X        // construct a command with a name, and arguments
  313. X     CmdLine(const char * name, CmdArg * ...);
  314. X
  315. X        // construct a command command with arguments, but no name
  316. X     CmdLine(CmdArg * cmdarg, CmdArg * ...);
  317. X.CE
  318. X
  319. XThe command name may be set (or queried) after construction by using
  320. Xthe \f4name()\fP member function.
  321. X
  322. XCommand arguments may be added after construction by using the \f4append()\fP
  323. Xmember function.
  324. X
  325. X.Ss "Other Common \*(CL Member Functions"
  326. X.UL "--------------------------------------"
  327. XThe most common requests to make of a \*(CL object is to ask it to parse
  328. Xits arguments, to query it's status, to print the command usage, and to
  329. Xprint an error message.  These may be accomplished with the following
  330. Xmember functions:
  331. X
  332. X.CS
  333. X   // Print usage to the given outstream or to
  334. X   // the default error outstream.
  335. X   //
  336. Xostream &  usage(ostream & os)  const;
  337. Xostream &  usage(void)  const;
  338. X
  339. X   // Print the command-name, followed by ": " and return the
  340. X   // outstream for the user to supply the remainder of the
  341. X   // error message.
  342. X   //
  343. X   // Example:
  344. X   //   cmd.error() << "can't use \-x with \-y." << endl ;
  345. X   //
  346. Xostream &  error(void)  const;
  347. X
  348. X   // Obtain the current status of the command. The status will be
  349. X   // zero if everything is okay; otherwise it will correspond
  350. X   // to a combination of CmdLine::CmdStatus bitmasks telling us
  351. X   // precisely what went wrong.
  352. X   //
  353. Xunsigned  status(void)  const;
  354. X
  355. X   // Parse arguments from the given string argument iterator.
  356. X   // The return value will be the resultant CmdLine status
  357. X   // (which may also be obtained using status()).
  358. X   //
  359. Xunsigned  parse(CmdLineArgIter & arg_iter);
  360. X.CE
  361. X
  362. X
  363. X.Ss "Modifying Parsing Behavior"
  364. X.UL "-----------------------------"
  365. XIf you wish to modify parsing behavior to something other than the default,
  366. Xthere are four more member functions that you will need to know how to use.
  367. XEach of these member functions deals with bitmasks of the type
  368. X\f4CmdLine::CmdFlags\fP.
  369. X
  370. X.CS
  371. X   // Flags that define parsing behavior
  372. X   //   The default flags (for Unix) are OPTS_FIRST.
  373. Xenum CmdFlags {
  374. X   ANY_CASE_OPTS = 0x001, // Ignore character-case for short-options
  375. X.sp 2p
  376. X   PROMPT_USER   = 0x002, // Prompt the user for missing required args
  377. X.sp 2p
  378. X   NO_ABORT      = 0x004, // Don't exit upon syntax error
  379. X.sp 2p
  380. X   OPTS_FIRST    = 0x008, // No options after positional parameters
  381. X.sp 2p
  382. X   OPTS_ONLY     = 0x010, // Don't accept short-options
  383. X.sp 2p
  384. X   KWDS_ONLY     = 0x020, // Don't accept long-options
  385. X.sp 2p
  386. X   TEMP          = 0x040, // Assume all arg-strings are temporary
  387. X.sp 2p
  388. X   QUIET         = 0x080, // Don't print syntax error messages
  389. X.sp 2p
  390. X   NO_GUESSING   = 0x100, // Don't guess if cant match an option. 
  391. X                             // Unless this flag is given, then
  392. X                             // when we see an unmatched option,
  393. X                             // we will try to see if it matches
  394. X                             // a keyword (and vice-versa).
  395. X} ;
  396. X
  397. X   // Get the current set of command-flags
  398. Xunsigned  flags(void)  const;
  399. X
  400. X   // Specify a new set of command-flags
  401. Xvoid  flags(unsigned newflags);
  402. X
  403. X   // Set only the given command-flags, leave the others alone
  404. Xvoid  set(unsigned flags);
  405. X
  406. X   // Clear only the given command-flags, leave the others alone
  407. Xvoid  clear(unsigned flags =~0);
  408. X.CE
  409. X
  410. XThese are the basic member functions of a \*(CL object. The are others as well
  411. Xbut these should provide most of the desired functionality. For more detailed
  412. Xinformation, please see \f4<cmdline.h>\fP.
  413. X
  414. X.RE
  415. X.\"-----------------------------------------------
  416. END_OF_FILE
  417. if test 13264 -ne `wc -c <'doc/classes.man'`; then
  418.     echo shar: \"'doc/classes.man'\" unpacked with wrong size!
  419. fi
  420. # end of 'doc/classes.man'
  421. fi
  422. if test -f 'src/cmd/shells.c' -a "${1}" != "-c" ; then 
  423.   echo shar: Will not clobber existing file \"'src/cmd/shells.c'\"
  424. else
  425. echo shar: Extracting \"'src/cmd/shells.c'\" \(16461 characters\)
  426. sed "s/^X//" >'src/cmd/shells.c' <<'END_OF_FILE'
  427. X//------------------------------------------------------------------------
  428. X// ^FILE: shells.c - implement classes for the various Unix shells
  429. X//
  430. X// ^DESCRIPTION:
  431. X//     This file packages all the information we need to know about each
  432. X//  of the shells that cmdparse(1) will support into a set of (sub)classes.
  433. X//
  434. X// ^HISTORY:
  435. X//    04/19/92    Brad Appleton    <brad@ssd.csd.harris.com>    Created
  436. X//-^^---------------------------------------------------------------------
  437. X
  438. X#include <stdlib.h>
  439. X#include <iostream.h>
  440. X#include <string.h>
  441. X#include <ctype.h>
  442. X
  443. X#include <fifolist.h>
  444. X
  445. X#include "shells.h"
  446. X#include "argtypes.h"
  447. X
  448. X//--------------------------------------------------------------- ShellVariable
  449. X
  450. XShellVariable::ShellVariable(const char * name)
  451. X   : var_name(name), var_value(NULL)
  452. X{
  453. X}
  454. X
  455. XShellVariable::~ShellVariable(void)
  456. X{
  457. X}
  458. X
  459. X//------------------------------------------------------------ ShellArrayValues
  460. X
  461. XDECLARE_FIFO_LIST(CharPtrList, char *);
  462. X
  463. Xstruct  ShellArrayValues {
  464. X   CharPtrList       list;
  465. X   CharPtrListArray  array;
  466. X
  467. X   ShellArrayValues(void);
  468. X} ;
  469. X
  470. XShellArrayValues::ShellArrayValues(void)
  471. X   : array(list)
  472. X{
  473. X   list.self_cleaning(1);
  474. X}
  475. X
  476. X//------------------------------------------------------------------ ShellArray
  477. X
  478. XShellArray::ShellArray(const char * name)
  479. X   : array_name(name), array_value(NULL)
  480. X{
  481. X}
  482. X
  483. XShellArray::~ShellArray(void)
  484. X{
  485. X   delete  array_value ;
  486. X}
  487. X
  488. Xvoid
  489. XShellArray::append(const char * value)
  490. X{
  491. X   if (array_value == NULL) {
  492. X      array_value = new ShellArrayValues ;
  493. X   }
  494. X   char ** valptr = new char* ;
  495. X   if (valptr) {
  496. X      *valptr = (char *)value;
  497. X      array_value->list.add(valptr);
  498. X   }
  499. X}
  500. X
  501. Xunsigned
  502. XShellArray::count(void) const
  503. X{
  504. X   return  ((array_value) ? array_value->list.count() : 0);
  505. X}
  506. X
  507. Xconst char *
  508. XShellArray::operator[](unsigned  index) const
  509. X{
  510. X   return  ((array_value) ? array_value->array[index] : NULL);
  511. X}
  512. X
  513. X//----------------------------------------------------------- AbstractUnixShell
  514. X
  515. XAbstractUnixShell::~AbstractUnixShell(void)
  516. X{
  517. X}
  518. X
  519. X//------------------------------------------------------------------- UnixShell
  520. X
  521. XUnixShell::UnixShell(const char * shell_name)
  522. X   : shell(NULL), valid(1)
  523. X{
  524. X   if (::strcmp(BourneShell::NAME, shell_name) == 0) {
  525. X      shell = new BourneShell ;
  526. X   } else if (::strcmp("ash", shell_name) == 0) {
  527. X      shell = new BourneShell ;
  528. X   } else if (::strcmp(KornShell::NAME, shell_name) == 0) {
  529. X      shell = new KornShell ;
  530. X   } else if (::strcmp(BourneAgainShell::NAME, shell_name) == 0) {
  531. X      shell = new BourneAgainShell ;
  532. X   } else if (::strcmp(CShell::NAME, shell_name) == 0) {
  533. X      shell = new CShell ;
  534. X   } else if (::strcmp("tcsh", shell_name) == 0) {
  535. X      shell = new CShell ;
  536. X   } else if (::strcmp("itcsh", shell_name) == 0) {
  537. X      shell = new CShell ;
  538. X   } else if (::strcmp(ZShell::NAME, shell_name) == 0) {
  539. X      shell = new ZShell ;
  540. X   } else if (::strcmp(Plan9Shell::NAME, shell_name) == 0) {
  541. X      shell = new Plan9Shell ;
  542. X   } else if (::strcmp(PerlShell::NAME, shell_name) == 0) {
  543. X      shell = new PerlShell ;
  544. X   } else if (::strcmp(TclShell::NAME, shell_name) == 0) {
  545. X      shell = new TclShell ;
  546. X   } else {
  547. X      valid = 0;
  548. X   }
  549. X}
  550. X
  551. XUnixShell::~UnixShell(void)
  552. X{
  553. X   delete  shell;
  554. X}
  555. X
  556. Xconst char *
  557. XUnixShell::name(void) const
  558. X{
  559. X   return  ((shell) ? shell->name() : NULL);
  560. X}
  561. X
  562. Xvoid
  563. XUnixShell::unset_args(const char * name) const
  564. X{
  565. X   if (shell)  shell->unset_args(name);
  566. X}
  567. X
  568. Xint
  569. XUnixShell::is_positionals(const char * name) const
  570. X{
  571. X   return  ((shell) ? shell->is_positionals(name) : 0);
  572. X}
  573. X
  574. Xvoid
  575. XUnixShell::set(const ShellVariable & variable) const
  576. X{
  577. X   if (shell)  shell->set(variable);
  578. X}
  579. X
  580. Xvoid
  581. XUnixShell::set(const ShellArray & array, int variant) const
  582. X{
  583. X   if (shell)  shell->set(array, variant);
  584. X}
  585. X
  586. X//----------------------------------------------------------------- varname
  587. X
  588. X// Remove any "esoteric" portions of a vraible name (such as a leading '$')
  589. X//
  590. Xinline  static  const char *
  591. Xvarname(const char * name, char skip)
  592. X{
  593. X   return  ((*name == skip) && (*(name + 1))) ? (name + 1): name ;
  594. X}
  595. X
  596. X//----------------------------------------------------------------- BourneShell
  597. X
  598. Xconst char * BourneShell::NAME = "sh" ;
  599. X
  600. XBourneShell::BourneShell(void)
  601. X{
  602. X}
  603. X
  604. XBourneShell::~BourneShell(void)
  605. X{
  606. X}
  607. X
  608. Xconst char *
  609. XBourneShell::name(void) const
  610. X{
  611. X   return  BourneShell::NAME ;
  612. X}
  613. X
  614. Xvoid
  615. XBourneShell::unset_args(const char *) const
  616. X{
  617. X   cout << "shift $# ;" << endl ;
  618. X}
  619. X
  620. Xint
  621. XBourneShell::is_positionals(const char * name) const
  622. X{
  623. X   name = varname(name, '$');
  624. X   return  ((::strcmp(name, "--") == 0) || (::strcmp(name, "-") == 0) ||
  625. X            (::strcmp(name, "@") == 0)  || (::strcmp(name, "*") == 0)) ;
  626. X}
  627. X
  628. Xvoid
  629. XBourneShell::set(const ShellVariable & variable) const
  630. X{
  631. X   const char * name = varname(variable.name(), '$');
  632. X   if (is_positionals(name)) {
  633. X      cout << "set -- '" ;
  634. X   } else {
  635. X      cout << name << "='" ;
  636. X   }
  637. X   escape_value(variable.value());
  638. X   cout << "';" << endl ;
  639. X}
  640. X
  641. Xvoid
  642. XBourneShell::set(const ShellArray & array, int variant) const
  643. X{
  644. X   int  ndx;
  645. X   const char * name = varname(array.name(), '$');
  646. X
  647. X   if (is_positionals(name)) {
  648. X      // set -- 'arg1' 'arg2' ...
  649. X      cout << "set -- ";
  650. X      for (ndx = 0 ; ndx < array.count() ; ndx++) {
  651. X         if (ndx)  cout << ' ' ;
  652. X         cout << '\'' ;
  653. X         escape_value(array[ndx]);
  654. X         cout << '\'' ;
  655. X      }
  656. X      cout << ';' << endl ;
  657. X   } else if (variant) {
  658. X      // argname_count=N
  659. X      // argname1='arg1'
  660. X      //   ...
  661. X      // argnameN='argN'
  662. X      cout << name << "_count=" << array.count() << ';' << endl ;
  663. X      for (ndx = 0 ; ndx < array.count() ; ndx++) {
  664. X         cout << name << (ndx + 1) << "='";
  665. X         escape_value(array[ndx]);
  666. X         cout << "';" << endl ;
  667. X      }
  668. X   } else {
  669. X      // argname='arg1 arg2 ...'
  670. X      cout << name << "='";
  671. X      for (ndx = 0 ; ndx < array.count() ; ndx++) {
  672. X         if (ndx)  cout << ' ' ;
  673. X         escape_value(array[ndx]);
  674. X      }
  675. X      cout << "';" << endl ;
  676. X   }
  677. X}
  678. X
  679. Xvoid
  680. XBourneShell::escape_value(const char * value) const
  681. X{
  682. X   for ( ; *value ; value++) {
  683. X      switch (*value) {
  684. X      case '\'' :
  685. X         cout << "'\\''" ;
  686. X         break ;
  687. X
  688. X      case '\\' :
  689. X      case '\b' :
  690. X      case '\r' :
  691. X      case '\v' :
  692. X      case '\f' :
  693. X         cout << '\\' ;    // fall thru to default case
  694. X      default :
  695. X         cout << char(*value) ;
  696. X      }
  697. X   } //for
  698. X}
  699. X
  700. X//------------------------------------------------------------------- KornShell
  701. X
  702. Xconst char * KornShell::NAME = "ksh" ;
  703. X
  704. XKornShell::KornShell(void)
  705. X{
  706. X}
  707. X
  708. XKornShell::~KornShell(void)
  709. X{
  710. X}
  711. X
  712. Xconst char *
  713. XKornShell::name(void) const
  714. X{
  715. X   return  KornShell::NAME ;
  716. X}
  717. X
  718. Xvoid
  719. XKornShell::unset_args(const char *) const
  720. X{
  721. X   cout << "set -- ;" << endl ;
  722. X}
  723. X
  724. Xvoid
  725. XKornShell::set(const ShellVariable & variable) const
  726. X{
  727. X   BourneShell::set(variable);
  728. X} 
  729. X
  730. Xvoid
  731. XKornShell::set(const ShellArray & array, int variant) const
  732. X{
  733. X   const char * name = varname(array.name(), '$');
  734. X   if (is_positionals(name)) {
  735. X      cout << "set -- " ;
  736. X   } else {
  737. X      cout << "set " << (variant ? '+' : '-') << "A " << name << ' ' ;
  738. X   }
  739. X   for (int  ndx = 0 ; ndx < array.count() ; ndx++) {
  740. X      if (ndx)  cout << ' ' ;
  741. X      cout << '\'' ;
  742. X      escape_value(array[ndx]);
  743. X      cout << '\'' ;
  744. X   }
  745. X   cout << ';' << endl ;
  746. X}
  747. X
  748. X//------------------------------------------------------------ BourneAgainShell
  749. X
  750. Xconst char * BourneAgainShell::NAME = "bash" ;
  751. X
  752. XBourneAgainShell::BourneAgainShell(void)
  753. X{
  754. X}
  755. X
  756. XBourneAgainShell::~BourneAgainShell(void)
  757. X{
  758. X}
  759. X
  760. Xconst char *
  761. XBourneAgainShell::name(void) const
  762. X{
  763. X   return  BourneAgainShell::NAME ;
  764. X}
  765. X
  766. Xvoid
  767. XBourneAgainShell::set(const ShellVariable & variable) const
  768. X{
  769. X   BourneShell::set(variable);
  770. X} 
  771. X
  772. Xvoid
  773. XBourneAgainShell::set(const ShellArray & array, int variant) const
  774. X{
  775. X   BourneShell::set(array, variant);
  776. X}
  777. X
  778. X//---------------------------------------------------------------------- CShell
  779. X
  780. Xconst char * CShell::NAME = "csh" ;
  781. X
  782. XCShell::CShell(void)
  783. X{
  784. X}
  785. X
  786. XCShell::~CShell(void)
  787. X{
  788. X}
  789. X
  790. Xconst char *
  791. XCShell::name(void) const
  792. X{
  793. X   return  CShell::NAME ;
  794. X}
  795. X
  796. Xvoid
  797. XCShell::unset_args(const char *) const
  798. X{
  799. X   cout << "set argv=();" << endl ;
  800. X}
  801. X
  802. Xint
  803. XCShell::is_positionals(const char * name) const
  804. X{
  805. X   name = varname(name, '$');
  806. X   return  (::strcmp(name, "argv") == 0);
  807. X}
  808. X
  809. Xvoid
  810. XCShell::set(const ShellVariable & variable) const
  811. X{
  812. X   const char * name = varname(variable.name(), '$');
  813. X   int  posl = is_positionals(name);
  814. X   cout << "set " << name << '=' ;
  815. X   if (posl)  cout << '(' ;
  816. X   cout << '\'' ;
  817. X   escape_value(variable.value());
  818. X   cout << '\'' ;
  819. X   if (posl)  cout << ')' ;
  820. X   cout << ';' << endl ;;
  821. X}
  822. X
  823. Xvoid
  824. XCShell::set(const ShellArray & array, int ) const
  825. X{
  826. X   cout << "set " << varname(array.name(), '$') << "=(" ;
  827. X   for (int  ndx = 0 ; ndx < array.count() ; ndx++) {
  828. X      if (ndx)  cout << ' ' ;
  829. X      cout << '\'' ;
  830. X      escape_value(array[ndx]);
  831. X      cout << '\'' ;
  832. X   }
  833. X   cout << ");" << endl ;
  834. X}
  835. X
  836. Xvoid
  837. XCShell::escape_value(const char * value) const
  838. X{
  839. X   for ( ; *value ; value++) {
  840. X      switch (*value) {
  841. X      case '\'' :
  842. X         cout << "'\\''" ;
  843. X         break ;
  844. X
  845. X      case '!' :
  846. X      case '\n' :
  847. X      case '\b' :
  848. X      case '\r' :
  849. X      case '\v' :
  850. X      case '\f' :
  851. X         cout << '\\' ;    // fall thru to default case
  852. X      default :
  853. X         cout << char(*value) ;
  854. X      }
  855. X   } //for
  856. X}
  857. X
  858. X//---------------------------------------------------------------------- ZShell
  859. X
  860. Xconst char * ZShell::NAME = "zsh" ;
  861. X
  862. XZShell::ZShell(void)
  863. X{
  864. X}
  865. X
  866. XZShell::~ZShell(void)
  867. X{
  868. X}
  869. X
  870. Xconst char *
  871. XZShell::name(void) const
  872. X{
  873. X   return  ZShell::NAME ;
  874. X}
  875. X
  876. Xvoid
  877. XZShell::unset_args(const char *) const
  878. X{
  879. X   cout << "argv=();" << endl ;
  880. X}
  881. X
  882. Xint
  883. XZShell::is_positionals(const char * name) const
  884. X{
  885. X   name = varname(name, '$');
  886. X   return  ((::strcmp(name, "--") == 0) || (::strcmp(name, "-") == 0) ||
  887. X            (::strcmp(name, "@") == 0)  || (::strcmp(name, "*") == 0) ||
  888. X            (::strcmp(name, "argv") == 0));
  889. X}
  890. X
  891. Xvoid
  892. XZShell::set(const ShellVariable & variable) const
  893. X{
  894. X   const char * name = varname(variable.name(), '$');
  895. X   int  posl = is_positionals(name);
  896. X   cout << name << '=' ;
  897. X   if (posl)  cout << '(' ;
  898. X   cout << '\'' ;
  899. X   escape_value(variable.value());
  900. X   cout << '\'' ;
  901. X   if (posl)  cout << ')' ;
  902. X   cout << ';' << endl ;;
  903. X}
  904. X
  905. Xvoid
  906. XZShell::set(const ShellArray & array, int ) const
  907. X{
  908. X   cout << varname(array.name(), '$') << "=(" ;
  909. X   for (int  ndx = 0 ; ndx < array.count() ; ndx++) {
  910. X      if (ndx)  cout << ' ' ;
  911. X      cout << '\'' ;
  912. X      escape_value(array[ndx]);
  913. X      cout << '\'' ;
  914. X   }
  915. X   cout << ");" << endl ;
  916. X}
  917. X
  918. Xvoid
  919. XZShell::escape_value(const char * value) const
  920. X{
  921. X   for ( ; *value ; value++) {
  922. X      switch (*value) {
  923. X      case '\'' :
  924. X         cout << "'\\''" ;
  925. X         break ;
  926. X
  927. X      case '!' :
  928. X      case '\\' :
  929. X      case '\b' :
  930. X      case '\r' :
  931. X      case '\v' :
  932. X      case '\f' :
  933. X         cout << '\\' ;    // fall thru to default case
  934. X      default :
  935. X         cout << char(*value) ;
  936. X      }
  937. X   } //for
  938. X}
  939. X
  940. X//------------------------------------------------------------------ Plan9Shell
  941. X
  942. Xconst char * Plan9Shell::NAME = "rc" ;
  943. X
  944. XPlan9Shell::Plan9Shell(void)
  945. X{
  946. X}
  947. X
  948. XPlan9Shell::~Plan9Shell(void)
  949. X{
  950. X}
  951. X
  952. Xconst char *
  953. XPlan9Shell::name(void) const
  954. X{
  955. X   return  Plan9Shell::NAME ;
  956. X}
  957. X
  958. Xvoid
  959. XPlan9Shell::unset_args(const char *) const
  960. X{
  961. X   cout << "*=();" << endl ;
  962. X}
  963. X
  964. Xint
  965. XPlan9Shell::is_positionals(const char * name) const
  966. X{
  967. X   name = varname(name, '$');
  968. X   return  (::strcmp(name, "*") == 0);
  969. X}
  970. X
  971. Xvoid
  972. XPlan9Shell::set(const ShellVariable & variable) const
  973. X{
  974. X   const char * name = varname(variable.name(), '$');
  975. X   int  posl = is_positionals(name);
  976. X   cout << name << '=' ;
  977. X   if (posl)  cout << '(' ;
  978. X   cout << '\'' ;
  979. X   escape_value(variable.value());
  980. X   cout << '\'' ;
  981. X   if (posl)  cout << ')' ;
  982. X   cout << ';' << endl ;;
  983. X}
  984. X
  985. Xvoid
  986. XPlan9Shell::set(const ShellArray & array, int ) const
  987. X{
  988. X   cout << varname(array.name(), '$') << "=(" ;
  989. X   for (int  ndx = 0 ; ndx < array.count() ; ndx++) {
  990. X      if (ndx)  cout << ' ' ;
  991. X      cout << '\'' ;
  992. X      escape_value(array[ndx]);
  993. X      cout << '\'' ;
  994. X   }
  995. X   cout << ");" << endl ;
  996. X}
  997. X
  998. Xvoid
  999. XPlan9Shell::escape_value(const char * value) const
  1000. X{
  1001. X   for ( ; *value ; value++) {
  1002. X      switch (*value) {
  1003. X      case '\'' :
  1004. X         cout << "''" ;
  1005. X         break ;
  1006. X
  1007. X      case '\\' :
  1008. X      case '\b' :
  1009. X      case '\r' :
  1010. X      case '\v' :
  1011. X      case '\f' :
  1012. X         cout << '\\' ;    // fall thru to default case
  1013. X      default :
  1014. X         cout << char(*value) ;
  1015. X      }
  1016. X   } //for
  1017. X}
  1018. X
  1019. X//------------------------------------------------------------------- PerlShell
  1020. X
  1021. Xconst char * PerlShell::NAME = "perl" ;
  1022. X
  1023. XPerlShell::PerlShell(void)
  1024. X{
  1025. X   static const char perl_true[]  = "1" ;
  1026. X   static const char perl_false[] = "0" ;
  1027. X
  1028. X      // use different defaults for TRUE and FALSE
  1029. X   ShellCmdArgBool::True(perl_true);
  1030. X   ShellCmdArgBool::False(perl_false);
  1031. X}
  1032. X
  1033. XPerlShell::~PerlShell(void)
  1034. X{
  1035. X}
  1036. X
  1037. Xconst char *
  1038. XPerlShell::name(void) const
  1039. X{
  1040. X   return  PerlShell::NAME ;
  1041. X}
  1042. X
  1043. Xvoid
  1044. XPerlShell::unset_args(const char *) const
  1045. X{
  1046. X   cout << "@ARGV = ();" << endl ;
  1047. X}
  1048. X
  1049. Xint
  1050. XPerlShell::is_positionals(const char * name) const
  1051. X{
  1052. X   name = varname(name, '@');
  1053. X   return  (::strcmp(name, "ARGV") == 0);
  1054. X}
  1055. X
  1056. Xvoid
  1057. XPerlShell::set(const ShellVariable & variable) const
  1058. X{
  1059. X   const char * name = varname(variable.name(), '$');
  1060. X   int array = (*name == '@') ;
  1061. X   cout << (array ? "" : "$") << name << " = " ;
  1062. X   if (array)  cout << '(' ;
  1063. X   cout << '\'' ;
  1064. X   escape_value(variable.value());
  1065. X   cout << '\'' ;
  1066. X   if (array)  cout << ')' ;
  1067. X   cout << ';' << endl ;;
  1068. X}
  1069. X
  1070. Xvoid
  1071. XPerlShell::set(const ShellArray & array, int ) const
  1072. X{
  1073. X   const char * name = varname(array.name(), '@');
  1074. X   int scalar = (*name == '$') ;
  1075. X   cout << (scalar ? "" : "@") << name << " = " ;
  1076. X   cout << (scalar ? '\'' : '(') ;
  1077. X   for (int  ndx = 0 ; ndx < array.count() ; ndx++) {
  1078. X      if (ndx)  cout << (scalar ? " " : ", ") ;
  1079. X      if (! scalar)  cout << '\'' ;
  1080. X      escape_value(array[ndx]);
  1081. X      if (! scalar)  cout << '\'' ;
  1082. X   }
  1083. X   cout << (scalar ? '\'' : ')') ;
  1084. X   cout << ";" << endl ;
  1085. X}
  1086. X
  1087. Xvoid
  1088. XPerlShell::escape_value(const char * value) const
  1089. X{
  1090. X   for ( ; *value ; value++) {
  1091. X      switch (*value) {
  1092. X      case '\t' :  cout << "\\t" ; break ;
  1093. X      case '\n' :  cout << "\\n" ; break ;
  1094. X      case '\b' :  cout << "\\b" ; break ;
  1095. X      case '\r' :  cout << "\\r" ; break ;
  1096. X      case '\v' :  cout << "\\v" ; break ;
  1097. X      case '\f' :  cout << "\\f" ; break ;
  1098. X
  1099. X      case '\'' :
  1100. X      case '\\' :
  1101. X         cout << "\\" ;    // fall thru to default
  1102. X      default :
  1103. X         cout << char(*value) ;
  1104. X      }
  1105. X   } //for
  1106. X}
  1107. X
  1108. X//------------------------------------------------------------------- TclShell
  1109. X
  1110. Xconst char * TclShell::NAME = "tcl" ;
  1111. X
  1112. XTclShell::TclShell(void)
  1113. X{
  1114. X   static const char tcl_true[]  = "1" ;
  1115. X   static const char tcl_false[] = "0" ;
  1116. X
  1117. X      // use different defaults for TRUE and FALSE
  1118. X   ShellCmdArgBool::True(tcl_true);
  1119. X   ShellCmdArgBool::False(tcl_false);
  1120. X}
  1121. X
  1122. XTclShell::~TclShell(void)
  1123. X{
  1124. X}
  1125. X
  1126. Xconst char *
  1127. XTclShell::name(void) const
  1128. X{
  1129. X   return  TclShell::NAME ;
  1130. X}
  1131. X
  1132. Xvoid
  1133. XTclShell::unset_args(const char * name) const
  1134. X{
  1135. X   cout << "set " << varname(name, '$') << " {};" << endl ;
  1136. X}
  1137. X
  1138. Xint
  1139. XTclShell::is_positionals(const char * name) const
  1140. X{
  1141. X   name = varname(name, '$');
  1142. X   return  ((::strcmp(name, "argv") == 0) || (::strcmp(name, "args") == 0));
  1143. X}
  1144. X
  1145. Xvoid
  1146. XTclShell::set(const ShellVariable & variable) const
  1147. X{
  1148. X   const char * name = varname(variable.name(), '$');
  1149. X   cout << "set " << name << ' ' ;
  1150. X   cout << '"' ;
  1151. X   escape_value(variable.value());
  1152. X   cout << '"' ;
  1153. X   cout << ';' << endl ;;
  1154. X}
  1155. X
  1156. Xvoid
  1157. XTclShell::set(const ShellArray & array, int ) const
  1158. X{
  1159. X   const char * name = varname(array.name(), '@');
  1160. X   int scalar = (*name == '$') ;
  1161. X   cout << "set " << name << " [ list " ;
  1162. X   for (int  ndx = 0 ; ndx < array.count() ; ndx++) {
  1163. X      if (ndx)  cout << ' ' ;
  1164. X      cout << '"' ;
  1165. X      escape_value(array[ndx]);
  1166. X      cout << '"' ;
  1167. X   }
  1168. X   cout << " ]" ;
  1169. X   cout << ";" << endl ;
  1170. X}
  1171. X
  1172. Xvoid
  1173. XTclShell::escape_value(const char * value) const
  1174. X{
  1175. X   for ( ; *value ; value++) {
  1176. X      switch (*value) {
  1177. X      case '\t' :  cout << "\\t" ; break ;
  1178. X      case '\n' :  cout << "\\n" ; break ;
  1179. X      case '\b' :  cout << "\\b" ; break ;
  1180. X      case '\r' :  cout << "\\r" ; break ;
  1181. X      case '\v' :  cout << "\\v" ; break ;
  1182. X      case '\f' :  cout << "\\f" ; break ;
  1183. X
  1184. X      case '\'' :
  1185. X      case '\\' :
  1186. X      case '{' :
  1187. X      case '}' :
  1188. X      case '[' :
  1189. X      case ']' :
  1190. X      case '$' :
  1191. X      case ';' :
  1192. X      case '"' :
  1193. X         cout << "\\" ;    // fall thru to default
  1194. X      default :
  1195. X         cout << char(*value) ;
  1196. X      }
  1197. X   } //for
  1198. X}
  1199. X
  1200. END_OF_FILE
  1201. if test 16461 -ne `wc -c <'src/cmd/shells.c'`; then
  1202.     echo shar: \"'src/cmd/shells.c'\" unpacked with wrong size!
  1203. fi
  1204. # end of 'src/cmd/shells.c'
  1205. fi
  1206. if test -f 'src/cmd/shells.h' -a "${1}" != "-c" ; then 
  1207.   echo shar: Will not clobber existing file \"'src/cmd/shells.h'\"
  1208. else
  1209. echo shar: Extracting \"'src/cmd/shells.h'\" \(11983 characters\)
  1210. sed "s/^X//" >'src/cmd/shells.h' <<'END_OF_FILE'
  1211. X//------------------------------------------------------------------------
  1212. X// ^FILE: shells.h - define classes for the various Unix shells
  1213. X//
  1214. X// ^DESCRIPTION:
  1215. X//     This file encapsulates all the information that cmdparse(1) needs
  1216. X//     to know about each of the various shells that it will support.
  1217. X//
  1218. X//     To add a new shell to the list of shells supported here:
  1219. X//        1) Add its class definition in this file.
  1220. X//
  1221. X//        2) Implement its member functions in "shells.h"
  1222. X//           (dont forget the NAME data-member to hold the name).
  1223. X//
  1224. X//        3) Add an "else if" statement for the new shell into
  1225. X//           the virtual constructor UnixShell::UnixShell(const char *).
  1226. X//
  1227. X// ^HISTORY:
  1228. X//    04/19/92    Brad Appleton    <brad@ssd.csd.harris.com>    Created
  1229. X//-^^---------------------------------------------------------------------
  1230. X
  1231. X#ifndef _shells_h
  1232. X#define _shells_h
  1233. X
  1234. X   // A ShellVariable object houses the name and value of a shell
  1235. X   // environment variable.
  1236. X   //
  1237. Xclass  ShellVariable {
  1238. Xpublic:
  1239. X   ShellVariable(const char * name);
  1240. X
  1241. X   virtual ~ShellVariable(void);
  1242. X
  1243. X      // Return the name of this variable
  1244. X   const char *
  1245. X   name(void) const { return  var_name ; }
  1246. X
  1247. X      // Set the value of this variable
  1248. X   void
  1249. X   set(const char * value) { var_value = value; }
  1250. X
  1251. X      // Return the value of this variable
  1252. X   const char *
  1253. X   value(void) const { return  var_value; }
  1254. X
  1255. Xprotected:
  1256. X   const char * var_name ;
  1257. X   const char * var_value ;
  1258. X};
  1259. X
  1260. X
  1261. X   // A ShellArray object houses the name and values of a shell array.
  1262. X   //
  1263. Xstruct  ShellArrayValues;
  1264. Xclass  ShellArray {
  1265. Xpublic:
  1266. X   ShellArray(const char * name);
  1267. X
  1268. X   virtual ~ShellArray(void);
  1269. X
  1270. X      // Return the name of this array
  1271. X   const char *
  1272. X   name(void) const { return  array_name; }
  1273. X
  1274. X      // Append to the list of values in this array
  1275. X   void
  1276. X   append(const char * value);
  1277. X
  1278. X      // Return the number of items in this array.
  1279. X   unsigned
  1280. X   count(void) const;
  1281. X
  1282. X      // Return the desired element of an array
  1283. X      //
  1284. X      // NOTE: the elements range in index from 0 .. count-1,
  1285. X      //       an out-of-range index will result in a run-time
  1286. X      //       NULL-ptr dereferencing error!
  1287. X      //
  1288. X   const char *
  1289. X   operator[](unsigned  index) const;
  1290. X
  1291. Xprotected:
  1292. X   const char       * array_name ;
  1293. X   ShellArrayValues * array_value ;
  1294. X} ;
  1295. X
  1296. X
  1297. X   // AbstractUnixShell is an abstract class for an arbitrary Unix shell
  1298. X   // program.  It represents all the functionality that cmdparse(1)
  1299. X   // requires of a command-interpreter.
  1300. X   //
  1301. Xclass  AbstractUnixShell {
  1302. Xpublic:
  1303. X   virtual
  1304. X   ~AbstractUnixShell(void);
  1305. X
  1306. X      // Return the name of this shell
  1307. X   virtual  const char *
  1308. X   name(void) const = 0;
  1309. X
  1310. X      // Does "name" correspond to the positional-parameters for this shell?
  1311. X   virtual  int
  1312. X   is_positionals(const char * name) const = 0;
  1313. X
  1314. X      // Unset the positional parameters of this shell.
  1315. X      //
  1316. X      // The parameter "name" is the name of a shell variable
  1317. X      // for which is_positionals() returns TRUE.
  1318. X      //
  1319. X   virtual  void
  1320. X   unset_args(const char * name) const = 0;
  1321. X
  1322. X      // Set the given variable name to the given value
  1323. X   virtual  void
  1324. X   set(const ShellVariable & variable) const = 0;
  1325. X
  1326. X      // Set the given array name to the given values.
  1327. X      // Some shells have more than one way to set an array.
  1328. X      // Such shells should label these varying methods as
  1329. X      // variant0 .. variantN, the desired variant method to use
  1330. X      // (which defaults to zero), should be indicated by the
  1331. X      // last parameter.
  1332. X      //
  1333. X      // This member function is responsible for checking to see
  1334. X      // if the array name corresponds to the positional-parameters
  1335. X      // (and for behaving accordingly if this is the case).
  1336. X      //
  1337. X   virtual  void
  1338. X   set(const ShellArray & array, int variant) const = 0;
  1339. X
  1340. Xprotected:
  1341. X   AbstractUnixShell(void) {};
  1342. X
  1343. X} ;
  1344. X
  1345. X
  1346. X   // UnixShell is used as an envelope class (using its siblings as
  1347. X   // letter classes). It is a "shell" that does not decide what
  1348. X   // type of shell it is until runtime.
  1349. X   // 
  1350. Xclass  UnixShell {
  1351. Xpublic:
  1352. X      // This is a virtual constructor that constructs a Unix shell object
  1353. X      // that is the appropriate derived class of AbstractUnixShell.
  1354. X      //
  1355. X   UnixShell(const char * shell_name);
  1356. X
  1357. X   virtual
  1358. X   ~UnixShell(void);
  1359. X
  1360. X      // See if this shell is valid
  1361. X   int
  1362. X   is_valid(void) const { return  (valid) ? 1 : 0; }
  1363. X
  1364. X      // Return the name of this shell
  1365. X   virtual  const char *
  1366. X   name(void) const;
  1367. X
  1368. X   virtual  void
  1369. X   unset_args(const char * name) const;
  1370. X
  1371. X   virtual  int
  1372. X   is_positionals(const char * name) const;
  1373. X
  1374. X   virtual  void
  1375. X   set(const ShellVariable & variable) const;
  1376. X
  1377. X   virtual  void
  1378. X   set(const ShellArray & array, int variant) const;
  1379. X
  1380. Xprivate:
  1381. X   unsigned    valid : 1 ;
  1382. X   AbstractUnixShell * shell;
  1383. X
  1384. X} ;
  1385. X
  1386. X
  1387. X   // BourneShell (sh) - the most common of the Unix Shells - implemented
  1388. X   //                    by Stephen R. Bourne
  1389. X   //
  1390. X   // Variables are set using:
  1391. X   //      name='value';
  1392. X   //
  1393. X   // Arrays (by default) are set using:
  1394. X   //      name='value1 value2 value3 ...';
  1395. X   //
  1396. X   // but if requested, the following array-variant will be used instead:
  1397. X   //      name_count=N;
  1398. X   //      name1='value1';
  1399. X   //      name2='value2';
  1400. X   //          ...
  1401. X   //      nameN='valueN';
  1402. X   //
  1403. X   // If a variable name matches one of "@", "*", "-", or "--", then the 
  1404. X   // variable is assumed to refer to the positional-parameters of the
  1405. X   // shell-script and the following syntax will be used:
  1406. X   //      set -- 'value1' 'value2' 'value3' ...
  1407. X   //
  1408. Xclass  BourneShell : public  AbstractUnixShell {
  1409. Xpublic:
  1410. X   BourneShell(void);
  1411. X
  1412. X   virtual  ~BourneShell(void);
  1413. X
  1414. X   virtual  const char *
  1415. X   name(void) const;
  1416. X
  1417. X   virtual  void
  1418. X   unset_args(const char * name) const;
  1419. X
  1420. X   virtual  int
  1421. X   is_positionals(const char * name) const;
  1422. X
  1423. X   virtual  void
  1424. X   set(const ShellVariable & variable) const;
  1425. X
  1426. X   virtual  void
  1427. X   set(const ShellArray & array, int variant) const;
  1428. X
  1429. X   static const char * NAME ;
  1430. X
  1431. Xprotected:
  1432. X   void
  1433. X   escape_value(const char * value) const;
  1434. X
  1435. Xprivate:
  1436. X
  1437. X} ;
  1438. X
  1439. X
  1440. X   // KornShell (ksh) -- David G. Korn's reimplementation of the Bourne shell
  1441. X   //
  1442. X   // Variables are set using the same syntax as in the Bourne Shell.
  1443. X   //
  1444. X   // Arrays (by default) are set using:
  1445. X   //      set -A name 'value1' 'value2' 'value3' ...;
  1446. X   //
  1447. X   // but if requested, the following array-variant will be used instead:
  1448. X   //      set +A name 'value1' 'value2' 'value3' ...;
  1449. X   //
  1450. X   // If a variable name matches one of "@", "*", "-", or "--", then the 
  1451. X   // variable is assumed to refer to the positional-parameters of the
  1452. X   // shell-script and the following syntax will be used:
  1453. X   //      set -- 'value1' 'value2' 'value3' ...
  1454. X   //
  1455. Xclass  KornShell : public BourneShell {
  1456. Xpublic:
  1457. X   KornShell(void);
  1458. X
  1459. X   virtual  ~KornShell(void);
  1460. X
  1461. X   virtual  const char *
  1462. X   name(void) const;
  1463. X
  1464. X   virtual  void
  1465. X   unset_args(const char * name) const;
  1466. X
  1467. X   virtual  void
  1468. X   set(const ShellVariable & variable) const;
  1469. X
  1470. X   virtual  void
  1471. X   set(const ShellArray & array, int variant) const;
  1472. X
  1473. X   static const char * NAME ;
  1474. X
  1475. Xprotected:
  1476. X
  1477. Xprivate:
  1478. X
  1479. X} ;
  1480. X
  1481. X
  1482. X   // BourneAgainShell (bash) -- The Free Software Foundation's answer to ksh
  1483. X   //
  1484. X   // bash is treated exactlt like the Bourne Shell, this will change when
  1485. X   // bash supports arrays.
  1486. X   //
  1487. Xclass  BourneAgainShell : public BourneShell {
  1488. Xpublic:
  1489. X   BourneAgainShell(void);
  1490. X
  1491. X   virtual  ~BourneAgainShell(void);
  1492. X
  1493. X   virtual  const char *
  1494. X   name(void) const;
  1495. X
  1496. X   virtual  void
  1497. X   set(const ShellVariable & variable) const;
  1498. X
  1499. X   virtual  void
  1500. X   set(const ShellArray & array, int variant) const;
  1501. X
  1502. X   static const char * NAME ;
  1503. X
  1504. Xprotected:
  1505. X
  1506. Xprivate:
  1507. X
  1508. X} ;
  1509. X
  1510. X
  1511. X   // CShell (csh) -- Bill Joy's rewrite of "sh" with C like syntax.
  1512. X   //                 this will work for tcsh and itcsh as well.
  1513. X   //
  1514. X   // Variables are set using:
  1515. X   //      set name='value';
  1516. X   //
  1517. X   // Arrays (by default) are set using:
  1518. X   //      set name=('value1' 'value2' 'value3' ...);
  1519. X   //
  1520. Xclass  CShell : public AbstractUnixShell {
  1521. Xpublic:
  1522. X   CShell(void);
  1523. X
  1524. X   virtual  ~CShell(void);
  1525. X
  1526. X   virtual  const char *
  1527. X   name(void) const;
  1528. X
  1529. X   virtual  void
  1530. X   unset_args(const char * name) const;
  1531. X
  1532. X   virtual  int
  1533. X   is_positionals(const char * name) const;
  1534. X
  1535. X   virtual  void
  1536. X   set(const ShellVariable & variable) const;
  1537. X
  1538. X   virtual  void
  1539. X   set(const ShellArray & array, int variant) const;
  1540. X
  1541. X   static const char * NAME ;
  1542. X
  1543. Xprotected:
  1544. X   void
  1545. X   escape_value(const char * value) const;
  1546. X
  1547. Xprivate:
  1548. X
  1549. X} ;
  1550. X
  1551. X
  1552. X   // ZShell (zsh) -- Paul Falstad's shell combining lots of stuff from
  1553. X   //                 csh and ksh and some stuff of his own.
  1554. X   //
  1555. X   // Variables are set using:
  1556. X   //    name='value';
  1557. X   //
  1558. X   // Arrays are set using:
  1559. X   //    name=('value1' 'value2' 'value3' ...);
  1560. X   //
  1561. X   // If a variable name matches one of "@", "*", "-", "--", or "argv" then
  1562. X   // the variable is assumed to refer to the positional-parameters of the
  1563. X   // shell-script and the following syntax will be used:
  1564. X   //    argv=('value1' 'value2' 'value3' ...);
  1565. X   //
  1566. Xclass  ZShell : public AbstractUnixShell {
  1567. Xpublic:
  1568. X   ZShell(void);
  1569. X
  1570. X   virtual  ~ZShell(void);
  1571. X
  1572. X   virtual  const char *
  1573. X   name(void) const;
  1574. X
  1575. X   virtual  void
  1576. X   unset_args(const char * name) const;
  1577. X
  1578. X   virtual  int
  1579. X   is_positionals(const char * name) const;
  1580. X
  1581. X   virtual  void
  1582. X   set(const ShellVariable & variable) const;
  1583. X
  1584. X   virtual  void
  1585. X   set(const ShellArray & array, int variant) const;
  1586. X
  1587. X   static const char * NAME ;
  1588. X
  1589. Xprotected:
  1590. X   void
  1591. X   escape_value(const char * value) const;
  1592. X
  1593. Xprivate:
  1594. X
  1595. X} ;
  1596. X
  1597. X
  1598. X   // Plan9Shell (rc) -- Tom Duff's shell from the Plan 9 papers.
  1599. X   //        A public domain version (with some enhancements) was
  1600. X   //        written by Byron Rakitzis.
  1601. X   //
  1602. X   // Variables are set using:
  1603. X   //    name='value';
  1604. X   //
  1605. X   // Arrays are set using:
  1606. X   //    name=('value1' 'value2' 'value3' ...);
  1607. X   //
  1608. Xclass  Plan9Shell : public AbstractUnixShell {
  1609. Xpublic:
  1610. X   Plan9Shell(void);
  1611. X
  1612. X   virtual  ~Plan9Shell(void);
  1613. X
  1614. X   virtual  const char *
  1615. X   name(void) const;
  1616. X
  1617. X   virtual  void
  1618. X   unset_args(const char * name) const;
  1619. X
  1620. X   virtual  int
  1621. X   is_positionals(const char * name) const;
  1622. X
  1623. X   virtual  void
  1624. X   set(const ShellVariable & variable) const;
  1625. X
  1626. X   virtual  void
  1627. X   set(const ShellArray & array, int variant) const;
  1628. X
  1629. X   static const char * NAME ;
  1630. X
  1631. Xprotected:
  1632. X   void
  1633. X   escape_value(const char * value) const;
  1634. X
  1635. Xprivate:
  1636. X
  1637. X} ;
  1638. X
  1639. X
  1640. X   // Perl (perl) -- Larry Wall's Practical Extraction and Report Generation
  1641. X   //                utility.
  1642. X   //
  1643. X   // Variables are set using:
  1644. X   //    $name = 'value';
  1645. X   //
  1646. X   // Arrays are set using:
  1647. X   //    @name = ('value1', 'value2', 'value3', ...);
  1648. X   //
  1649. Xclass  PerlShell : public AbstractUnixShell {
  1650. Xpublic:
  1651. X   PerlShell(void);
  1652. X
  1653. X   virtual  ~PerlShell(void);
  1654. X
  1655. X   virtual  const char *
  1656. X   name(void) const;
  1657. X
  1658. X   virtual  void
  1659. X   unset_args(const char * name) const;
  1660. X
  1661. X   virtual  int
  1662. X   is_positionals(const char * name) const;
  1663. X
  1664. X   virtual  void
  1665. X   set(const ShellVariable & variable) const;
  1666. X
  1667. X   virtual  void
  1668. X   set(const ShellArray & array, int variant) const;
  1669. X
  1670. X   static const char * NAME ;
  1671. X
  1672. Xprotected:
  1673. X   void
  1674. X   escape_value(const char * value) const;
  1675. X
  1676. Xprivate:
  1677. X
  1678. X} ;
  1679. X
  1680. X
  1681. X   // Tcl -- Karl Lehenbauer and friends implementation of a shell based
  1682. X   //        on John K. Ousterhout's Tool Command Language
  1683. X   //
  1684. X   // Variables are set using:
  1685. X   //    set name "value";
  1686. X   //
  1687. X   // Arrays are set using:
  1688. X   //     set name [list "value1" "value2" "value3" ...];
  1689. X   //
  1690. Xclass  TclShell : public AbstractUnixShell {
  1691. Xpublic:
  1692. X   TclShell(void);
  1693. X
  1694. X   virtual  ~TclShell(void);
  1695. X
  1696. X   virtual  const char *
  1697. X   name(void) const;
  1698. X
  1699. X   virtual  void
  1700. X   unset_args(const char * name) const;
  1701. X
  1702. X   virtual  int
  1703. X   is_positionals(const char * name) const;
  1704. X
  1705. X   virtual  void
  1706. X   set(const ShellVariable & variable) const;
  1707. X
  1708. X   virtual  void
  1709. X   set(const ShellArray & array, int variant) const;
  1710. X
  1711. X   static const char * NAME ;
  1712. X
  1713. Xprotected:
  1714. X   void
  1715. X   escape_value(const char * value) const;
  1716. X
  1717. Xprivate:
  1718. X
  1719. X} ;
  1720. X
  1721. X
  1722. X#endif  /* _shells_h */
  1723. END_OF_FILE
  1724. if test 11983 -ne `wc -c <'src/cmd/shells.h'`; then
  1725.     echo shar: \"'src/cmd/shells.h'\" unpacked with wrong size!
  1726. fi
  1727. # end of 'src/cmd/shells.h'
  1728. fi
  1729. if test -f 'src/cmd/syntax.c' -a "${1}" != "-c" ; then 
  1730.   echo shar: Will not clobber existing file \"'src/cmd/syntax.c'\"
  1731. else
  1732. echo shar: Extracting \"'src/cmd/syntax.c'\" \(11234 characters\)
  1733. sed "s/^X//" >'src/cmd/syntax.c' <<'END_OF_FILE'
  1734. X//------------------------------------------------------------------------
  1735. X// ^FILE: syntax.c - implement the ArgSyntax class
  1736. X//
  1737. X// ^DESCRIPTION:
  1738. X//    This file uses a SyntaxFSM to implement a class to parse an argument
  1739. X//    syntax string from input and to hold the "compiled" result.
  1740. X//
  1741. X// ^HISTORY:
  1742. X//    03/25/92    Brad Appleton    <brad@ssd.csd.harris.com>    Created
  1743. X//-^^---------------------------------------------------------------------
  1744. X
  1745. X#include <stdlib.h>
  1746. X#include <iostream.h>
  1747. X#include <string.h>
  1748. X#include <ctype.h>
  1749. X
  1750. X#include <cmdline.h>
  1751. X
  1752. X#include "syntax.h"
  1753. X#include "quoted.h"
  1754. X
  1755. X//------------------------------------------------------------------ copy_token
  1756. X
  1757. X//-------------------
  1758. X// ^FUNCTION: copy_token - copy into a token
  1759. X//
  1760. X// ^SYNOPSIS:
  1761. X//    copy_token(dest, src)
  1762. X//
  1763. X// ^PARAMETERS:
  1764. X//    const char * & dest;
  1765. X//    -- where to house the duplicated token
  1766. X//
  1767. X//    SyntaxFSM::token_t src;
  1768. X//    -- the token to copy.
  1769. X//
  1770. X// ^DESCRIPTION:
  1771. X//    Duplicate the token denoted by "src" into "dest".
  1772. X//
  1773. X// ^REQUIREMENTS:
  1774. X//    None.
  1775. X//
  1776. X// ^SIDE-EFFECTS:
  1777. X//    Allocates storage for "dest" is token length is non-zero.
  1778. X//
  1779. X// ^RETURN-VALUE:
  1780. X//    None.
  1781. X//
  1782. X// ^ALGORITHM:
  1783. X//    Trivial.
  1784. X//-^^----------------
  1785. Xvoid
  1786. Xcopy_token(const char * & dest, SyntaxFSM::token_t src)
  1787. X{
  1788. X   char * tok = new char[src.len + 1] ;
  1789. X   ::strncpy(tok, src.start, src.len);
  1790. X   tok[src.len] = '\0';
  1791. X   dest = tok;
  1792. X}
  1793. X
  1794. X//---------------------------------------------------------------- ArgSyntax
  1795. X
  1796. X//-------------------
  1797. X// ^FUNCTION: parse_syntax - parse syntax string
  1798. X//
  1799. X// ^SYNOPSIS:
  1800. X//    parse_syntax(str)
  1801. X//
  1802. X// ^PARAMETERS:
  1803. X//    const char * str;
  1804. X//    -- the string (containing the argument syntax) to parse.
  1805. X//
  1806. X// ^DESCRIPTION:
  1807. X//    Parse the syntax-string and compile it into an internal format
  1808. X//    (namely an ArgSyntax object).
  1809. X//
  1810. X// ^REQUIREMENTS:
  1811. X//    "str" should correspond to the following:
  1812. X//
  1813. X//       [<KEYWORD-SPEC>] [<VALUE-SPEC>]
  1814. X//
  1815. X//    Where <KEYWORD-SPEC> is of the form:
  1816. X//       c|keyword
  1817. X//
  1818. X//    Where 'c' is the option-character and "keyword" is the keyword.
  1819. X//
  1820. X//    (There must be no spaces surrounding the '|', if there arem then a space
  1821. X//    before the '|' means an "empty" option and a space after the '|' means
  1822. X//    an empty keyword).
  1823. X//
  1824. X//    <VALUE-SPEC> should look like:
  1825. X//        value [...]
  1826. X//
  1827. X//    Where "value" is the value name and "..." indicates the value is really
  1828. X//    a list of values. The entire VALUE-SPEC should be surrounded by '[' and
  1829. X//    ']' if the value is optional.
  1830. X//
  1831. X//    If the argument itself is optional then the entire syntax string
  1832. X//    should be inside of square brackets.
  1833. X//
  1834. X//    Lastly - a positional AND keyword argument may be denoted by
  1835. X//        "[c|keyword] value"
  1836. X//
  1837. X// ^SIDE-EFFECTS:
  1838. X//    - modifies all parts of the ArgSyntax object.
  1839. X//    - prints syntax error messages on cout.
  1840. X//
  1841. X// ^RETURN-VALUE:
  1842. X//    None.
  1843. X//
  1844. X// ^ALGORITHM:
  1845. X//    Too complicated to be described here - follow along.
  1846. X//-^^----------------
  1847. Xint
  1848. XArgSyntax::parse_syntax(const char * syntax)
  1849. X{
  1850. X   const char * ptr = syntax;
  1851. X   SyntaxFSM  fsm;
  1852. X   SyntaxFSM::token_t  token;
  1853. X
  1854. X   while (fsm(ptr, token)) {
  1855. X      switch(fsm.state()) {
  1856. X      case  SyntaxFSM::OPTION :
  1857. X         // We have an option character - save it and move on
  1858. X         if (token.len)  arg_char = *(token.start) ;
  1859. X         if (! fsm.level())  arg_syntax |= CmdArg::isREQ;
  1860. X         break;
  1861. X
  1862. X      case  SyntaxFSM::KEYWORD :
  1863. X         // We have a keyword - save it and move on
  1864. X         ::copy_token(arg_keyword, token);
  1865. X         if (! fsm.level())  arg_syntax |= CmdArg::isREQ;
  1866. X         break;
  1867. X
  1868. X      case  SyntaxFSM::VALUE :
  1869. X         // We have a value - save it and call parse_value to
  1870. X         // figure out what the flags are.
  1871. X         //
  1872. X         if (token.len)  ::copy_token(arg_value, token);
  1873. X         parse_value(fsm);
  1874. X         break;
  1875. X
  1876. X      case  SyntaxFSM::LIST :
  1877. X         // We have an ellipsis -- update the syntax flags
  1878. X         arg_syntax |= CmdArg::isLIST;
  1879. X         break;
  1880. X
  1881. X      case  SyntaxFSM::ERROR :
  1882. X         // Error!
  1883. X         cerr << "syntax error in \"" << syntax << "\"." << endl ;
  1884. X         return  -1;
  1885. X
  1886. X      default :
  1887. X         cerr << "internal error in class SyntaxFSM.\n\tunexpected state "
  1888. X              << "(" << fsm.state() << ") encountered." << endl ;
  1889. X         return  -1;
  1890. X      } //switch
  1891. X   } //while
  1892. X
  1893. X   return  0;
  1894. X}
  1895. X
  1896. X
  1897. X//-------------------
  1898. X// ^FUNCTION: parse_value - parse an argument value
  1899. X//
  1900. X// ^SYNOPSIS:
  1901. X//    parse_value(fsm)
  1902. X//
  1903. X// ^PARAMETERS:
  1904. X//    const SyntaxFSM & fsm;
  1905. X//    -- the finite-state machine that is reading input.
  1906. X//
  1907. X// ^DESCRIPTION:
  1908. X//    The "value" has already been read and saved, we need to figure out
  1909. X//    what syntax_flags to associate with the argument.
  1910. X//
  1911. X// ^REQUIREMENTS:
  1912. X//    "fsm" MUST be in the SyntaxFSM::VALUE state!
  1913. X//
  1914. X// ^SIDE-EFFECTS:
  1915. X//    Modifies the arg_syntax flags of an ArgSyntax object.
  1916. X//
  1917. X// ^RETURN-VALUE:
  1918. X//    None.
  1919. X//
  1920. X// ^ALGORITHM:
  1921. X//    Too complicated to be described here - follow along.
  1922. X//
  1923. X//-^^----------------
  1924. Xvoid
  1925. XArgSyntax::parse_value(const SyntaxFSM & fsm)
  1926. X{
  1927. X   // Each of the possibilities we encounter in the SyntaxFSM::VALUE state
  1928. X   // will correspond to some combination of num_tokens, num_braces, and
  1929. X   // level. Let us determine all the valid possibilites below:
  1930. X   //
  1931. X   //   (num_tokens, num_braces, level)            syntax-string
  1932. X   //   -------------------------------     ---------------------------
  1933. X   //             (1, 0, 0)                      "value"
  1934. X   //             (1, 0, 1)                      "[value]"
  1935. X   //             (3, 0, 0)                      "c|string value"
  1936. X   //             (3, 0, 1)                      "c|string [value]"
  1937. X   //             (3, 0, 1)                      "[c|string value]"
  1938. X   //             (3, 0, 2)                      "[c|string [value]]"
  1939. X   //             (3, 1, 0)                      "[c|string] value"
  1940. X   //             (3, 1, 1)                      "[c|string] [value]"
  1941. X   //             (3, 1, 1)                      "[[c|string] value]"
  1942. X   //
  1943. X   // There are only two case where a given (num_token, num_braces, level)
  1944. X   // combination corresponds to more than one possible syntax-string. These
  1945. X   // two cases are (3, 0, 1) and (3, 1, 1). We can ignore the "ambiguity"
  1946. X   // of (3, 1, 1) because although the two possible syntax-strings are
  1947. X   // different, they mean exactly the same thing. (3, 0, 1) is a different
  1948. X   // case however: how do we tell if the whole argument is optional or if
  1949. X   // just the value is optional? If the whole argument is required (meaning
  1950. X   // "not optional") then we will already have set the isREQ flag when we
  1951. X   // parsed the option and/or the keyword name.
  1952. X   //
  1953. X   if (fsm.num_tokens() == 1) {
  1954. X      // cases (1, 0, 0) and (1, 0, 1)
  1955. X      arg_syntax |= CmdArg::isPOS;
  1956. X      if (! fsm.level()) {
  1957. X         arg_syntax |= (CmdArg::isREQ | CmdArg::isVALREQ);
  1958. X      } else {
  1959. X         arg_syntax |= (CmdArg::isOPT | CmdArg::isVALOPT);
  1960. X      }
  1961. X   } else {
  1962. X      if (fsm.num_braces()) {
  1963. X         // cases (3, 1, 0) and (3, 1, 1)
  1964. X         arg_syntax |= CmdArg::isPOS;
  1965. X         if (! fsm.level()) {
  1966. X            // case (3, 1, 0)
  1967. X            arg_syntax |= (CmdArg::isREQ | CmdArg::isVALREQ);
  1968. X         } else {
  1969. X            // case (3, 1, 1)
  1970. X            arg_syntax |= (CmdArg::isOPT | CmdArg::isVALOPT);
  1971. X         }
  1972. X      } else {
  1973. X         if (! fsm.level()) {
  1974. X            // case (3, 0, 0)
  1975. X            arg_syntax |= (CmdArg::isREQ | CmdArg::isVALREQ);
  1976. X         } else if (fsm.level() == 1) {
  1977. X            // case (3, 0, 1)
  1978. X            if (arg_syntax & CmdArg::isREQ) {
  1979. X               arg_syntax |= CmdArg::isVALOPT;
  1980. X            } else {
  1981. X               arg_syntax |= CmdArg::isVALREQ;
  1982. X            }
  1983. X         } else {
  1984. X            // case (3, 0, 2)
  1985. X            arg_syntax |= CmdArg::isVALOPT;
  1986. X         } //if level
  1987. X      } //if num-braces
  1988. X   } //if num-tokens
  1989. X}
  1990. X
  1991. X
  1992. X//-------------------
  1993. X// ^FUNCTION: parse_flag - parse a flag
  1994. X//
  1995. X// ^SYNOPSIS:
  1996. X//    parse_flag(is)
  1997. X//
  1998. X// ^PARAMETERS:
  1999. X//    istream & is;
  2000. X//    -- the input stream to read the flag from.
  2001. X//
  2002. X// ^DESCRIPTION:
  2003. X//    By specifying a string that is accepted by "parse_syntax" one
  2004. X//    can specify almost any combination of CmdArg::SyntaxFlags. 
  2005. X//    The only ones that cannot be specified in this manner are the
  2006. X//    CmdArg::isVALSTICKY and CmdArg::isVALSEP flags. In order to
  2007. X//    specify these flags, we allow the syntax string to be followed
  2008. X//    by a colon (':') and one of "SEPARATE" or "STICKY".
  2009. X//
  2010. X// ^REQUIREMENTS:
  2011. X//    None.
  2012. X//
  2013. X// ^SIDE-EFFECTS:
  2014. X//    - modifies the syntax-flags of an ArgSyntax object.
  2015. X//    - prints syntax error messages on stderr.
  2016. X//    - modifies the state of "is" if an error occurs.
  2017. X//    - consumes characters from is.
  2018. X//
  2019. X// ^RETURN-VALUE:
  2020. X//    A reference to the input stream used.
  2021. X//
  2022. X// ^ALGORITHM:
  2023. X//    Trivial.
  2024. X//-^^----------------
  2025. Xistream &
  2026. XArgSyntax::parse_flag(istream & is)
  2027. X{
  2028. X   char  ch;
  2029. X   is >> ch;
  2030. X   if (! is)  return  is;
  2031. X
  2032. X      // If `ch' is a quote then the flags were omitted
  2033. X   if ((ch == '\'') || (ch == '"')) {
  2034. X      is.putback(ch);
  2035. X      return  is ;
  2036. X   }
  2037. X
  2038. X      // The flags are here, make sure they start with ':'
  2039. X   if (ch != ':') {
  2040. X      cerr << "Unexpected token after syntax string.\n"
  2041. X           << "\texpecting a colon, or a double or single quote." << endl ;
  2042. X      is.clear(ios::failbit);
  2043. X      return  is;
  2044. X   }
  2045. X
  2046. X      // Now parse the flag
  2047. X   char  arg_flag[16];
  2048. X   is.width(sizeof(arg_flag) - 1);
  2049. X   is >> arg_flag;
  2050. X   if (! is) {
  2051. X      if (is.eof()) {
  2052. X         cerr << "Error - premature end-of-input.\n"
  2053. X              << "\texpecting one of \"sticky\" or \"separate\"." << endl ; 
  2054. X      } else {
  2055. X         cerr << "Unable to extract argument flag." << endl ;
  2056. X      }
  2057. X      return  is;
  2058. X   }
  2059. X   char * flag = arg_flag;
  2060. X
  2061. X      // Skip any leading "CmdArg::isVAL" portion of the flag      
  2062. X   if (CmdLine::strmatch("Cmd", flag, 3) == CmdLine::str_EXACT)  flag += 3;
  2063. X   if (CmdLine::strmatch("Arg", flag, 3) == CmdLine::str_EXACT)  flag += 3;
  2064. X   if (CmdLine::strmatch("::", flag, 2) == CmdLine::str_EXACT)   flag += 2;
  2065. X   if (CmdLine::strmatch("is", flag, 2) == CmdLine::str_EXACT)   flag += 2;
  2066. X   while ((*flag == '_') || (*flag == '-'))  ++flag;
  2067. X   if (CmdLine::strmatch("VAL", flag, 3) == CmdLine::str_EXACT)  flag += 3;
  2068. X   while ((*flag == '_') || (*flag == '-'))  ++flag;
  2069. X
  2070. X      // check for an ambiguous flag
  2071. X   if (((*flag == 's') || (*flag == 'S')) && (! *(flag + 1))) {
  2072. X      cerr << "Ambiguous flag \"" << flag << "\"." << endl ;
  2073. X      is.clear(ios::failbit);
  2074. X      return  is;
  2075. X   }
  2076. X
  2077. X   if (CmdLine::strmatch("Sticky", flag) != CmdLine::str_NONE) {
  2078. X      arg_syntax |= CmdArg::isVALSTICKY ;
  2079. X   } else if (CmdLine::strmatch("Separate", flag) != CmdLine::str_NONE) {
  2080. X      arg_syntax |= CmdArg::isVALSEP ;
  2081. X   } else {
  2082. X      cerr << "Invalid flag \"" << flag << "\".\n"
  2083. X           << "\tmust be one of \"sticky\" or \"separate\"." << endl ;
  2084. X      is.clear(ios::failbit);
  2085. X      return  is;
  2086. X   }
  2087. X
  2088. X   return  is ;
  2089. X}
  2090. X
  2091. X//------------------------------------------------------------------ operator>>
  2092. X
  2093. Xistream &
  2094. Xoperator>>(istream & is, ArgSyntax & arg)
  2095. X{
  2096. X   QuotedString  qstr(256);
  2097. X
  2098. X   is >> qstr ;
  2099. X   if (! is)  return  is;
  2100. X
  2101. X   if (arg.parse_syntax(qstr))  return  is;
  2102. X   return  arg.parse_flag(is);
  2103. X}
  2104. X
  2105. END_OF_FILE
  2106. if test 11234 -ne `wc -c <'src/cmd/syntax.c'`; then
  2107.     echo shar: \"'src/cmd/syntax.c'\" unpacked with wrong size!
  2108. fi
  2109. # end of 'src/cmd/syntax.c'
  2110. fi
  2111. echo shar: End of archive 4 \(of 7\).
  2112. cp /dev/null ark4isdone
  2113. MISSING=""
  2114. for I in 1 2 3 4 5 6 7 ; do
  2115.     if test ! -f ark${I}isdone ; then
  2116.     MISSING="${MISSING} ${I}"
  2117.     fi
  2118. done
  2119. if test "${MISSING}" = "" ; then
  2120.     echo You have unpacked all 7 archives.
  2121.     rm -f ark[1-9]isdone
  2122. else
  2123.     echo You still need to unpack the following archives:
  2124.     echo "        " ${MISSING}
  2125. fi
  2126. ##  End of shell archive.
  2127. exit 0
  2128.  
  2129. exit 0 # Just in case...
  2130.