home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #16 / NN_1992_16.iso / spool / comp / sources / misc / 3775 < prev    next >
Encoding:
Text File  |  1992-07-26  |  57.0 KB  |  2,138 lines

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