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

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