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

  1. Newsgroups: comp.sources.misc
  2. From: brad@hcx1.ssd.csd.harris.com (Brad Appleton)
  3. Subject:  v31i050:  cmdline - C++ Library for parsing command-line arguments, Part03/07
  4. Message-ID: <1992Jul27.020525.29278@sparky.imd.sterling.com>
  5. X-Md4-Signature: 06b4e7c6c6ad6239de5adbe17530fb1a
  6. Date: Mon, 27 Jul 1992 02:05:25 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 50
  11. Archive-name: cmdline/part03
  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 3 (of 7)."
  21. # Contents:  Overview src/lib/cmdarg.c src/lib/cmdline.c
  22. #   src/lib/cmdtest.c src/lib/dump.c src/lib/strindent.c
  23. #   src/lib/usage.c
  24. # Wrapped by brad@hcx1 on Mon Jul 20 10:41:28 1992
  25. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  26. if test -f 'Overview' -a "${1}" != "-c" ; then 
  27.   echo shar: Will not clobber existing file \"'Overview'\"
  28. else
  29. echo shar: Extracting \"'Overview'\" \(10504 characters\)
  30. sed "s/^X//" >'Overview' <<'END_OF_FILE'
  31. X
  32. X                    An overview of CmdLine and cmdparse
  33. X                    ===================================
  34. X
  35. X                 by Brad Appleton <brad@ssd.csd.harris.com>
  36. X
  37. X
  38. X
  39. X Introduction
  40. X ------------
  41. X CmdLine is a C++ Library for parsing command-line arguments. It is 
  42. X approximately 2000 lines of C++ code (excluding comments).
  43. X
  44. X Cmdparse is a command-line interface to CmdLine for Unix shell-scripts.
  45. X It is approximately 1200 lines of C++ code (excluding comments).
  46. X
  47. X
  48. X CmdLine(3C++)
  49. X -------------
  50. X CmdLine is a set of classes to parse command-line arguments.  Unlike
  51. X getopt() and its variants, CmdLine does more than just split up the
  52. X command-line into some canonical form.  CmdLine will actually parse
  53. X the command-line, assigning the appropriate command-line values to
  54. X the corresponding variables, and will verify the command-line syntax
  55. X (and print a usage message if necessary) all in one member function
  56. X call.  Furthermore, many features of CmdLine's parsing behavior are
  57. X configurable at run-time.  These features include the following:
  58. X
  59. X     o  Prompting the user for missing arguments.
  60. X     o  Allowing keywords (-count=4) and/or options (-c4).
  61. X     o  Ignoring bad syntax instead of terminating.
  62. X     o  Ignoring upper/lower case on the command-line.
  63. X     o  Suppressing the printing of syntax error messages.
  64. X     o  Controlling the verboseness of usage messages.
  65. X     o  Controlling whether or not options may be processed
  66. X          after positional parameters have been seen.
  67. X
  68. X CmdLine also allows for options that take an optional argument, options
  69. X that take a (possibly optional) list of one or more arguments, options
  70. X whose argument must reside in the same token as the option itself, and
  71. X options whose argument must reside in a separate token from the option
  72. X itself.
  73. X
  74. X CmdLine consists of a set of C++ classes to parse arguments from an
  75. X input source called a CmdLineArgIter (which is a base class for iterating
  76. X over arguments from an arbitrary input source).  Argument iterators are
  77. X defined for an argv[] array (with or without a corresponding argc), for
  78. X a string of tokens that are separated by a given set of delimiters, and
  79. X for an input-stream.  Users can easily extend CmdLine to parse arguments
  80. X from other input sources simply by creating their own argument iterator
  81. X classes derived from the CmdLineArgIter class defined in <cmdline.h>.
  82. X
  83. X Command-line arguments are themselves objects that contain a specific
  84. X command-line interface, and a function that performs the desired actions
  85. X when its corresponding argument is seen on the command line.  Predefined
  86. X command-line argument types (derived from the abstract class CmdArg in
  87. X <cmdline.h>) exist for boolean, integer, floating-point, character, and
  88. X string arguments, and for lists of integers, floats, and strings.  These
  89. X predefined subclasses of CmdArg may be found in <cmdargs.h>.  Users can
  90. X also create their own command-argument types on the fly by defining and
  91. X implementing an appropriate subclass of the CmdArg class.
  92. X
  93. X Using CmdLine is relatively easy - you need to construct your arguments,
  94. X your command-line, and your argument iterator.  Then all that is left to
  95. X do is call the "parse" member function of your CmdLine object.  The
  96. X following is a simple example:
  97. X
  98. X    #include <stdlib.h>
  99. X    #include <iostream.h>
  100. X    #include <cmdargs.h>
  101. X
  102. X    int  main(int argc, char * argv[])
  103. X    {
  104. X          // Declare arguments
  105. X       CmdArgInt  count('c', "count", "number", "number of copies to print.");
  106. X       CmdArgBool xflag('x', "xmode", "turn on 'x'-mode.");
  107. X       CmdArgChar fdsep('s', "separator", "char", "field-separator to use.");
  108. X       CmdArgStr  input("input-file",  "input file to read.");
  109. X       CmdArgStrList  output("[output-file ...]",  "where to print output.");
  110. X
  111. X          // Declare command object and its argument-iterator
  112. X       CmdLine  cmd(*argv, &count, &xflag, &fdsep, &input, &output, NULL);
  113. X       CmdArgvIter  arg_iter(--argc, ++argv);
  114. X
  115. X          // Initialize arguments to appropriate default values.
  116. X       count = 1;
  117. X       xflag = 0;
  118. X       fdsep = ',';
  119. X
  120. X          // Parse arguments
  121. X       cmd.parse(arg_iter);
  122. X
  123. X          // Print arguments
  124. X       cout << "count=" << count << endl ;
  125. X       cout << "xflag=" << (xflag ? "ON" : "OFF") << endl ;
  126. X       cout << "fdsep='" << (char) fdsep << "'" << endl ;
  127. X       cout << "input=\"" << input << "\"" << endl ;
  128. X       
  129. X       for (int i = 0 ; i < output.count() ; i++) {
  130. X          cout << "output[" << i << "]=" << output[i] << endl ;
  131. X       }
  132. X
  133. X       return  0;
  134. X    }
  135. X
  136. X
  137. X The Unix command-line syntax for the above program would be as follows:
  138. X
  139. X    Usage: progname [-c number] [-x] [-s char] input-file [output-file ...]
  140. X
  141. X    Options/Arguments:
  142. X            -c number        number of copies to print.
  143. X            -x               turn on 'x'-mode.
  144. X            -s char          field-separator to use.
  145. X            input-file       input file to read.
  146. X            output-file ...  where to print output.
  147. X
  148. X
  149. X The Unix command-line syntax using long-options (keywords) for the above
  150. X program would be as follows:
  151. X
  152. X    Usage: progname [--count number] [--xmode] [--separator char]
  153. X                    input-file [output-file ...]
  154. X
  155. X    Options/Arguments:
  156. X            --count number    number of copies to print.
  157. X            --xmode           turn on 'x'-mode.
  158. X            --separator char  field-separator to use.
  159. X            input-file        input file to read.
  160. X            output-file ...   where to print output.
  161. X
  162. X
  163. X By default, CmdLine allows both options and long-options to appear on the
  164. X command-line. You can instruct CmdLine to disallow one or the other however.
  165. X As an "extra", when options are disallowed, the "-" prefix is assumed to
  166. X denote a long-option instead of an option (hence either "-" or "--" denotes
  167. X a keyword in this case).  Using this feature, CmdLine can be used to supply
  168. X the type of long-option syntax that is now becoming quite popular in the
  169. X Unix world. Using this "new" syntax, the command-line syntax for the above
  170. X command would be the following:
  171. X
  172. X    Usage: progname [-count number] [-xmode] [-separator char]
  173. X                    input-file [output-file ...]
  174. X
  175. X    Options/Arguments:
  176. X            -count number    number of copies to print.
  177. X            -xmode           turn on 'x'-mode.
  178. X            -separator char  field-separator to use.
  179. X            input-file       input file to read.
  180. X            output-file ...  where to print output.
  181. X
  182. X
  183. X It should be mentioned that, when long-options are used, only a unique
  184. X prefix of the keyword needs to be given (and character-case is ignored).
  185. X Hence, in the above example, "-x", "-X", and "-xm" will match "-xmode".
  186. X
  187. X
  188. X cmdparse(1)
  189. X -----------
  190. X Using "cmdparse" is even easier than using CmdLine. You declare your
  191. X arguments in a string and then you invoke cmdparse with the command
  192. X line of your shell-script and cmdparse will output a script of variable
  193. X settings for you to evaluate.  The following is an example (using the
  194. X same arguments as in our sample program):
  195. X
  196. X    #!/bin/sh
  197. X    NAME="`/bin/basename $0`"
  198. X
  199. X    ARGS='
  200. X       ArgInt   count  "[c|count number]"    "number of copies to print."
  201. X       ArgBool  xflag  "[x|xmode]"           "turn on x-mode."
  202. X       ArgChar  fdsep  "[s|separator char]"  "field-separator to use."
  203. X       ArgStr   input  "input-file"          "input file to read."
  204. X       ArgStr   output "[output-file ...]"   "where to print output."
  205. X    '
  206. X
  207. X    if  cmdparse -shell=sh -decls="$ARGS" -- $NAME "$@" > tmp$$
  208. X    then
  209. X       . tmp$$
  210. X       /bin/rm -f tmp$$
  211. X    else
  212. X       EXITVAL=$?
  213. X       /bin/rm -f tmp$$
  214. X       exit $EXITVAL
  215. X    fi
  216. X
  217. X    echo "xflag=" $xflag
  218. X    echo "count=" $count
  219. X    echo "fdsep=" $fdsep
  220. X    echo "input=" $input
  221. X    if [ "$output" ] ; then
  222. X       echo "output=" $output
  223. X    fi
  224. X
  225. X
  226. X Note that you declare the syntax of an argument differently for cmdparse
  227. X than for CmdLine. The syntax for a single argument for cmdparse looks like
  228. X the following:
  229. X
  230. X    <arg-type>  <arg-name>  <syntax>  <description>
  231. X
  232. X Where <arg-type> is one of the following:
  233. X
  234. X    ArgInt     --  an integer value (or list of values)
  235. X    ArgFloat   --  a floating-point value (or list of values)
  236. X    ArgChar    --  a character value (or list of values)
  237. X    ArgStr     --  a string value (or list of values)
  238. X    ArgBool    --  a boolean flag that is turned ON
  239. X    ArgClear   --  a boolean flag that is turned OFF
  240. X    ArgToggle  --  a boolean flag that is toggled
  241. X    ArgUsage   --  print usage and exit
  242. X    ArgDummy   -- a dummy argument
  243. X
  244. X If desired, the leading "Arg" portion may be omitted from the type-name.
  245. X
  246. X <arg-name> is simply the name of the variable in your script that you wish
  247. X to contain the resultant value from the command-line.  Any default value
  248. X must be assigned to the variable before invoking cmdparse.
  249. X
  250. X <syntax> and <description> *MUST* be enclosed in either single or double
  251. X quotes! <description> is simply that, the description of the argument.
  252. X <syntax> is a little trickier, there are three basic forms of syntax:
  253. X
  254. X   1)  "c|keyword"        -- an option the takes no value
  255. X   2)  "c|keyword value"  -- an option that takes a value
  256. X   3)  "value"            -- a positional parameter
  257. X
  258. X Note that the option-character MUST precede the keyword-name and that
  259. X there must be NO spaces surrounding the '|' in "c|keyword"!
  260. X
  261. X Any "optional" parts of the argument should appear inside square-brackets
  262. X ('[' and ']') and a list of values is denoted by an ellipsis (" ...").
  263. X Most options will be inside of square brackets to reflect the fact that
  264. X they are "optional".
  265. X
  266. X Some example <syntax> strings follow:
  267. X
  268. X    "c|keyword"                -- a required option
  269. X    "[c|keyword]"              -- an option with no value
  270. X    "[c|keyword value]"        -- an option that takes a value
  271. X    "[c|keyword [value]]"      -- an option that takes an optional value
  272. X    "[c|keyword value ...]"    -- an option that takes 1 or more values
  273. X    "[c|keyword [value ...]]"  -- an option that takes 0 or more values
  274. X    "value"                    -- a required positional parameter
  275. X    "[value]"                  -- an optional positional-parameter
  276. X    "[c|keyword] value"        -- a required argument that may be matched
  277. X                                  either positionally or by keyword!
  278. X
  279. X
  280. X Further Information
  281. X -------------------
  282. X This is just a brief overview of what the CmdLine package can do. Please
  283. X read the documentation for a more thorough explanation of this products'
  284. X capabilities and limitations!
  285. X
  286. END_OF_FILE
  287. if test 10504 -ne `wc -c <'Overview'`; then
  288.     echo shar: \"'Overview'\" unpacked with wrong size!
  289. fi
  290. # end of 'Overview'
  291. fi
  292. if test -f 'src/lib/cmdarg.c' -a "${1}" != "-c" ; then 
  293.   echo shar: Will not clobber existing file \"'src/lib/cmdarg.c'\"
  294. else
  295. echo shar: Extracting \"'src/lib/cmdarg.c'\" \(9945 characters\)
  296. sed "s/^X//" >'src/lib/cmdarg.c' <<'END_OF_FILE'
  297. X//------------------------------------------------------------------------
  298. X// ^FILE: cmdarg.c - implement a CmdArg
  299. X//
  300. X// ^DESCRIPTION:
  301. X//    This file implements the CmdArg class which is the base
  302. X//    class for all command-arguments.
  303. X//
  304. X// ^HISTORY:
  305. X//    03/25/92    Brad Appleton    <brad@ssd.csd.harris.com>    Created
  306. X//-^^---------------------------------------------------------------------
  307. X
  308. X#include <stdlib.h>
  309. X#include <iostream.h>
  310. X#include <string.h>
  311. X#include <ctype.h>
  312. X
  313. X#include "cmdline.h"
  314. X
  315. X//---------------------------------------------------------------------- CmdArg
  316. X
  317. Xint  CmdArg::is_dummy(void) { return  0; }
  318. X
  319. X   // Copy-Constructor
  320. XCmdArg::CmdArg(const CmdArg & cp)
  321. X   : arg_char_name(cp.arg_char_name),
  322. X     arg_keyword_name(cp.arg_keyword_name),
  323. X     arg_value_name(cp.arg_value_name),
  324. X     alloc_value_name(cp.alloc_value_name),
  325. X     arg_syntax(cp.arg_syntax),
  326. X     arg_description(cp.arg_description),
  327. X     arg_flags(cp.arg_flags)
  328. X{
  329. X   if (alloc_value_name) {
  330. X      char * val_name = new char[::strlen(cp.arg_value_name) + 1] ;
  331. X      ::strcpy((char *)val_name, cp.arg_value_name);
  332. X      arg_value_name = val_name;
  333. X   }
  334. X}
  335. X
  336. X   // Constructors
  337. X
  338. XCmdArg::CmdArg(char         optchar,
  339. X               const char * keyword,
  340. X               const char * value,
  341. X               const char * description,
  342. X               unsigned     syntax_flags)
  343. X   : arg_char_name(optchar),
  344. X     arg_keyword_name(keyword),
  345. X     arg_value_name(value), alloc_value_name(0),
  346. X     arg_syntax(syntax_flags),
  347. X     arg_description(description),
  348. X     arg_flags(0)
  349. X{
  350. X   parse_description();
  351. X   parse_value();
  352. X   adjust_syntax();
  353. X}
  354. X
  355. X
  356. XCmdArg::CmdArg(char         optchar,
  357. X               const char * keyword,
  358. X               const char * description,
  359. X               unsigned     syntax_flags)
  360. X   : arg_char_name(optchar),
  361. X     arg_keyword_name(keyword),
  362. X     arg_value_name(NULL), alloc_value_name(0),
  363. X     arg_syntax(syntax_flags),
  364. X     arg_description(description),
  365. X     arg_flags(0)
  366. X{
  367. X   parse_description();
  368. X   adjust_syntax();
  369. X}
  370. X
  371. X
  372. XCmdArg::CmdArg(const char * value,
  373. X               const char * description,
  374. X               unsigned     syntax_flags)
  375. X   : arg_char_name(0),
  376. X     arg_keyword_name(NULL),
  377. X     arg_value_name(value), alloc_value_name(0),
  378. X     arg_syntax(syntax_flags),
  379. X     arg_description(description),
  380. X     arg_flags(0)
  381. X{
  382. X   parse_description();
  383. X   parse_value();
  384. X   adjust_syntax();
  385. X}
  386. X
  387. X
  388. X   // Destructor
  389. XCmdArg::~CmdArg(void)
  390. X{
  391. X   if (alloc_value_name)    delete [] (char *)arg_value_name;
  392. X}
  393. X
  394. X
  395. X//-------------------
  396. X// ^FUNCTION: adjust_syntax - adjust command argument syntax
  397. X//
  398. X// ^SYNOPSIS:
  399. X//    CmdArg::adjust_syntax(void)
  400. X//
  401. X// ^PARAMETERS:
  402. X//    None.
  403. X//
  404. X// ^DESCRIPTION:
  405. X//    This routine tries to "iron out" any inconsistencies (such as
  406. X//    conflicting syntax flags) in the way a command-argument is specified
  407. X//    and makes its best guess at what the user eally intended.
  408. X//
  409. X// ^REQUIREMENTS:
  410. X//    parse_value() and parse_description() must already have been called.
  411. X//
  412. X// ^SIDE-EFFECTS:
  413. X//    Modifies the argument syntax flags.
  414. X//    Modifies is keyword and value names if they are ""
  415. X//
  416. X// ^RETURN-VALUE:
  417. X//    None.
  418. X//
  419. X// ^ALGORITHM:
  420. X//    Follow along in the code ...
  421. X//-^^----------------
  422. Xvoid
  423. XCmdArg::adjust_syntax(void)
  424. X{
  425. X   static const char default_value_name[] = "value" ;
  426. X
  427. X      // If the value is specified as both OPTIONAL and REQUIRED
  428. X      // then assume it is required.
  429. X      //
  430. X   if ((arg_syntax & isVALREQ) && (arg_syntax & isVALOPT)) {
  431. X      arg_syntax &= ~isVALOPT ;
  432. X   }
  433. X
  434. X      // If they said the argument was both STICKY and SEPARATE then
  435. X      // I dont know what to think just just ignore both of them.
  436. X      //
  437. X   if ((arg_syntax & isVALSTICKY) && (arg_syntax & isVALSEP)) {
  438. X      arg_syntax &= ~(isVALSTICKY | isVALSEP);
  439. X   }
  440. X
  441. X      // If a non-NULL, non-empty value-name was given but we werent
  442. X      // told that the argument takes a value, then assume that it
  443. X      // does take a value and that the value is required.
  444. X      //
  445. X   if (arg_value_name && *arg_value_name && (! (arg_syntax & isVALTAKEN))) {
  446. X      arg_syntax |= isVALREQ;
  447. X   }
  448. X
  449. X      // If a value is taken and the argument is positional, then
  450. X      // we need to make isREQ and isOPT consistent with isVALREQ
  451. X      // and isVALOPT
  452. X      //
  453. X   if ((arg_syntax & isVALTAKEN) && (arg_syntax & isPOS)) {
  454. X      arg_syntax &= ~(isREQ | isOPT);
  455. X      if (arg_syntax & isVALREQ)  arg_syntax |= isREQ;
  456. X      if (arg_syntax & isVALOPT)  arg_syntax |= isOPT;
  457. X   }
  458. X
  459. X      // If the keyword name is empty then just use NULL
  460. X   if (arg_keyword_name  &&  (! *arg_keyword_name)) {
  461. X      arg_keyword_name = NULL;
  462. X   }
  463. X
  464. X      // If the value name is empty then just use NULL
  465. X   if (arg_value_name  &&  (! *arg_value_name)) {
  466. X      arg_value_name = NULL;
  467. X   }
  468. X
  469. X      // If a value is taken but no value name was given,
  470. X      // then default the value name.
  471. X      //
  472. X   if ((arg_syntax & isVALTAKEN) && (! arg_value_name)) {
  473. X      arg_value_name = default_value_name;
  474. X   }
  475. X
  476. X      // If no keyword name or character name was given, then the
  477. X      // argument had better take a value and it must be positional
  478. X      //
  479. X   if ((! arg_char_name) && (arg_keyword_name == NULL) &&
  480. X                            (! (arg_syntax & isPOS))) {
  481. X      if (arg_syntax & isVALTAKEN) {
  482. X         arg_syntax |= isPOS;
  483. X      } else {
  484. X         cerr << "*** Error: non-positional CmdArg "
  485. X              << "has no character or keyword name!\n"
  486. X              << "\t(error occurred in CmdArg constructor)" << endl ;
  487. X      }
  488. X   }
  489. X}
  490. X
  491. X
  492. X//-------------------
  493. X// ^FUNCTION: parse_description - parse the argument description string
  494. X//
  495. X// ^SYNOPSIS:
  496. X//    CmdLine::parse_description(void)
  497. X//
  498. X// ^PARAMETERS:
  499. X//    None.
  500. X//
  501. X// ^DESCRIPTION:
  502. X//    All we have to do is see if the first non-white character of
  503. X//    the description is string is ';'. If it is, then the argument
  504. X//    is a "hidden" argument and the description starts with the
  505. X//    next non-white character.
  506. X//
  507. X// ^REQUIREMENTS:
  508. X//    None.
  509. X//
  510. X// ^SIDE-EFFECTS:
  511. X//    Modifies arg_description
  512. X//
  513. X// ^RETURN-VALUE:
  514. X//    None.
  515. X//
  516. X// ^ALGORITHM:
  517. X//    Trivial.
  518. X//-^^----------------
  519. Xenum { c_HIDDEN = ';', c_OPEN = '[', c_CLOSE = ']', c_LIST = '.' } ;
  520. X
  521. Xvoid
  522. XCmdArg::parse_description(void)
  523. X{
  524. X   if (arg_description == NULL)  return;
  525. X   while (isspace(*arg_description))  ++arg_description;
  526. X   if (*arg_description == c_HIDDEN) {
  527. X      arg_syntax |= isHIDDEN ;
  528. X      ++arg_description;
  529. X      while (isspace(*arg_description))  ++arg_description;
  530. X   }
  531. X}
  532. X
  533. X
  534. X//-------------------
  535. X// ^FUNCTION: parse_value - parse the argument value name
  536. X//
  537. X// ^SYNOPSIS:
  538. X//    CmdLine::parse_value(void)
  539. X//
  540. X// ^PARAMETERS:
  541. X//    None.
  542. X//
  543. X// ^DESCRIPTION:
  544. X//    This routine parses the argument value string. If the value name is
  545. X//    is enclosed between '[' and ']', then the value is optional (not
  546. X//    required) and we need to modify the arg_syntax flags. Also, if the
  547. X//    value name is suffixed by "..." then it means the value is a LIST
  548. X//    of values and we need to modify the arg_syntax flags.
  549. X//
  550. X// ^REQUIREMENTS:
  551. X//    This routine must be called BEFORE, adjust_syntax() is called/
  552. X//
  553. X// ^SIDE-EFFECTS:
  554. X//    Modifies the arg_value_name and the arg_syntax flags.
  555. X//
  556. X// ^RETURN-VALUE:
  557. X//    None.
  558. X//
  559. X// ^ALGORITHM:
  560. X//    Its kind of hairy so follow along.
  561. X//-^^----------------
  562. Xvoid
  563. XCmdArg::parse_value(void)
  564. X{
  565. X   const char * save_value = arg_value_name;
  566. X   int  brace = 0;
  567. X   int  errors = 0;
  568. X
  569. X   // Skip whitespace as necessary and look for a '['
  570. X   while (isspace(*arg_value_name))  ++arg_value_name;
  571. X   if (*arg_value_name == c_OPEN) {
  572. X      ++brace;
  573. X      ++arg_value_name;
  574. X      while (isspace(*arg_value_name))  ++arg_value_name;
  575. X      arg_syntax &= ~isVALREQ;
  576. X      arg_syntax |= isVALOPT;
  577. X   }
  578. X
  579. X   // Now that arg_value_name points to the beginning of the value,
  580. X   // lets find the end of it.
  581. X   //
  582. X   const char * ptr = arg_value_name;
  583. X   while ((*ptr) && (! isspace(*ptr)) &&
  584. X          (*ptr != c_LIST) && (*ptr != c_CLOSE)) {
  585. X      ++ptr;
  586. X   }
  587. X
  588. X   // See if we dont need to allocate a new string
  589. X   if ((! *ptr) && (save_value == arg_value_name))  return;
  590. X
  591. X   // Copy the value name
  592. X   alloc_value_name = 1;
  593. X   int  len = (int) (ptr - arg_value_name);
  594. X   char * copied_value = new char[len + 1];
  595. X   (void) ::strncpy(copied_value, arg_value_name, len);
  596. X   copied_value[len] = '\0';
  597. X   arg_value_name = copied_value;
  598. X
  599. X   // Did we end on a ']' ?
  600. X   if (*ptr == c_CLOSE) {
  601. X      if (! brace) {
  602. X         cerr << "Error: unmatched '" << char(c_CLOSE) << "'." << endl ;
  603. X         ++errors;
  604. X         arg_syntax &= ~isVALREQ;
  605. X         arg_syntax |= isVALOPT;
  606. X      }
  607. X      brace = 0;
  608. X      ++ptr;
  609. X   }
  610. X
  611. X   // Skip whitespace and see if we are finished.
  612. X   while (isspace(*ptr))  ++ptr;
  613. X   if (! *ptr) {
  614. X      // Was there an unmatched ']'
  615. X      if (brace) {
  616. X         cerr << "Error: unmatched '" << char(c_OPEN) << "'." << endl ;
  617. X         ++errors;
  618. X      }
  619. X      if (errors) {
  620. X         cerr << "*** Syntax error in value \"" << save_value << "\".\n"
  621. X              << "\t(error occurred in CmdArg constructor)" << endl ;
  622. X      }
  623. X      return;
  624. X   }
  625. X
  626. X   // Not done - we had better see a "..."
  627. X   if (::strncmp(ptr, "...", 3) != 0) {
  628. X      cerr << "Error: unexpected token \"" << ptr << "\"." << endl ;
  629. X      ++errors;
  630. X   } else {
  631. X      arg_syntax |= isLIST;
  632. X      ptr += 3;
  633. X      while (isspace(*ptr))  ++ptr;
  634. X      if (brace && (*ptr != c_CLOSE)) {
  635. X         cerr << "Error: unmatched '" << char(c_OPEN) << "'." << endl ;
  636. X         ++errors;
  637. X      } else {
  638. X        // If theres anything left (except ']') it's an error
  639. X        if (brace && (*ptr == c_CLOSE))  ++ptr;
  640. X        while (isspace(*ptr))  ++ptr;
  641. X        if (*ptr) {
  642. X           cerr << "Error: unexpected token \"" << ptr << "\"." << endl ;
  643. X           ++errors;
  644. X        }
  645. X      }
  646. X   }
  647. X
  648. X   // Were there any errors?
  649. X   if (errors) {
  650. X      cerr << "*** Syntax error in value \"" << save_value << "\".\n"
  651. X           << "\t(error occurred in CmdArg constructor)" << endl ;
  652. X   }
  653. X}
  654. END_OF_FILE
  655. if test 9945 -ne `wc -c <'src/lib/cmdarg.c'`; then
  656.     echo shar: \"'src/lib/cmdarg.c'\" unpacked with wrong size!
  657. fi
  658. # end of 'src/lib/cmdarg.c'
  659. fi
  660. if test -f 'src/lib/cmdline.c' -a "${1}" != "-c" ; then 
  661.   echo shar: Will not clobber existing file \"'src/lib/cmdline.c'\"
  662. else
  663. echo shar: Extracting \"'src/lib/cmdline.c'\" \(7900 characters\)
  664. sed "s/^X//" >'src/lib/cmdline.c' <<'END_OF_FILE'
  665. X//------------------------------------------------------------------------
  666. X// ^FILE: cmdline.c - implement CmdLine member functions.
  667. X//
  668. X// ^DESCRIPTION:
  669. X//    Many of the more basic member functions of a CmdLine are implemented
  670. X//    in this file. They are as follows:
  671. X//
  672. X//       Contructors
  673. X//       Destructors
  674. X//       CmdLine::name()
  675. X//       CmdLine::error()
  676. X//       CmdLine::append
  677. X//
  678. X// ^HISTORY:
  679. X//    03/21/92    Brad Appleton    <brad@ssd.csd.harris.com>    Created
  680. X//-^^---------------------------------------------------------------------
  681. X
  682. X#include <stdlib.h>
  683. X#include <iostream.h>
  684. X#include <stdarg.h>
  685. X#include <string.h>
  686. X#include <ctype.h>
  687. X
  688. X#include "cmdline.h"
  689. X#include "cmdargs.h"
  690. X#include "arglist.h"
  691. X#include "states.h"
  692. X
  693. X#define  va_CmdArgP(ap)  va_arg(ap, CmdArg *)
  694. X
  695. X
  696. X//------------------------------------------------------------------- init_args
  697. X
  698. X//-------------------
  699. X// ^FUNCTION: init_args - initialize the arg_list member of a CmdLine
  700. X//
  701. X// ^SYNOPSIS:
  702. X//    init_args(list)
  703. X//
  704. X// ^PARAMETERS:
  705. X//    CmdArgListList & * list;
  706. X//    -- a reference to the list that is to be initialized.
  707. X//
  708. X// ^DESCRIPTION:
  709. X//    Allocate space for the list of command-arguments and insert
  710. X//    The default arguments onto the list.
  711. X//
  712. X// ^REQUIREMENTS:
  713. X//    list should be NULL upon entry
  714. X//
  715. X// ^SIDE-EFFECTS:
  716. X//    creates the arg-list and makes "list" point to it.
  717. X//
  718. X// ^RETURN-VALUE:
  719. X//    None.
  720. X//
  721. X// ^ALGORITHM:
  722. X//    - Create a new arg-list (sure it is NOT self-cleaning, the user is
  723. X//                             responsible for deleting inserted items)
  724. X//    - Insert the default arguments onto the list
  725. X//    - Make list point to the newly created list
  726. X//-^^----------------
  727. Xstatic void
  728. Xinit_args(CmdArgListList * & list)
  729. X{
  730. X   static  CmdArgUsage  default_help1('?', "?",    "; print usage and exit.");
  731. X   static  CmdArgUsage  default_help2('H', "Help", "; print usage and exit.");
  732. X
  733. X   list = new CmdArgListList ;
  734. X   list->self_cleaning(1);
  735. X
  736. X   CmdArgList * arg_list = new CmdArgList;
  737. X   arg_list->self_cleaning(0);
  738. X
  739. X   CmdArgList * default_list = new CmdArgList;
  740. X   default_list->self_cleaning(0);
  741. X   default_list->add(&default_help1);
  742. X   default_list->add(&default_help2);
  743. X
  744. X   list->add(arg_list);
  745. X   list->add(default_list);
  746. X}
  747. X
  748. X//---------------------------------------------------------------- filebasename
  749. X
  750. X//-------
  751. X// ^FUNCTION: filebasename
  752. X//
  753. X// ^SYNOPSIS:
  754. X//    static const char * filebasename(filename);
  755. X//
  756. X// ^PARAMETERS:
  757. X//    const char * filename;
  758. X//    -- the filename to get the "base" of.
  759. X//
  760. X// ^DESCRIPTION:
  761. X//    Extract and return the basename of "filename".
  762. X//
  763. X// ^REQUIREMENTS:
  764. X//    "filename" should be non-NULL and non-empty.
  765. X//
  766. X// ^SIDE-EFFECTS:
  767. X//    On VAX/VMS, MS-DOS, and OS/2 systems space is allocated (using malloc)
  768. X//    for the returned value.
  769. X//
  770. X// ^RETURN-VALUE:
  771. X//    The basename portion of the filename.
  772. X//
  773. X// ^ALGORITHM:
  774. X//    For Unix systems:
  775. X//       return everything following the rightmost '/'
  776. X//
  777. X//    For VAX/VMS systems:
  778. X//       make a copy of filename.
  779. X//       strip off any device name, any directory name.
  780. X//       strip off any "." extension.
  781. X//       strip off any version number.
  782. X//
  783. X//    For MS-DOS systems:
  784. X//       make a copy of filename.
  785. X//       strip off any drive and/or directory path.
  786. X//       strip off any "." extension.
  787. X//-^^----
  788. Xstatic const char *
  789. Xfilebasename(const char * filename)
  790. X{
  791. X
  792. X#if (defined(vms) || defined(msdos) || defined(os2))
  793. X   const char * start, * p1, * p2 ;
  794. X   const char * str, * ext;
  795. X
  796. X# ifdef vms
  797. X   const char * ver;
  798. X   // remove leading directory and/or device name
  799. X   p1 = ::strrchr(filename, ':');
  800. X   p2 = ::strrchr(filename, ']');
  801. X# else
  802. X   // remove leading directory and/or drive name
  803. X   p1 = ::strrchr(filename, '/');
  804. X   p2 = ::strrchr(filename, '\\');
  805. X# endif
  806. X   if ((p1 == NULL) && (p2 == NULL)) {
  807. X      start = filename ;
  808. X   } else if (p1 && (p2 == NULL)) {
  809. X      start = p1 + 1;
  810. X   } else if (p2 && (p1 == NULL)) {
  811. X      start = p2 + 1;
  812. X   } else {
  813. X      start = ((p1 > p2) ? p1 : p2) + 1;
  814. X   }
  815. X
  816. X   str = new char[strlen(start) + 1];
  817. X   (void) ::strcpy(str, start);
  818. X
  819. X   // remove the extension
  820. X   ext = ::strrchr(str, '.');
  821. X   if (ext)  *ext = '0' ;
  822. X
  823. X# ifdef vms
  824. X   // remove the version
  825. X   ver = ::strrchr(str, ';');
  826. X   if (ver)  *ver = '0' ;
  827. X# endif
  828. X
  829. X   return  str ;
  830. X
  831. X#else
  832. X
  833. X   char * p = ::strrchr(filename, '/') ;
  834. X   return  (p == NULL) ? filename : (p + 1) ;
  835. X
  836. X#endif /* if (vms || msdos || os2) */
  837. X
  838. X}
  839. X
  840. X//--------------------------------------------------------------- class CmdLine
  841. X
  842. X  // Contructor with a command-name
  843. XCmdLine::CmdLine(const char * cmdname)
  844. X   : cmd_parse_state(cmd_START_STATE),
  845. X     cmd_state(cmd_START_STATE),
  846. X     cmd_flags(DEFAULT_CMDFLAGS),
  847. X     cmd_status(CmdLine::NO_ERROR),
  848. X     cmd_name(NULL),
  849. X     cmd_matched_arg(NULL),
  850. X     cmd_args(NULL),
  851. X     cmd_err(NULL)
  852. X{
  853. X   name(cmdname);
  854. X   ::init_args(cmd_args);
  855. X}
  856. X
  857. X   // Constructor with a name and CmdArgs
  858. XCmdLine::CmdLine(const char * cmdname, CmdArg * ...)
  859. X   : cmd_parse_state(cmd_START_STATE),
  860. X     cmd_state(cmd_START_STATE),
  861. X     cmd_flags(DEFAULT_CMDFLAGS),
  862. X     cmd_status(CmdLine::NO_ERROR),
  863. X     cmd_name(NULL),
  864. X     cmd_matched_arg(NULL),
  865. X     cmd_args(NULL),
  866. X     cmd_err(NULL)
  867. X{
  868. X   name(cmdname);
  869. X   ::init_args(cmd_args);
  870. X
  871. X   CmdArgListListIter  iter(cmd_args);
  872. X   CmdArgList * arg_list = iter();
  873. X
  874. X   va_list  ap;
  875. X   va_start(ap, cmdname);
  876. X   for (CmdArg * cmdarg = va_CmdArgP(ap) ; cmdarg ; cmdarg = va_CmdArgP(ap)) {
  877. X      arg_list->add(cmdarg);
  878. X   }
  879. X   va_end(ap);
  880. X}
  881. X
  882. X
  883. X   // Constructor with CmdArgs
  884. XCmdLine::CmdLine(CmdArg * cmdarg, CmdArg * ...)
  885. X   : cmd_parse_state(cmd_START_STATE),
  886. X     cmd_state(cmd_START_STATE),
  887. X     cmd_flags(DEFAULT_CMDFLAGS),
  888. X     cmd_status(CmdLine::NO_ERROR),
  889. X     cmd_name(NULL),
  890. X     cmd_matched_arg(NULL),
  891. X     cmd_args(NULL),
  892. X     cmd_err(NULL)
  893. X{
  894. X   if (cmdarg == NULL)  return;
  895. X   ::init_args(cmd_args);
  896. X
  897. X   CmdArgListListIter  iter(cmd_args);
  898. X   CmdArgList * arg_list = iter();
  899. X
  900. X   arg_list->add(cmdarg);
  901. X
  902. X   va_list  ap;
  903. X   va_start(ap, cmdarg);
  904. X   for (cmdarg = va_CmdArgP(ap) ; cmdarg ; cmdarg = va_CmdArgP(ap)) {
  905. X      arg_list->add(cmdarg);
  906. X   }
  907. X   va_end(ap);
  908. X}
  909. X
  910. X
  911. X   // Destructor
  912. XCmdLine::~CmdLine(void)
  913. X{
  914. X   delete  cmd_args;
  915. X
  916. X#if (defined(vms) || defined(msdos) || defined(os2))
  917. X   delete [] cmd_name;
  918. X#endif
  919. X}
  920. X
  921. X
  922. X   // Set the name of the command
  923. Xvoid
  924. XCmdLine::name(const char * progname)
  925. X{
  926. X#if (defined(vms) || defined(msdos) || defined(os2))
  927. X   delete [] cmd_name;
  928. X#endif
  929. X   cmd_name = ::filebasename(progname);
  930. X}
  931. X
  932. X
  933. X   // Print an error message prefix and return a reference to the
  934. X   // error output stream for this command
  935. Xostream &
  936. XCmdLine::error(int  print) const
  937. X{
  938. X   ostream * os = (cmd_err) ? (ostream *)cmd_err : &cerr ;
  939. X   if (print && cmd_name && *cmd_name)  *os << cmd_name << ": " ;
  940. X   return  *os;
  941. X}
  942. X
  943. X
  944. X  // Add an argument to the current list of CmdArgs
  945. XCmdLine &
  946. XCmdLine::append(CmdArg * cmdarg)
  947. X{
  948. X   CmdArgListListIter  iter(cmd_args);
  949. X   CmdArgList * arg_list = iter();
  950. X   arg_list->add(cmdarg);
  951. X
  952. X   return  *this ;
  953. X}
  954. X
  955. X
  956. X//---------------------------------------------------------- CmdLineCmdArgIter
  957. X
  958. X   // Constructors and Destructors
  959. X
  960. XCmdLineCmdArgIter::CmdLineCmdArgIter(CmdLine & cmd)
  961. X   : iter(NULL)
  962. X{
  963. X   if (cmd.cmd_args) {
  964. X      CmdArgListListIter  listlist_iter(cmd.cmd_args);
  965. X      CmdArgList  * list = listlist_iter();
  966. X      if (list)  iter = new CmdArgListIter(list);
  967. X   }
  968. X}
  969. X
  970. XCmdLineCmdArgIter::CmdLineCmdArgIter(CmdLine * cmd)
  971. X   : iter(NULL)
  972. X{
  973. X   if (cmd->cmd_args) {
  974. X      CmdArgListListIter  listlist_iter(cmd->cmd_args);
  975. X      CmdArgList  * list = listlist_iter();
  976. X      if (list)  iter = new CmdArgListIter(list);
  977. X   }
  978. X}
  979. X
  980. XCmdLineCmdArgIter::~CmdLineCmdArgIter(void)
  981. X{
  982. X   delete  iter;
  983. X}
  984. X
  985. X   // Return the current argument and advance to the next one.
  986. X   // Returns NULL if we are already at the end of the list.
  987. X   //
  988. XCmdArg *
  989. XCmdLineCmdArgIter::operator()(void)
  990. X{
  991. X   return  (iter) ? (*iter)() : NULL ;
  992. X}
  993. X
  994. END_OF_FILE
  995. if test 7900 -ne `wc -c <'src/lib/cmdline.c'`; then
  996.     echo shar: \"'src/lib/cmdline.c'\" unpacked with wrong size!
  997. fi
  998. # end of 'src/lib/cmdline.c'
  999. fi
  1000. if test -f 'src/lib/cmdtest.c' -a "${1}" != "-c" ; then 
  1001.   echo shar: Will not clobber existing file \"'src/lib/cmdtest.c'\"
  1002. else
  1003. echo shar: Extracting \"'src/lib/cmdtest.c'\" \(8009 characters\)
  1004. sed "s/^X//" >'src/lib/cmdtest.c' <<'END_OF_FILE'
  1005. X//------------------------------------------------------------------------
  1006. X// ^FILE: cmdtest.c - test program for the CmdLine library
  1007. X//
  1008. X// ^DESCRIPTION:
  1009. X//    This program tests as many features of command-line as possible.
  1010. X//
  1011. X// ^HISTORY:
  1012. X//    03/18/92    Brad Appleton    <brad@ssd.csd.harris.com>    Created
  1013. X//-^^---------------------------------------------------------------------
  1014. X
  1015. X#include <stdlib.h>
  1016. X#include <iostream.h>
  1017. X#include <ctype.h>
  1018. X#include <cmdargs.h>
  1019. X
  1020. X//---------------------------------------------------------------- CmdArgModCmd
  1021. X
  1022. X   // CmdArgModCmd is a special argument that we use for testing.
  1023. X   // The argument actually modifies the flags of the associated
  1024. X   // command before it has finished parsing the arguments, hence
  1025. X   // the new flags take effect for all remaining arguments.
  1026. X   //
  1027. X   // This argument takes a value (which is optional). If no value
  1028. X   // is given, then the flags are unset, otherwise the value is
  1029. X   // a list of characters, each of which corresponds to a CmdFlag
  1030. X   // to turn on.
  1031. X   //
  1032. Xclass  CmdArgModCmd : public CmdArg {
  1033. Xpublic:
  1034. X   CmdArgModCmd(char         optchar,
  1035. X                const char * keyword,
  1036. X                const char * value,
  1037. X                const char * description,
  1038. X                unsigned     syntax_flags =CmdArg::isOPTVALOPT);
  1039. X
  1040. X   virtual
  1041. X   ~CmdArgModCmd(void);
  1042. X
  1043. X   virtual  int
  1044. X   operator()(const char * & arg, CmdLine & cmd);
  1045. X} ;
  1046. X
  1047. XCmdArgModCmd::CmdArgModCmd(char         optchar,
  1048. X                           const char * keyword,
  1049. X                           const char * value,
  1050. X                           const char * description,
  1051. X                           unsigned     syntax_flags)
  1052. X   : CmdArg(optchar, keyword, value, description, syntax_flags) {}
  1053. X
  1054. XCmdArgModCmd::~CmdArgModCmd(void) {}
  1055. X
  1056. Xint CmdArgModCmd::operator()(const char * & arg, CmdLine & cmd)
  1057. X{
  1058. X   unsigned  new_flags = 0;
  1059. X   for (const char * p = arg ; *p ; p++) {
  1060. X      char ch = *p;
  1061. X      if (isupper(ch))  ch = tolower(ch);
  1062. X      switch (ch) {
  1063. X         case 'c' : new_flags |= CmdLine::ANY_CASE_OPTS;  break;
  1064. X
  1065. X         case 'p' : new_flags |= CmdLine::PROMPT_USER;    break;
  1066. X
  1067. X         case 'n' : new_flags |= CmdLine::NO_ABORT;       break;
  1068. X
  1069. X         case 'f' : new_flags |= CmdLine::OPTS_FIRST;     break;
  1070. X
  1071. X         case 'o' : new_flags |= CmdLine::OPTS_ONLY;      break;
  1072. X
  1073. X         case 'k' : new_flags |= CmdLine::KWDS_ONLY;      break;
  1074. X
  1075. X         case 't' : new_flags |= CmdLine::TEMP;           break;
  1076. X
  1077. X         case 'q' : new_flags |= CmdLine::QUIET;          break;
  1078. X
  1079. X         case 'g' : new_flags |= CmdLine::NO_GUESSING;    break;
  1080. X
  1081. X         default  : break;
  1082. X      } //switch
  1083. X   } //for
  1084. X   cmd.flags(new_flags);
  1085. X   arg = NULL;
  1086. X   return  0;
  1087. X}
  1088. X
  1089. X
  1090. X//------------------------------------------------------ Command Line Arguments
  1091. X
  1092. Xstatic CmdArgModCmd    fflag('f', "flags", "[cpnfoktqg]",
  1093. X   "Use this argument to change the behavior of \
  1094. Xparsing for all remaining arguments.  If no \
  1095. Xvalue is given   then the command-flags are \
  1096. Xcleared.  Otherwise each letter specifies a flag \
  1097. Xto set:\n\
  1098. X   'c' = any-Case-opts\n\
  1099. X   'p' = Prompt-user\n\
  1100. X   'n' = No-abort\n\
  1101. X   'f' = options-First\n\
  1102. X   'o' = Opts-only\n\
  1103. X   'k' = Keywords-only\n\
  1104. X   't' = Temporary-args\n\
  1105. X   'q' = Quiet!\n\
  1106. X   'g' = no-Guessing\n\
  1107. XThis-is-a-very-long-line-containing-no-whitespace-\
  1108. Xcharacters-and-I-just-want-to-see-if-it-gets-\
  1109. Xformatted-appropriately!"
  1110. X   );
  1111. X
  1112. Xstatic CmdArgStr       str('s', "str", "[string]", "string to parse");
  1113. Xstatic CmdArgInt       debug ('D', "Debug", "[level]", "turn on debugging",
  1114. X                              CmdArg::isVALSTICKY);
  1115. Xstatic CmdArgBool      infile('p', "parse", "parse from cin");
  1116. X
  1117. Xstatic CmdArgSet       xflag('x', "x", ";turn on X-rated mode");
  1118. Xstatic CmdArgClearRef  nxflag(xflag, 'n', "nx", ";turn off X-rated mode");
  1119. Xstatic CmdArgInt       count('c', "count", "number", "number of copies");
  1120. Xstatic CmdArgChar      delim('d', "delimiter", "char", "delimiter character");
  1121. Xstatic CmdArgChar      ext('e', "ext", "[char]", "extension to use",
  1122. X                                                 CmdArg::isVALSTICKY);
  1123. Xstatic CmdArgChar      code('C', "Code", "char", "code to use",
  1124. X                                                 CmdArg::isVALSTICKY);
  1125. Xstatic CmdArgStr       why('y', "why", "[reason]", "specify the reason why",
  1126. X                                                   CmdArg::isVALSEP);
  1127. Xstatic CmdArgStr       who('w', "who", "logname", "the user responsible",
  1128. X                                                  CmdArg::isVALSEP);
  1129. Xstatic CmdArgIntList   ints('i', "int", "number ...", "list of ints");
  1130. Xstatic CmdArgStrList   grps('g', "groups", "newsgroup", "list of newsgroups");
  1131. Xstatic CmdArgDummy     dummy("--", "denote end of options");
  1132. Xstatic CmdArgStr       name('n', "name", "name", "name of document",
  1133. X                                                 CmdArg::isPOS);
  1134. Xstatic CmdArgStrList   files("[files ...]", "files to process");
  1135. X
  1136. X//------------------------------------------------------------------ print_args
  1137. X
  1138. Xstatic void
  1139. Xprint_args(void) {
  1140. X   cout << "xflag=" << (xflag ? "ON" : "OFF") << endl ;
  1141. X   cout << "count=" << count << endl ;
  1142. X
  1143. X   unsigned  sflags = str.flags();
  1144. X   if ((sflags & CmdArg::GIVEN) && (! (sflags & CmdArg::VALGIVEN))) {
  1145. X      cout << "No string given on command-line!" << endl ;
  1146. X   } else {
  1147. X      cout << "str=\"" << str << "\"" << endl ;
  1148. X   }
  1149. X   cout << "delim='" << delim << "'" << endl ;
  1150. X   cout << "ext='" << ext << "'" << endl ;
  1151. X   cout << "code='" << code << "'" << endl ;
  1152. X   cout << "why=\"" << why << "\"" << endl ;
  1153. X   cout << "who=\"" << who << "\"" << endl ;
  1154. X
  1155. X   unsigned  nints = ints.count();
  1156. X   for (int i = 0; i < nints ; i++) {
  1157. X      cout << "int[" << i << "]=" << ints[i] << endl ;
  1158. X   }
  1159. X
  1160. X   unsigned  ngrps = grps.count();
  1161. X   for (i = 0; i < ngrps ; i++) {
  1162. X      cout << "groups[" << i << "]=\"" << grps[i] << "\"" << endl ;
  1163. X   }
  1164. X
  1165. X   cout << "name=\"" << name << "\"" << endl ;
  1166. X
  1167. X   unsigned  nfiles = files.count();
  1168. X   for (i = 0; i < nfiles ; i++) {
  1169. X      cout << "files[" << i << "]=\"" << files[i] << "\"" << endl ;
  1170. X   }
  1171. X}
  1172. X
  1173. X//------------------------------------------------------------------------ dump
  1174. X
  1175. Xstatic void
  1176. Xdump(CmdLine & cmd)
  1177. X{
  1178. X   if (debug) {
  1179. X      cmd.dump(cout);
  1180. X      if (debug > 1) cmd.dump_args(cout);
  1181. X   }
  1182. X}
  1183. X
  1184. X//------------------------------------------------------------------------ main
  1185. X
  1186. Xint
  1187. Xmain(int argc, char * argv[]) {
  1188. X   CmdLine  cmd(*argv,
  1189. X                & fflag,
  1190. X                & str,
  1191. X                & infile,
  1192. X                & debug,
  1193. X                & xflag,
  1194. X                & nxflag,
  1195. X                & count,
  1196. X                & delim,
  1197. X                & ext,
  1198. X                & code,
  1199. X                & why,
  1200. X                & who,
  1201. X                & ints,
  1202. X                & grps,
  1203. X                & dummy,
  1204. X                & name,
  1205. X                & files,
  1206. X                NULL);
  1207. X   CmdArgvIter  argv_iter(--argc, ++argv);
  1208. X
  1209. X   cout << "Test of " << CmdLine::ident() << endl ;
  1210. X
  1211. X   xflag = 0;
  1212. X   count = 1;
  1213. X   str = NULL;
  1214. X   delim = '\t';
  1215. X   name = NULL;
  1216. X
  1217. X   cout << "Parsing the command-line ..." << endl ;
  1218. X   unsigned status = cmd.parse(argv_iter);
  1219. X   if (status)  cmd.error() << "parsing errors occurred!" << endl ;
  1220. X
  1221. X   print_args();
  1222. X
  1223. X   unsigned dbg_flags = debug.flags();
  1224. X   if ((dbg_flags & CmdArg::GIVEN) && (! (dbg_flags & CmdArg::VALGIVEN))) {
  1225. X      debug = 1;
  1226. X   }
  1227. X
  1228. X   dump(cmd);
  1229. X
  1230. X   int  parse_cin = infile;
  1231. X
  1232. X   // Parse arguments from a string
  1233. X   if (str) {
  1234. X      CmdStrTokIter  tok_iter(str);
  1235. X
  1236. X      xflag = 0;
  1237. X      count = 1;
  1238. X      str = NULL;
  1239. X      delim = '\t';
  1240. X      name = NULL;
  1241. X
  1242. X      cout << "\n\nParsing the string ..." << endl ;
  1243. X      status = cmd.parse(tok_iter);
  1244. X      print_args();
  1245. X      dump(cmd);
  1246. X   }
  1247. X
  1248. X
  1249. X   // Parse arguments from a file
  1250. X   if (parse_cin) {
  1251. X      xflag = 0;
  1252. X      count = 1;
  1253. X      str = NULL;
  1254. X      delim = '\t';
  1255. X      name = NULL;
  1256. X
  1257. X      CmdIstreamIter  file_iter(cin);
  1258. X      cout << "\n\nParsing from cin ..." << endl ;
  1259. X      status = cmd.parse(file_iter);
  1260. X      print_args();
  1261. X      dump(cmd);
  1262. X   }
  1263. X
  1264. X   return  0;
  1265. X}
  1266. X
  1267. END_OF_FILE
  1268. if test 8009 -ne `wc -c <'src/lib/cmdtest.c'`; then
  1269.     echo shar: \"'src/lib/cmdtest.c'\" unpacked with wrong size!
  1270. fi
  1271. # end of 'src/lib/cmdtest.c'
  1272. fi
  1273. if test -f 'src/lib/dump.c' -a "${1}" != "-c" ; then 
  1274.   echo shar: Will not clobber existing file \"'src/lib/dump.c'\"
  1275. else
  1276. echo shar: Extracting \"'src/lib/dump.c'\" \(7287 characters\)
  1277. sed "s/^X//" >'src/lib/dump.c' <<'END_OF_FILE'
  1278. X//------------------------------------------------------------------------
  1279. X// ^FILE: dump.c - debugging/dumping functions of the CmdLine library
  1280. X//
  1281. X// ^DESCRIPTION:
  1282. X//    If DEBUG_CMDLINE is #defined when this file is compiled, then
  1283. X//    the functions that print out debugging information for a CmdLine
  1284. X//    and a CmdArg are implemented.
  1285. X//
  1286. X// ^HISTORY:
  1287. X//    04/01/92    Brad Appleton    <brad@ssd.csd.harris.com>    Created
  1288. X//-^^---------------------------------------------------------------------
  1289. X
  1290. X#include  "cmdline.h"
  1291. X
  1292. X#ifdef DEBUG_CMDLINE
  1293. X# include  <iostream.h>
  1294. X# include  <string.h>
  1295. X
  1296. X# include  "arglist.h"
  1297. X# include  "states.h"
  1298. X#endif
  1299. X
  1300. X
  1301. X#ifdef DEBUG_CMDLINE
  1302. X
  1303. X   // Indent a line corresponding to a given indent level.
  1304. X   // The number of spaces to indent is 3x the indent level
  1305. X   //
  1306. Xstatic ostream &
  1307. Xindent(ostream & os, unsigned level)
  1308. X{
  1309. X   os.width(level * 3);
  1310. X   return  (os << "");
  1311. X}
  1312. X
  1313. X
  1314. X   // Dump the arg_syntax field of a CmdArg in a mnemonic format
  1315. X   //
  1316. Xstatic ostream &
  1317. Xdump_arg_syntax(ostream & os, unsigned  syntax)
  1318. X{
  1319. X   if (syntax & CmdArg::isREQ) {
  1320. X      os << "isREQ" ;
  1321. X   } else {
  1322. X      os << "isOPT" ;
  1323. X   }
  1324. X
  1325. X   if (syntax & CmdArg::isVALREQ) {
  1326. X      os << "+isVALREQ" ;
  1327. X   }
  1328. X   if (syntax & CmdArg::isVALOPT) {
  1329. X      os << "+isVALOPT" ;
  1330. X   }
  1331. X   if (syntax & CmdArg::isVALSEP) {
  1332. X      os << "+isVALSEP" ;
  1333. X   }
  1334. X   if (syntax & CmdArg::isVALSTICKY) {
  1335. X      os << "+isVALSTICKY" ;
  1336. X   }
  1337. X   if (syntax & CmdArg::isLIST) {
  1338. X      os << "+isLIST" ;
  1339. X   }
  1340. X   if (syntax & CmdArg::isPOS) {
  1341. X      os << "+isPOS" ;
  1342. X   }
  1343. X   if (syntax & CmdArg::isHIDDEN) {
  1344. X      os << "+isHID" ;
  1345. X   }
  1346. X
  1347. X   return  os;
  1348. X}
  1349. X
  1350. X
  1351. X   // Dump the arg_flags field of a CmdArg in a mnemonic format
  1352. Xstatic ostream &
  1353. Xdump_arg_flags(ostream & os, unsigned  flags)
  1354. X{
  1355. X   if (flags & CmdArg::GIVEN) {
  1356. X      os << "GIVEN" ;
  1357. X   } else {
  1358. X      os << "NOTGIVEN";
  1359. X   }
  1360. X   if (flags & CmdArg::VALGIVEN) {
  1361. X      os << "+VALGIVEN";
  1362. X   }
  1363. X   if (flags & CmdArg::OPTION) {
  1364. X      os << "+OPTION";
  1365. X   }
  1366. X   if (flags & CmdArg::KEYWORD) {
  1367. X      os << "+KEYWORD";
  1368. X   }
  1369. X   if (flags & CmdArg::POSITIONAL) {
  1370. X      os << "+POSITIONAL";
  1371. X   }
  1372. X   if (flags & CmdArg::VALSEP) {
  1373. X      os << "+VALSEP";
  1374. X   } else if (flags & CmdArg::VALGIVEN) {
  1375. X      os << "+VALSAME";
  1376. X   }
  1377. X
  1378. X   return  os;
  1379. X}
  1380. X
  1381. X
  1382. X   // Dump the cmd_flags field of a CmdLine in a mnemonic format
  1383. Xstatic ostream &
  1384. Xdump_cmd_flags(ostream & os, unsigned flags)
  1385. X{
  1386. X   if (flags & CmdLine::NO_ABORT) {
  1387. X      os << "NO_ABORT" ;
  1388. X   } else {
  1389. X      os << "ABORT" ;
  1390. X   }
  1391. X   if (flags & CmdLine::ANY_CASE_OPTS) {
  1392. X      os << "+ANY_CASE_OPTS";
  1393. X   }
  1394. X   if (flags & CmdLine::PROMPT_USER) {
  1395. X      os << "+PROMPT_USER";
  1396. X   }
  1397. X   if (flags & CmdLine::OPTS_FIRST) {
  1398. X      os << "+OPTS_FIRST";
  1399. X   }
  1400. X   if (flags & CmdLine::OPTS_ONLY) {
  1401. X      os << "+OPTS_ONLY";
  1402. X   }
  1403. X   if (flags & CmdLine::KWDS_ONLY) {
  1404. X      os << "+KWDS_ONLY";
  1405. X   }
  1406. X   if (flags & CmdLine::TEMP) {
  1407. X      os << "+TEMP";
  1408. X   }
  1409. X   if (flags & CmdLine::QUIET) {
  1410. X      os << "+QUIET";
  1411. X   }
  1412. X   if (flags & CmdLine::NO_GUESSING) {
  1413. X      os << "+NO_GUESSING";
  1414. X   }
  1415. X
  1416. X   return  os;
  1417. X}
  1418. X
  1419. X
  1420. X   // Dump the status of a CmdLine in a mnemonic format
  1421. Xstatic ostream &
  1422. Xdump_cmd_status(ostream & os, unsigned  status)
  1423. X{
  1424. X   if (! status) {
  1425. X      os << "NO_ERROR";
  1426. X      return  os;
  1427. X   } else {
  1428. X      os << "ERROR";
  1429. X   }
  1430. X   if (status & CmdLine::ARG_MISSING) {
  1431. X      os << "+ARG_MISSING";
  1432. X   }
  1433. X   if (status & CmdLine::VAL_MISSING) {
  1434. X      os << "+VAL_MISSING";
  1435. X   }
  1436. X   if (status & CmdLine::VAL_NOTSTICKY) {
  1437. X      os << "+VAL_NOTSTICKY";
  1438. X   }
  1439. X   if (status & CmdLine::VAL_NOTSEP) {
  1440. X      os << "+VAL_NOTSEP";
  1441. X   }
  1442. X   if (status & CmdLine::KWD_AMBIGUOUS) {
  1443. X      os << "+KWD_AMBIG";
  1444. X   }
  1445. X   if (status & CmdLine::BAD_OPTION) {
  1446. X      os << "+BAD_OPT";
  1447. X   }
  1448. X   if (status & CmdLine::BAD_KEYWORD) {
  1449. X      os << "+BAD_KWD";
  1450. X   }
  1451. X   if (status & CmdLine::BAD_VALUE) {
  1452. X      os << "+BAD_VAL";
  1453. X   }
  1454. X   if (status & CmdLine::TOO_MANY_ARGS) {
  1455. X      os << "+TOO_MANY";
  1456. X   }
  1457. X
  1458. X   return  os;
  1459. X}
  1460. X
  1461. X
  1462. X   // Dump the state of a CmdLine in a mnemonic format
  1463. Xstatic ostream &
  1464. Xdump_cmd_state(ostream & os, unsigned  state)
  1465. X{
  1466. X   if (! state) {
  1467. X      os << "NO_OPTIONS";
  1468. X   } else {
  1469. X      os << "ARGS";
  1470. X   }
  1471. X   if (state & cmd_END_OF_OPTIONS) {
  1472. X      os << "+ENDOPTS";
  1473. X   }
  1474. X   if (state & cmd_OPTIONS_USED) {
  1475. X      os << "+OPTS_USED";
  1476. X   }
  1477. X   if (state & cmd_KEYWORDS_USED) {
  1478. X      os << "+KWDS_USED";
  1479. X   }
  1480. X   if (state & cmd_GUESSING) {
  1481. X      os << "+GUESSING";
  1482. X   }
  1483. X
  1484. X   return  os;
  1485. X}
  1486. X
  1487. X
  1488. X   // Dump the parse_state of a CmdLine in a mnemonic format
  1489. Xstatic ostream &
  1490. Xdump_cmd_parse_state(ostream & os, unsigned parse_state)
  1491. X{
  1492. X   switch (parse_state) {
  1493. X   case cmd_START_STATE :
  1494. X      os << "START_STATE";
  1495. X      break;
  1496. X
  1497. X   case cmd_TOK_REQUIRED :
  1498. X      os << "TOK_REQUIRED";
  1499. X      break;
  1500. X
  1501. X   case cmd_WANT_VAL :
  1502. X      os << "WANT_VAL";
  1503. X      break;
  1504. X
  1505. X   case cmd_NEED_VAL :
  1506. X      os << "NEED_VAL";
  1507. X      break;
  1508. X
  1509. X
  1510. X#ifdef vms_style
  1511. X   case cmd_WANT_VALSEP :
  1512. X      os << "WANT_VALSEP";
  1513. X      break;
  1514. X
  1515. X   case cmd_NEED_VALSEP :
  1516. X      os << "NEED_VALSEP";
  1517. X      break;
  1518. X
  1519. X   case cmd_WANT_LISTSEP :
  1520. X      os << "WANT_LISTSEP";
  1521. X      break;
  1522. X
  1523. X   case cmd_NEED_LISTSEP :
  1524. X      os << "NEED_LISTSEP";
  1525. X      break;
  1526. X
  1527. X#endif
  1528. X
  1529. X   default :
  1530. X      os << parse_state;
  1531. X   }
  1532. X
  1533. X   return  os;
  1534. X}
  1535. X
  1536. X
  1537. X   // Dump the arguments (including the default arguments) in an arg_list
  1538. Xstatic ostream &
  1539. Xdump_cmd_args(ostream & os, CmdArgListList * arg_list, unsigned level)
  1540. X{
  1541. X   ::indent(os, level) << "CmdLine::cmd_args {\n" ;
  1542. X
  1543. X   CmdArgListListIter  list_iter(arg_list);
  1544. X   for (CmdArgList * alist = list_iter() ; alist ; alist = list_iter()) {
  1545. X      CmdArgListIter iter(alist);
  1546. X      for (CmdArg * cmdarg = iter() ; cmdarg ; cmdarg = iter()) {
  1547. X         cmdarg->dump(os, level + 1);
  1548. X      }
  1549. X   }
  1550. X
  1551. X   ::indent(os, level) << "}" << endl;
  1552. X   return  os;
  1553. X}
  1554. X
  1555. X#endif  /* DEBUG_CMDLINE */
  1556. X
  1557. X
  1558. X   // Dump a CmdArg
  1559. Xvoid
  1560. XCmdArg::dump(ostream & os, unsigned level) const
  1561. X{
  1562. X#ifdef DEBUG_CMDLINE
  1563. X   ::indent(os, level) << "CmdArg {\n" ;
  1564. X
  1565. X   ::indent(os, level + 1) << "option='" << char(arg_char_name) << "', "
  1566. X                         << "keyword=\"" << arg_keyword_name << "\", "
  1567. X                         << "value=\"" << arg_value_name << "\"\n" ;
  1568. X
  1569. X   ::indent(os, level + 1) << "syntax=" ;
  1570. X   dump_arg_syntax(os, arg_syntax) << "\n";
  1571. X
  1572. X   ::indent(os, level + 1) << "flags=" ;
  1573. X   dump_arg_flags(os, arg_flags) << "\n";
  1574. X
  1575. X   ::indent(os, level) << "}" << endl;
  1576. X#endif
  1577. X}
  1578. X
  1579. X
  1580. X   // Dump a CmdLine
  1581. Xvoid
  1582. XCmdLine::dump(ostream & os, unsigned level) const
  1583. X{
  1584. X#ifdef DEBUG_CMDLINE
  1585. X   ::indent(os, level) << "CmdLine {\n" ;
  1586. X
  1587. X   ::indent(os, level + 1) << "name=\"" << cmd_name << "\"\n";
  1588. X
  1589. X   ::indent(os, level + 1) << "flags=" ;
  1590. X   dump_cmd_flags(os, cmd_flags) << "\n";
  1591. X
  1592. X   ::indent(os, level + 1) << "status=" ;
  1593. X   dump_cmd_status(os, cmd_status) << "\n";
  1594. X
  1595. X   ::indent(os, level + 1) << "state=" ;
  1596. X   dump_cmd_state(os, cmd_state) << "\n";
  1597. X
  1598. X   ::indent(os, level + 1) << "parse_state=" ;
  1599. X   dump_cmd_parse_state(os, cmd_parse_state) << "\n";
  1600. X
  1601. X   ::indent(os, level + 1);
  1602. X   if (cmd_matched_arg == NULL) {
  1603. X      os << "matched_arg=NULL\n";
  1604. X   } else {
  1605. X      os << "matched_arg=" << (void *)cmd_matched_arg << "\n";
  1606. X   }
  1607. X
  1608. X   ::indent(os, level) << "}" << endl;
  1609. X#endif
  1610. X}
  1611. X
  1612. X
  1613. X   // Dump the arguments of a CmdLine
  1614. Xvoid
  1615. XCmdLine::dump_args(ostream & os, unsigned level) const
  1616. X{
  1617. X#ifdef DEBUG_CMDLINE
  1618. X   dump_cmd_args(os, cmd_args, level);
  1619. X#endif
  1620. X}
  1621. X
  1622. END_OF_FILE
  1623. if test 7287 -ne `wc -c <'src/lib/dump.c'`; then
  1624.     echo shar: \"'src/lib/dump.c'\" unpacked with wrong size!
  1625. fi
  1626. # end of 'src/lib/dump.c'
  1627. fi
  1628. if test -f 'src/lib/strindent.c' -a "${1}" != "-c" ; then 
  1629.   echo shar: Will not clobber existing file \"'src/lib/strindent.c'\"
  1630. else
  1631. echo shar: Extracting \"'src/lib/strindent.c'\" \(8789 characters\)
  1632. sed "s/^X//" >'src/lib/strindent.c' <<'END_OF_FILE'
  1633. X//-------------------------------------------------------------------------
  1634. X// ^FILE: strindent.c - implement the strindent() function
  1635. X//
  1636. X// ^DESCRIPTION:
  1637. X//    This file implements the function strmatch() which matches a 
  1638. X//    keyword (case insensitive) and the function strindent() which
  1639. X//    prints a hanging, indented paragraph.
  1640. X//
  1641. X//    On VMS systems - we also implement a replacement for "getenv()"
  1642. X//    named "getsym()" to get the value of a VMS symbol.
  1643. X//
  1644. X// ^HISTORY:
  1645. X//    12/05/91     Brad Appleton     <brad@ssd.csd.harris.com>     Created
  1646. X//-^^-----------------------------------------------------------------------
  1647. X
  1648. X#include <iostream.h>
  1649. X#include <string.h>
  1650. X#include <ctype.h>
  1651. X
  1652. X#include "cmdline.h"
  1653. X
  1654. X// Need a portable version of tolower
  1655. X//
  1656. X//   NOTE:: I would make this inline except that cfront refuses
  1657. X//          to inline it because it is used twice in expressions
  1658. X//
  1659. X#define TO_LOWER(c)  ((isupper(c)) ? tolower(c) : c)
  1660. X
  1661. X
  1662. X//-------
  1663. X// ^FUNCTION: strmatch - match a keyword
  1664. X//
  1665. X// ^SYNOPSIS:
  1666. X//    static CmdLine::strmatch_t CmdLine::strmatch(src, attempt, len);
  1667. X//
  1668. X// ^PARAMETERS:
  1669. X//    const char * src;
  1670. X//    -- the actual keyword to match against
  1671. X//
  1672. X//    const char * attempt;
  1673. X//    -- the "candidate" that may or may not match the keyword
  1674. X//
  1675. X//    unsigned len;
  1676. X//    -- the number of character of "attempt" to consider (==0 if all
  1677. X//       characters of "attempt" should be used).
  1678. X//
  1679. X// ^DESCRIPTION:
  1680. X//    See if "attempt" matches "src" (either partially or completely) and
  1681. X//    return the result.
  1682. X//
  1683. X// ^REQUIREMENTS:
  1684. X//    None that havent been discusses in the PARAMETERS section.
  1685. X//
  1686. X// ^SIDE-EFFECTS:
  1687. X//    None.
  1688. X//
  1689. X// ^RETURN-VALUE:
  1690. X//    str_EXACT if "attempt" completely matches "src"
  1691. X//    str_PARTIAL is "attempt" partially matches "src"
  1692. X//    str_NONE otherwise
  1693. X//
  1694. X// ^ALGORITHM:
  1695. X//    For each character (in order) of "attempt" to be considered
  1696. X//       if attempt[i] != src[i] (case insensitive) return str_NONE
  1697. X//    end-for
  1698. X//    if we have exhausted "src" return str_EXACT,
  1699. X//    else return str_PARTIAL
  1700. X//-^^----
  1701. XCmdLine::strmatch_t
  1702. XCmdLine::strmatch(const char * src, const char * attempt, unsigned len)
  1703. X{
  1704. X   unsigned  i;
  1705. X
  1706. X   if (src == attempt)  return  str_EXACT ;
  1707. X   if ((src == NULL) || (attempt == NULL))  return  str_NONE ;
  1708. X   if ((! *src) && (! *attempt))  return  str_EXACT ;
  1709. X   if ((! *src) || (! *attempt))  return  str_NONE ;
  1710. X
  1711. X   for (i = 0 ; ((i < len) || (! len)) && (attempt[i] != '\0') ; i++) {
  1712. X      if (TO_LOWER(src[i]) != TO_LOWER(attempt[i]))  return  str_NONE ;
  1713. X   }
  1714. X
  1715. X   return  (src[i] == '\0') ? str_EXACT : str_PARTIAL ;
  1716. X}
  1717. X
  1718. X
  1719. X//--------------------------------------------------------------------------
  1720. X// ^FUNCTION: strindent - print a hanging indented paragraph
  1721. X//
  1722. X// ^SYNOPSIS:
  1723. X//    void CmdLine::strindent(os, maxcols, margin, title, indent, text)
  1724. X//
  1725. X// ^PARAMETERS:
  1726. X//    ostream & os;
  1727. X//    -- the stream to which output is sent
  1728. X//
  1729. X//    unsigned maxcols;
  1730. X//    -- the maximum width (in characters) of the output
  1731. X//
  1732. X//    unsigned margin;
  1733. X//    -- the number of spaces to use as the left margin
  1734. X//
  1735. X//    char * title;
  1736. X//    -- the paragraph title
  1737. X//
  1738. X//    unsigned indent;
  1739. X//    -- the distance between the title and the paragraph body
  1740. X//
  1741. X//    char * text;
  1742. X//    -- the body of the paragraph
  1743. X//
  1744. X// ^DESCRIPTION:
  1745. X//    Strindent will print on os, a titled, indented paragraph as follows:
  1746. X//
  1747. X//    <----------------------- maxcols --------------------------->
  1748. X//    <--- margin --><----- indent ---->
  1749. X//                   title              This is the first sentence
  1750. X//                                      of the paragraph. Etc ...
  1751. X//
  1752. X// ^REQUIREMENTS:
  1753. X//    - maxcols and indent must be positive numbers with maxcols > indent.
  1754. X//    - title should NOT contain any tabs or newlines.
  1755. X//
  1756. X// ^SIDE-EFFECTS:
  1757. X//    Output is printed to os.
  1758. X//
  1759. X// ^RETURN-VALUE:
  1760. X//    None.
  1761. X//
  1762. X// ^ALGORITHM:
  1763. X//    Print the paragraph title and then print the text.
  1764. X//    Lines are automatically adjusted so that each one starts in the
  1765. X//    appropriate column.
  1766. X//-^^-----------------------------------------------------------------------
  1767. Xvoid
  1768. XCmdLine::strindent(ostream    & os,
  1769. X                   unsigned     maxcols,
  1770. X                   unsigned     margin,
  1771. X                   const char * title,
  1772. X                   unsigned     indent,
  1773. X                   const char * text)
  1774. X{
  1775. X   // If we were given non-sensical parameters then dont use them
  1776. X   if (margin > maxcols)  margin = 0;
  1777. X   if ((indent + margin) >= maxcols)  indent = 1;
  1778. X
  1779. X   // print the title (left-justified)
  1780. X   os.width(margin);
  1781. X   os << "" ;
  1782. X   long  save_flags = os.flags();
  1783. X   os.setf(ios::left, ios::adjustfield);
  1784. X   os.width(indent);
  1785. X   os << ((title) ? title : "");
  1786. X   os.flags(save_flags);
  1787. X
  1788. X   if (text == NULL) {
  1789. X      os << endl ;
  1790. X      return;
  1791. X   }
  1792. X
  1793. X   // If the title is too big, start the paragraph on a new line
  1794. X   if (title  &&  (::strlen(title) > indent)) {
  1795. X      os << endl ;
  1796. X      os.width(margin + indent);
  1797. X      os << "";
  1798. X   }
  1799. X
  1800. X   // Loop through the paragraph text witing to print until we absolutely
  1801. X   // have to.
  1802. X   //
  1803. X   unsigned  col = margin + indent + 1;
  1804. X   unsigned  index = 0 ;
  1805. X   unsigned  last_white = 0 ;
  1806. X   const char * p = text ;
  1807. X
  1808. X   while (p[index]) {
  1809. X      switch (p[index]) {
  1810. X         // If we have a space - just remember where it is
  1811. X      case ' ' :
  1812. X         last_white = index;
  1813. X         ++col;
  1814. X         ++index;
  1815. X         break;
  1816. X
  1817. X         // If we have a tab - remember where it is and assume it
  1818. X         // will take up 8 spaces in the output.
  1819. X         //
  1820. X      case '\t' :
  1821. X         last_white = index;
  1822. X         col += 8;
  1823. X         ++index;
  1824. X         break;
  1825. X
  1826. X         // If we have a form-feed, carriage-return, or newline, then
  1827. X         // print what we have so far (including this character) and
  1828. X         // start a new line.
  1829. X         //
  1830. X      case '\n' :
  1831. X      case '\r' :
  1832. X      case '\f' :
  1833. X         os.write(p, index + 1);
  1834. X         p += index + 1;
  1835. X         col = margin + indent + 1;
  1836. X         index = last_white = 0;
  1837. X         if (*p) {
  1838. X            os.width(margin + indent);
  1839. X            os << "";
  1840. X         }
  1841. X         break;
  1842. X
  1843. X      default:
  1844. X         ++col;
  1845. X         ++index;
  1846. X         break;
  1847. X      } //switch
  1848. X
  1849. X         // Are we forced to start a new line?
  1850. X      if (col > maxcols) {
  1851. X            // Yes - if possible, print upto the last whitespace character
  1852. X            //       and start the next line on a word-boundary
  1853. X         if (last_white) {
  1854. X            os.write(p, last_white);
  1855. X            p += last_white;
  1856. X            while (*p == ' ')  ++p;
  1857. X         } else {
  1858. X               // No word boundary in sight - just split the line here!
  1859. X            os.write(p, index);
  1860. X            p += index;
  1861. X         }
  1862. X         os << endl ;
  1863. X
  1864. X            // We just printed a newline - dont print another one right now
  1865. X         while ((*p == '\n') || (*p == '\r') || (*p == '\f'))  ++p;
  1866. X         col = margin + indent + 1;
  1867. X         index = last_white = 0;
  1868. X         if (*p) {
  1869. X            os.width(margin + indent);
  1870. X            os << "";
  1871. X         }
  1872. X      } else if (index && (! p[index])) {
  1873. X         os << p << endl ;
  1874. X      }
  1875. X   } //while
  1876. X}
  1877. X
  1878. X
  1879. X#ifdef vms
  1880. X
  1881. X#  include <descrip.h>
  1882. X#  include <libdef.h>
  1883. X
  1884. X   extern "C" {
  1885. X      long   lib$get_symbol(...);
  1886. X      void   exit(int);
  1887. X   }
  1888. X
  1889. X//----------------------
  1890. X// ^FUNCTION: getsym - retrieve the value of a VMS symbol
  1891. X//
  1892. X// ^SYNOPSIS:
  1893. X//    const char * getsym(sym_name)
  1894. X//
  1895. X// ^PARAMETERS:
  1896. X//    char * sym_name;
  1897. X//    -- name of the symbol to retrieve
  1898. X//
  1899. X// ^DESCRIPTION:
  1900. X//    Get_symbol will lookup the named symbol and return its value
  1901. X//    as a string.
  1902. X//
  1903. X// ^REQUIREMENTS:
  1904. X//    sym_name should correspond to the name of a pre-defined symbol.
  1905. X//
  1906. X// ^SIDE-EFFECTS:
  1907. X//    None.  NO storage is allocated for the symbol-value and it will
  1908. X//    be overwritten by the next call to this function.
  1909. X//
  1910. X// ^RETURN-VALUE:
  1911. X//    NULL if the symbol is not found, otherwise it returns a pointer
  1912. X//    to a static buffer containing the contents of the symbol value.
  1913. X//    You MUST be finished using this buffer before another call to
  1914. X//    get_symbol is made.
  1915. X//
  1916. X// ^ACKNOWLEDGEMENTS:
  1917. X//    Thanx to Jim Barbour for writing most of this code. --BDA
  1918. X//
  1919. X// ^ALGORITHM:
  1920. X//    Trivial - just use the LIB$GET_SYMBOL system service.
  1921. X//-^^-------------------
  1922. Xconst char *
  1923. Xgetsym(const char * sym_name)
  1924. X{
  1925. X   static  char  sym_value[256];
  1926. X   unsigned long   stat;
  1927. X   unsigned short  buflen;
  1928. X   $DESCRIPTOR(sym_name_d, sym_name);
  1929. X   $DESCRIPTOR(sym_value_d, sym_value);
  1930. X
  1931. X   sym_value_d.dsc$w_length = sizeof(sym_value);
  1932. X   sym_name_d.dsc$w_length = ::strlen(sym_name);
  1933. X   stat = lib$get_symbol(&sym_name_d, &sym_value_d, &buflen, (void *)0);
  1934. X   if (stat == LIB$_NOSUCHSYM) {
  1935. X      return  NULL;
  1936. X   } else if (! (stat & 1)) {
  1937. X      ::exit(stat);
  1938. X   }
  1939. X   sym_value[buflen] = '\0';
  1940. X   return  sym_value;
  1941. X}
  1942. X
  1943. X#endif  /* vms */
  1944. END_OF_FILE
  1945. if test 8789 -ne `wc -c <'src/lib/strindent.c'`; then
  1946.     echo shar: \"'src/lib/strindent.c'\" unpacked with wrong size!
  1947. fi
  1948. # end of 'src/lib/strindent.c'
  1949. fi
  1950. if test -f 'src/lib/usage.c' -a "${1}" != "-c" ; then 
  1951.   echo shar: Will not clobber existing file \"'src/lib/usage.c'\"
  1952. else
  1953. echo shar: Extracting \"'src/lib/usage.c'\" \(9043 characters\)
  1954. sed "s/^X//" >'src/lib/usage.c' <<'END_OF_FILE'
  1955. X//------------------------------------------------------------------------
  1956. X// ^FILE: usage.c - functions to print the usage of a CmdLine
  1957. X//
  1958. X// ^DESCRIPTION:
  1959. X//     This file contains the functions that are used to print the
  1960. X//  command-line usage of a command that is represented by a CmdLine
  1961. X//  object.
  1962. X//
  1963. X// ^HISTORY:
  1964. X//    01/09/92    Brad Appleton    <brad@ssd.csd.harris.com>    Created
  1965. X//-^^---------------------------------------------------------------------
  1966. X
  1967. X#include <iostream.h>
  1968. X#include <stdlib.h>
  1969. X#include <string.h>
  1970. X
  1971. X#include "cmdline.h"
  1972. X#include "states.h"
  1973. X#include "arglist.h"
  1974. X
  1975. X#ifdef vms
  1976. X#  define  getenv  getsym
  1977. X   extern  const char * getsym(const char *);
  1978. X#endif
  1979. X
  1980. X
  1981. X//-------
  1982. X// ^FUNCTION: CmdLine::get_usage_level
  1983. X//
  1984. X// ^SYNOPSIS:
  1985. X//    CmdLine::CmdUsageLevel CmdLine::get_usage_level(void)
  1986. X//
  1987. X// ^PARAMETERS:
  1988. X//    NONE.
  1989. X//
  1990. X// ^DESCRIPTION:
  1991. X//    Gets the usage_level that tells us how "verbose" we should be
  1992. X//    when printing usage-messages. This usage_level is recorded in
  1993. X//    the environment variable $USAGE_LEVEL. This variable may have the
  1994. X//    following values:
  1995. X//
  1996. X//       0 : Dont print usage at all.
  1997. X//       1 : Print a terse usage message (command-line syntax only).
  1998. X//       2 : Print a verbose usage message (include argument descriptions).
  1999. X//
  2000. X//    If $USAGE_LEVEL is not defined or is empty, then the default
  2001. X//    usage_level is 2.
  2002. X//
  2003. X// ^REQUIREMENTS:
  2004. X//
  2005. X// ^SIDE-EFFECTS:
  2006. X//    None.
  2007. X//
  2008. X// ^RETURN-VALUE:
  2009. X//    The usage level to use.
  2010. X//
  2011. X// ^ALGORITHM:
  2012. X//    Read the usage_level from the environment and return it.
  2013. X//-^^----
  2014. XCmdLine::CmdUsageLevel
  2015. XCmdLine::get_usage_level(void)
  2016. X{
  2017. X   long level;
  2018. X   char * end_scan, * level_str = ::getenv("USAGE_LEVEL");
  2019. X
  2020. X   if (level_str == NULL)  return  VERBOSE_USAGE ;
  2021. X   if (*level_str == '\0') return  NO_USAGE ;
  2022. X
  2023. X   level = ::strtol(level_str, &end_scan, 0);
  2024. X   if (end_scan == level_str)  return  VERBOSE_USAGE ;
  2025. X
  2026. X   switch(level) {
  2027. X      case 0 :  return NO_USAGE ;
  2028. X      case 1 :  return TERSE_USAGE ;
  2029. X      default:  return VERBOSE_USAGE ;
  2030. X   }
  2031. X}
  2032. X
  2033. X//-------
  2034. X// ^FUNCTION: CmdLine::print_synopsis
  2035. X//
  2036. X// ^SYNOPSIS:
  2037. X//    unsigned CmdLine::print_synopsis(syntax, os, cols)
  2038. X//
  2039. X// ^PARAMETERS:
  2040. X//    CmdLine::CmdLineSyntax syntax;
  2041. X//    -- the syntax to use (long-option, short-option, or both)
  2042. X//       when printing the synopsis.
  2043. X//
  2044. X//    ostream & os;
  2045. X//    -- where to print.
  2046. X//
  2047. X//    int cols;
  2048. X//    -- the maximum width of a line.
  2049. X//
  2050. X// ^DESCRIPTION:
  2051. X//    Print a command-line synopsis (the command-line syntax).
  2052. X//    The synopsis should be printed to "os" using the desired syntax,
  2053. X//    in lines that are no more than "cols" characters wide.
  2054. X//
  2055. X// ^REQUIREMENTS:
  2056. X//
  2057. X// ^SIDE-EFFECTS:
  2058. X//     Prints on "os".
  2059. X//
  2060. X// ^RETURN-VALUE:
  2061. X//     The length of the longest argument-buf that was printed.
  2062. X//
  2063. X// ^ALGORITHM:
  2064. X//     It's kind of complicated so follow along!
  2065. X//-^^----
  2066. Xunsigned
  2067. XCmdLine::print_synopsis(CmdLine::CmdLineSyntax  syntax,
  2068. X                        ostream    & os,
  2069. X                        int          cols) const
  2070. X{
  2071. X#ifdef vms_style
  2072. X   static  char  usg_prefix[] = "Format: ";
  2073. X#else
  2074. X   static  char  usg_prefix[] = "Usage: ";
  2075. X#endif
  2076. X
  2077. X   unsigned  ll, positionals, longest = 0;
  2078. X
  2079. X   // first print the command name
  2080. X   os << usg_prefix << cmd_name ;
  2081. X   ll = (cmd_name ? ::strlen(cmd_name) : 0) + (sizeof(usg_prefix) - 1);
  2082. X
  2083. X   // set margin so that we always start printing arguments in a column
  2084. X   // that is *past* the command name.
  2085. X   //
  2086. X   unsigned  margin = ll + 1;
  2087. X
  2088. X   // print option-syntax followed by positional parameters
  2089. X   int  first;
  2090. X   char buf[256] ;
  2091. X   for (positionals = 0 ; positionals < 2 ; positionals++) {
  2092. X      first = 1;
  2093. X      CmdArgListListIter  list_iter(cmd_args);
  2094. X      for (CmdArgList * alist = list_iter() ; alist ; alist = list_iter()) {
  2095. X         CmdArgListIter  iter(alist);
  2096. X         for (CmdArg * cmdarg = iter() ; cmdarg ; cmdarg = iter()) {
  2097. X            unsigned  len, pl;
  2098. X
  2099. X               // don't display hidden arguments
  2100. X            if (cmdarg->syntax() & CmdArg::isHIDDEN)  continue;
  2101. X            if (!positionals  &&  (cmdarg->syntax() & CmdArg::isPOS))  continue;
  2102. X            if (positionals  &&  !(cmdarg->syntax() & CmdArg::isPOS))  continue;
  2103. X
  2104. X               // figure out how wide this parameter is (for printing)
  2105. X            pl = len = fmt_arg(cmdarg, buf, sizeof(buf), syntax, VERBOSE_USAGE);
  2106. X            if (! len)  continue;
  2107. X
  2108. X            if (cmdarg->syntax() & CmdArg::isLIST)  pl -= 4 ;  // " ..."
  2109. X            if (! (cmdarg->syntax() & CmdArg::isREQ))  pl -= 2 ;   // "[]"
  2110. X            if (pl > longest)  longest = pl;
  2111. X
  2112. X            //  Will this fit?
  2113. X            if ((ll + len + 1) > (cols - first)) {
  2114. X               os << char('\n') ;
  2115. X               os.width(margin);
  2116. X               os << "" ;  // No - start a new line;
  2117. X               ll = margin;
  2118. X            } else {
  2119. X               os << char(' ') ;  // Yes - just throw in a space
  2120. X               ++ll;
  2121. X            }
  2122. X            ll += len;
  2123. X            os << buf;
  2124. X
  2125. X            first = 0;
  2126. X         } //for each cmdarg
  2127. X      } //for each arg-list
  2128. X   } //for each parm-type
  2129. X   os << endl ;
  2130. X
  2131. X   return  longest ;
  2132. X}
  2133. X
  2134. X
  2135. X//-------
  2136. X// ^FUNCTION: CmdLine::print_descriptions
  2137. X//
  2138. X// ^SYNOPSIS:
  2139. X//    unsigned CmdLine::print_descriptions(syntax, os, cols, longest)
  2140. X//
  2141. X// ^PARAMETERS:
  2142. X//    CmdLine::CmdLineSyntax syntax;
  2143. X//    -- the syntax to use (long-option, short-option, or both)
  2144. X//       when printing the synopsis.
  2145. X//
  2146. X//    ostream & os;
  2147. X//    -- where to print.
  2148. X//
  2149. X//    int cols;
  2150. X//    -- the maximum width of a line.
  2151. X//
  2152. X//    unsigned longest;
  2153. X//    -- value returned by print_synopsis.
  2154. X//
  2155. X// ^DESCRIPTION:
  2156. X//    Print a command argument descriptions (using the command-line syntax).
  2157. X//    The descriptions should be printed to "os" using the desired syntax,
  2158. X//    in lines that are no more than "cols" characters wide.
  2159. X//
  2160. X// ^REQUIREMENTS:
  2161. X//    "longest" should correspond to a value returned by print_synopsis
  2162. X//    that used the same "cmd" and syntax.
  2163. X//
  2164. X// ^SIDE-EFFECTS:
  2165. X//     Prints on "os".
  2166. X//
  2167. X// ^RETURN-VALUE:
  2168. X//     None.
  2169. X//
  2170. X// ^ALGORITHM:
  2171. X//     Print the description for each argument.
  2172. X//-^^----
  2173. Xvoid
  2174. XCmdLine::print_descriptions(CmdLine::CmdLineSyntax   syntax,
  2175. X                            ostream                & os,
  2176. X                            int                      cols,
  2177. X                            unsigned                 longest) const
  2178. X{
  2179. X   int positionals, options = 0;
  2180. X   char buf[256];
  2181. X
  2182. X   for (positionals = 0 ; positionals < 2 ; positionals++) {
  2183. X      CmdArgListListIter  list_iter(cmd_args);
  2184. X      for (CmdArgList * alist = list_iter() ; alist ; alist = list_iter()) {
  2185. X         CmdArgListIter  iter(alist);
  2186. X         for (CmdArg * cmdarg = iter() ; cmdarg ; cmdarg = iter()) {
  2187. X               // don't display hidden arguments
  2188. X            if (cmdarg->syntax() & CmdArg::isHIDDEN)  continue;
  2189. X            if (!positionals  &&  (cmdarg->syntax() & CmdArg::isPOS))  continue;
  2190. X            if (positionals  &&  !(cmdarg->syntax() & CmdArg::isPOS))  continue;
  2191. X
  2192. X#ifdef vms_style
  2193. X            if ( !options++ )   os << "Qualifiers/Parameters:\n" ;
  2194. X#else
  2195. X            if ( !options++ )   os << "Options/Arguments:\n" ;
  2196. X#endif
  2197. X            if (! fmt_arg(cmdarg, buf, sizeof(buf), syntax, TERSE_USAGE)) {
  2198. X               continue;
  2199. X            }
  2200. X            const char * description = cmdarg->description();
  2201. X            if ((description == NULL) || (! *description))  continue;
  2202. X            strindent(os, cols, 8, buf, (longest + 2), description);
  2203. X         } //for each cmdarg
  2204. X      } //for each arg-list
  2205. X   } //for each parm-type
  2206. X}
  2207. X
  2208. X//-------
  2209. X// ^FUNCTION: CmdLine::usage - print command-usage
  2210. X//
  2211. X// ^SYNOPSIS:
  2212. X//    void CmdLine::usage(os, usage_level);
  2213. X//
  2214. X// ^PARAMETERS:
  2215. X//    ostream & os;
  2216. X//    -- where to print.
  2217. X//
  2218. X//    CmdLine::CmdUsageLevel  usage_level;
  2219. X//    -- verboseness to use.
  2220. X//
  2221. X// ^DESCRIPTION:
  2222. X//    Print the usage for the given CmdLine object on "os".
  2223. X//
  2224. X// ^REQUIREMENTS:
  2225. X//
  2226. X// ^SIDE-EFFECTS:
  2227. X//    Prints on "os".
  2228. X//
  2229. X// ^RETURN-VALUE:
  2230. X//    None.
  2231. X//
  2232. X// ^ALGORITHM:
  2233. X//    - get the usage level.
  2234. X//    - determine which syntax to use
  2235. X//    - get the max-columns for "os".
  2236. X//    - print synopsis if required.
  2237. X//    - print descriptions if required.
  2238. X//-^^----
  2239. Xostream &
  2240. XCmdLine::usage(ostream & os, CmdLine::CmdUsageLevel usage_level) const
  2241. X{
  2242. X   // get user-specified usage-level
  2243. X   //   (if status is zero this must be an explicit request so force verbose)
  2244. X   //
  2245. X   if (usage_level == DEFAULT_USAGE)  usage_level = get_usage_level();
  2246. X   if (usage_level == NO_USAGE)  return  os;
  2247. X
  2248. X   // determine syntax to use
  2249. X   CmdLineSyntax  cmd_syntax = syntax() ;
  2250. X
  2251. X   // get screen size (dont know how to do this yet)
  2252. X   int  max_cols = 79;
  2253. X
  2254. X   // print command-line synopsis
  2255. X   unsigned  longest = print_synopsis(cmd_syntax, os, max_cols) ;
  2256. X   if (usage_level == TERSE_USAGE)  return  os;
  2257. X
  2258. X   // now print argument descriptions
  2259. X   os << "\n" ;
  2260. X   print_descriptions(cmd_syntax, os, max_cols, longest) ;
  2261. X   return  os;
  2262. X}
  2263. X
  2264. Xostream &
  2265. XCmdLine::usage(CmdLine::CmdUsageLevel usage_level) const {
  2266. X   return  usage(*cmd_err, usage_level);
  2267. X}
  2268. X
  2269. END_OF_FILE
  2270. if test 9043 -ne `wc -c <'src/lib/usage.c'`; then
  2271.     echo shar: \"'src/lib/usage.c'\" unpacked with wrong size!
  2272. fi
  2273. # end of 'src/lib/usage.c'
  2274. fi
  2275. echo shar: End of archive 3 \(of 7\).
  2276. cp /dev/null ark3isdone
  2277. MISSING=""
  2278. for I in 1 2 3 4 5 6 7 ; do
  2279.     if test ! -f ark${I}isdone ; then
  2280.     MISSING="${MISSING} ${I}"
  2281.     fi
  2282. done
  2283. if test "${MISSING}" = "" ; then
  2284.     echo You have unpacked all 7 archives.
  2285.     rm -f ark[1-9]isdone
  2286. else
  2287.     echo You still need to unpack the following archives:
  2288.     echo "        " ${MISSING}
  2289. fi
  2290. ##  End of shell archive.
  2291. exit 0
  2292.  
  2293. exit 0 # Just in case...
  2294.