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

  1. Newsgroups: comp.sources.misc
  2. Path: sparky!kent
  3. From: brad@hcx1.ssd.csd.harris.com (Brad Appleton)
  4. Subject:  v31i052:  cmdline - C++ Library for parsing command-line arguments, Part05/07
  5. Message-ID: <1992Jul27.020821.29747@sparky.imd.sterling.com>
  6. Followup-To: comp.sources.d
  7. X-Md4-Signature: 1a604c4b595c1ea79014837919db452c
  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:08:21 GMT
  13. Approved: kent@sparky.imd.sterling.com
  14. Lines: 2064
  15.  
  16. Submitted-by: brad@hcx1.ssd.csd.harris.com (Brad Appleton)
  17. Posting-number: Volume 31, Issue 52
  18. Archive-name: cmdline/part05
  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 5 (of 7)."
  28. # Contents:  doc/cmdparse.man1 src/lib/cmdargs.c src/lib/private.c
  29. # Wrapped by brad@hcx1 on Mon Jul 20 10:41:31 1992
  30. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  31. if test -f 'doc/cmdparse.man1' -a "${1}" != "-c" ; then 
  32.   echo shar: Will not clobber existing file \"'doc/cmdparse.man1'\"
  33. else
  34. echo shar: Extracting \"'doc/cmdparse.man1'\" \(21692 characters\)
  35. sed "s/^X//" >'doc/cmdparse.man1' <<'END_OF_FILE'
  36. X.\"========== TO PRINT, USE: {n,t}roff -man file ==========
  37. X.if n .po 1
  38. X.if n .ll 78
  39. X.nh
  40. X.ds NM \f4cmdparse\fP
  41. X.ds | \f4|\fP
  42. X.so macros.man
  43. X.\"===================================
  44. X.TH cmdparse 1
  45. X.\"===================================
  46. X.SH NAME
  47. Xcmdparse \- parse command-line arguments for shell-scripts
  48. X.\"===================================
  49. X.SH SYNOPSIS
  50. X.na
  51. X.TP 12
  52. X\fBcmdparse\fP
  53. X[\fB\-anywhere\fP]
  54. X[\fB\-ignore-case\fP]
  55. X[\fB\-noabort\fP]
  56. X[\fB\-noguessing\fP]
  57. X[\fB\-prompt\fP]
  58. X.if t .br
  59. X[\fB\-options-only\fP]
  60. X[\fB\-keywords-only\fP]
  61. X[\fB\-quiet\fP]
  62. X[\fB\-arrays\fP]
  63. X[\fB\-usage\fP]
  64. X[\fB\-version\fP]
  65. X.if t .br
  66. X[\fB\-true\fP\ \fIstring\fP]
  67. X[\fB\-false\fP\ \fIstring\fP]
  68. X[\fB\-suffix\fP\ \fIstring\fP]
  69. X.if n .br
  70. X[\fB\-shell\fP\ \fIshellname\fP]
  71. X.if t .br
  72. X[\fB\-file\fP\ \fIfilename\fP]
  73. X[\fB\-env\fP\ \fIvarname\fP]
  74. X[\fB\-decls\fP\ \fIstring\fP]
  75. X.if t .br
  76. X\*(--\ \ 
  77. X\fIprogram-name\fP\ \ 
  78. X\fIarguments\fP\ .\^.\^.
  79. X.ad
  80. X.\"===================================
  81. X.SH DESCRIPTION
  82. X\*(NM will parse the user's command-line arguments using the
  83. X\f4CmdLine\fP(3\*(C+) library (taking into account any user-specified
  84. Xpreferences) and will print on standard output, a host of variable
  85. Xsettings using the syntax of the specified shell.  The user must then
  86. X"evaluate" the output of \*(NM in order to set the corresponding
  87. Xvariables for his (or her) shell-script.
  88. X
  89. XIf none of \fB\-file\fP, \fB\-env\fP, or \fB\-decls\fP is given then
  90. Xthe argument declarations will be read from standard input (unless
  91. Xstandard input is associated with a terminal, in which case an error
  92. Xwill result).
  93. X
  94. XIf more than one of \fB\-file\fP, \fB\-env\fP, or \fB\-decls\fP is given
  95. Xthen argument declarations are read from all the places specified but
  96. Xin the following order:
  97. X
  98. X.RS
  99. XFirst, argument declarations are read from the string supplied with the
  100. X\fB\-decls\fP option.
  101. X
  102. XSecond, any argument declarations contained in the environment variable
  103. Xspecified by the \fB\-env\fP option are appended to the current set of
  104. Xargument declarations.
  105. X
  106. XLastly, any argument declarations contained in the file specified
  107. Xby the \fB\-file\fP option are appended to the current set of
  108. Xargument declarations.
  109. X.RE
  110. X
  111. XThe order in which the set of argument declarations are processed is important
  112. Xbecause any positional parameters that were specified are expected to occur
  113. Xin the same order as the order in which the corresponding argument declarations
  114. Xwere processed.
  115. X
  116. XDepending upon which shell you are using, you may want to evaluate the output
  117. Xof \*(NM directly (as in "\f4eval $cmdparse_output\fP") or you may wish to
  118. Xfirst redirect output to a file and then evaluate it (as in "\f4.\ cmdparse_output\fP").  Some shells may not preserve all the special
  119. Xcharacters (such as a newline) correctly when the former approach is used.
  120. XOther shells may not permit you to change the value of "local" variables
  121. Xin "sourced" files when the latter approach is used.  You will have to
  122. Xdecide which approach to use based upon your needs, and the shell you are
  123. Xusing.
  124. X
  125. X.\"===================================
  126. X.SH EXAMPLE
  127. X.nf
  128. X.ft 4
  129. X#!/bin/sh
  130. X#
  131. X# Here is a Bourne Shell script named "cmdname".
  132. X#
  133. X# The short-option syntax is:
  134. X#     cmdname [\-c number] [\-x] [\-s char]
  135. X#             input-file [output-file \*(..]
  136. X#
  137. X# The long-option syntax is:
  138. X#     cmdname [\*(--count number] [\*(--xmode] [\*(--separator char]
  139. X#             input-file [output-file \*(..]
  140. X#             
  141. XNAME="`basename $0`"
  142. X
  143. X## Declare the arguments.
  144. XARGS='
  145. X   ArgInt   count  "[c|count number]"    "number of copies to print."
  146. X   ArgBool  xflag  "[x|xmode]"           "turn on x-mode."
  147. X   ArgChar  fdsep  "[s|separator char]"  "field-separator to use."
  148. X   ArgStr   input  "input-file"          "input file to read."
  149. X   ArgStr   output "[output-file \*(..]"   "where to print output."
  150. X\&'
  151. X
  152. X## Parse the arguments
  153. Xif  cmdparse \-shell=sh \-decls="$ARGS" \*(-- $NAME "$@" > tmp$$
  154. Xthen
  155. X   ## Success \- evaluate the result.
  156. X   \&.  tmp$$
  157. X   rm \-f tmp$$
  158. Xelse
  159. X   ## Either usage was printed or we found a syntax error.
  160. X   EXITVAL=$?
  161. X   rm \-f tmp$$
  162. X   exit $EXITVAL
  163. Xfi
  164. X
  165. X## Print the arguments
  166. Xecho "xflag=" $xflag
  167. Xecho "count=" $count
  168. Xecho "fdsep=" $fdsep
  169. Xecho "input=" $input
  170. Xif [ "$output" ] ; then
  171. X   echo "output=" $output
  172. Xfi
  173. X.ft R
  174. X.fi
  175. X.\"===================================
  176. X.SH OPTIONS
  177. XOnly a unique prefix of each option-name needs to be given (and the
  178. Xoptions are matched case-insensitive).
  179. XThe possible options are as follows:
  180. X
  181. X.TP
  182. X\fB\-anywhere\fP
  183. XAllow options (and keywords) to follow positional parameters.
  184. XUnless this option is specified, anything that follows a positional
  185. Xparameter that resembles an option (begins with a `\-') will be
  186. Xtreated as yet another positional parameter.
  187. X.TP
  188. X\fB\-ignore-case\fP
  189. XIgnore character case on single-character options.
  190. X.TP
  191. X\fB\-noabort\fP
  192. XDon't exit if improper command-line syntax was used. Just ignore the
  193. Xerrors and continue parsing.
  194. X.TP
  195. X\fB\-noguessing\fP
  196. XBy default, if an unknown single-character option appears on the command-line,
  197. X\*(NM will "guess" by seeing if the option corresponds to a keyword.
  198. XSimilarly, if an unknown keyword (long-option) is encountered, \*(NM
  199. Xwill see if it matches a single-character option.  Specifying this option
  200. Xdisables this behavior.
  201. X.TP
  202. X\fB\-prompt\fP
  203. XPrompt the user interactively for any missing required arguments.
  204. X.TP
  205. X\fB\-options-only\fP
  206. XDon't match keywords (long-options).  Look only for single-character options.
  207. X.TP
  208. X\fB\-keywords-only\fP
  209. XDon't match options.  Look only for keywords (long-options). Using this
  210. Xoption also allows the single-character option prefix (`\-') to be used
  211. Xfor long-options.
  212. X.TP
  213. X\fB\-quiet\fP
  214. XDon't print command-line syntax error messages.
  215. X.TP
  216. X\fB\-arrays\fP
  217. XUse alternative syntax for arrays. See the appropriate subsection of
  218. Xthe section \s-1\fBSHELLS\fP\s+1 to see how (and if) this option will affect
  219. Xthe output of \*(NM.
  220. X.TP
  221. X\fB\-usage\fP
  222. XPrint command-line usage and exit.  Don't parse anything!
  223. X.TP
  224. X\fB\-version\fP
  225. XPrint version information and exit.  Don't parse anything!
  226. X.TP
  227. X\fB\-true\fP\ \fIstring\fP
  228. XThe string to use for boolean arguments that are turned \fIon\fP.
  229. XThe default string is \f4"TRUE"\fP (unless the \fIperl\fP or \fItcl\fP shells
  230. Xare used, in which case the default is \f4"1"\fP).
  231. X.TP
  232. X\fB\-false\fP\ \fIstring\fP
  233. XThe string to use for boolean arguments that are turned \fIoff\fP.
  234. XThe default string is \f4""\fP (unless the \fIperl\fP or \fItcl\fP shells
  235. Xare used, in which case the default is \f4"0"\fP).
  236. X.TP
  237. X\fB\-suffix\fP\ \fIstring\fP
  238. XWhen no value is supplied for an option that takes an optional value,
  239. Xthe variable \fInamesuffix\fP, is set to \s-1TRUE\s+1 (where \fIname\fP
  240. Xis the name of the corresponding variable and \fIsuffix\fP is the string
  241. Xargument given to this option).  If this option is not specified then
  242. Xthe suffix "\f4_FLAG\fP" will be used.
  243. X.TP
  244. X\fB\-shell\fP\ \fIshellname\fP
  245. XSet program arguments using the syntax of the given shell
  246. X(default=\fIsh\fP).
  247. X.TP
  248. X\fB\-file\fP\ \fIfilename\fP
  249. XThe file from which program argument declarations are read.
  250. XIf \fIfilename\fP is ``\-'' then standard input is read.
  251. X.TP
  252. X\fB\-env\fP\ \fIvarname\fP
  253. XThe name of the environment variable containing the program argument
  254. Xdeclarations.
  255. X.TP
  256. X\fB\-decls\fP\ \fIstring\fP
  257. XThe string that contains the program argument declarations.
  258. X.TP
  259. X\*(--
  260. XIndicates the end of options/keywords.
  261. X.TP
  262. X\fIprogram-name\fP
  263. XThe name of the program whose arguments are to be parsed.
  264. XIf desired, the \fIprogram-name\fP may be specified as a keyword
  265. X(instead of positionally) using the syntax \fB\-name\fP=\fIprogram-name\fR.
  266. X.TP
  267. X\fIarguments\fP\ .\^.\^.
  268. XThe program-arguments to be parsed
  269. X
  270. X.\"===================================
  271. X.SH EXIT STATUS
  272. X\*(NM will exit with one of the following status codes:
  273. X
  274. X.IP 0
  275. XArguments were successfully parsed. No syntax errors were found and the
  276. Xshell-script variable settings have been printed on standard output.
  277. X
  278. X.IP 1
  279. XEither usage or version information was explicitly requested. The desired
  280. Xinformation was printed on standard diagnostic output. No arguments were
  281. Xparsed.
  282. X
  283. X.IP 2
  284. XSome type of command-line syntax error occurred. Any syntax error messages
  285. Xhave been printed on standard diagnostic output.
  286. X
  287. X.IP 3
  288. XAn invalid or unknown shell (command-interpreter) was specified on the
  289. Xcommand-line to \*(NM.  See the section entitled \s-1\fBSHELLS\fP\s+1
  290. Xfor a list of the known shells.
  291. X
  292. X.IP 4
  293. XA syntax error of some type occurred in one or more command-line argument
  294. Xdeclarations.  Any syntax error messages
  295. Xhave been printed on standard diagnostic output.
  296. X.\"===================================
  297. X.so parsing.man
  298. X.\"===================================
  299. X.SH ARGUMENT DECLARATIONS
  300. XThe syntax for a single argument for \*(NM looks like the following:
  301. X
  302. X.RS
  303. X<\fIarg-type\fP>  <\fIarg-name\fP>  <\fIsyntax\fP>  <\fIdescription\fP>
  304. X.RE
  305. X
  306. XWhere <\fIarg-type\fP> is one of the following (case-insensitive):
  307. X
  308. X.RS
  309. X.IP \f4ArgInt\fP  15
  310. XAn integer value (or list of values).
  311. X.IP \f4ArgFloat\fP  15
  312. XA floating-point value (or list of values).
  313. X.IP \f4ArgChar\fP  15
  314. XA character value (or list of values).
  315. X.IP \f4ArgStr\fP  15
  316. XA string value (or list of values).
  317. X.IP \f4ArgBool\fP  15
  318. XA boolean flag that is initially \s-1FALSE\s+1 and is turned \fIon\fP
  319. Xwhenever it is matched.
  320. X.IP \f4ArgClear\fP  15
  321. XA boolean flag that is initially \s-1TRUE\s+1 and is turned \fIoff\fP
  322. Xwhenever it is matched.
  323. X.IP \f4ArgToggle\fP  15
  324. XA boolean flag that is initially \s-1FALSE\s+1 and is \fItoggled\fP
  325. Xwhenever it is matched.
  326. X.IP \f4ArgUsage\fP  15
  327. XPrint usage and exit.
  328. X.IP \f4ArgDummy\fP  15
  329. XA dummy argument.
  330. X.RE
  331. X
  332. XIf desired, the leading "\f4Arg\fP" portion of the type-name may be omitted.
  333. X
  334. XThe field <\fIarg-name\fP> is simply the name of the variable in your script
  335. Xthat you wish to contain the resultant value from the command-line.
  336. XAny default value must be assigned to the variable \fIbefore\fP invoking
  337. X\*(NM.
  338. X
  339. XThe fields <\fIsyntax\fP> and <\fIdescription\fP> \s-1MUST\s+1 be enclosed
  340. Xin either single or double quotes! If you want the character you are using
  341. Xto quote the field to also appear within the field, then precede the quote
  342. Xcharacter (inside the quotes) with a backslash (`\\').
  343. X
  344. XThe <\fIdescription\fP> is simply a textual description of the argument.
  345. XThe <\fIsyntax\fP> is a little trickier, there are three basic forms of syntax:
  346. X
  347. X.RS
  348. X.TP
  349. X\f4"c|keyword"\fP
  350. XAn option that may be matched by \fB\-c\fP or by \fB\*(--keyword\fP
  351. Xand takes no value.
  352. X.TP
  353. X\f4"c|keyword\ \ value"\fP
  354. XAn option that may be matched by \fB\-c\fP or by \fB\*(--keyword\fP
  355. Xand requires a value.
  356. X.TP
  357. X\f4"value"\fP
  358. XA positional parameter.
  359. X.RE
  360. X
  361. XNote that the option-character \s-1MUST\s+1 precede the keyword-name and that
  362. Xthere must be \s-1NO\s+1 spaces surrounding the `\*|' in
  363. X``\f4c|keyword\fP'' (unless either the option-character or the keyword-name
  364. Xis intended to be empty).  If you wish a keyword to have no corresponding
  365. Xshort-option (or vice versa) than put a blank in the option-character
  366. X(or keyword) portion of the syntax declaration.
  367. X
  368. XAny optional parts of the argument should appear inside square-brackets
  369. X(`[' and `]') and a list of values is denoted by an ellipsis (`` .\^.\^.'').
  370. XMost options will be inside of square brackets to reflect the fact that
  371. Xthey are "optional".
  372. X
  373. XSome example <\fIsyntax\fP> strings follow:
  374. X
  375. X.RS
  376. X.TP
  377. X\f4"c|keyword"\fP
  378. XA required option.
  379. X.TP
  380. X\f4"[c|keyword]"\fP
  381. XAn option with no value.
  382. X.TP
  383. X\f4"[c|keyword\ \ value]"\fP
  384. XAn option that takes a value.
  385. X.TP
  386. X\f4"[c|keyword\ \ [value]]"\fP
  387. XAn option that takes an optional value.
  388. X.TP
  389. X\f4"[c|keyword\ \ value\ .\^.\^.]"\fP
  390. XAn option that takes \fIone or more\fP values.
  391. X.TP
  392. X\f4"[c|keyword\ \ [value \*(..]]"\fP
  393. XAn option that takes \fIzero or more\fP values.
  394. X.TP
  395. X\f4"value"\fP
  396. XA required positional parameter.
  397. X.TP
  398. X\f4"[value]"\fP
  399. XAn optional positional-parameter.
  400. X.TP
  401. X\f4"[\ \ |keyword]"\fP
  402. XAn option that may be matched by keyword but has no corresponding
  403. Xsingle character option.
  404. X.TP
  405. X\f4"[c|\ \ value]"\fP
  406. XAn option that takes a value but has no corresponding keyword name. 
  407. X.TP
  408. X\f4"[c|keyword]\ \ value"\fP
  409. XA required argument that may be matched either positionally or by keyword.
  410. X.RE
  411. X
  412. X.SS SYNTAX FLAGS
  413. X.RS
  414. XNormally, the value to an option may be supplied either in the same
  415. Xcommand-line token (as in "\fB\-c\fIvalue\fR"), or in a separate token
  416. X(as in "\fB\-c\ \ \fIvalue\fR").
  417. XIf desired, the <\fIsyntax\fP> field may optionally be followed by a colon
  418. X(`:') and one of "\s-1\f4SEPARATE\fP\s+1" or "\s-1\f4STICKY\fP\s+1".
  419. XThe former specifies that the argument value may only occur in a separate
  420. Xcommand-line token, the latter specifies that the argument value may only
  421. Xoccur in the same command-line token.
  422. X.RE
  423. X.\"===================================
  424. X.SH SHELLS
  425. XAt present, \*(NM knows about the following shells:
  426. X.RS
  427. X.IP \fIsh\fP  6
  428. XThe Bourne Shell. This shell is the standard unix shell
  429. X(designed and written by Stephen R. Bourne).
  430. X.IP \fIcsh\fP  6
  431. XThe C Shell. Bill Joy's answer to \fIsh\fP using C-like syntax.
  432. X.IP \fIksh\fP  6
  433. XThe Korn shell. David G. Korn's shell combining all the "best" features
  434. Xof \fIsh\fP and \fIcsh\fP in a "clean" fashion.
  435. X.IP \fIbash\fP  6
  436. XThe Bourne Again Shell.  The Free Software Foundation's answer to \fIksh\fP.
  437. X.IP \fIzsh\fP  6
  438. XThe Z Shell.  Paul Falstad's creation combining all the "best" features
  439. Xof \fIksh\fP and \fIcsh\fP plus some stuff of his own.
  440. X.IP \fIrc\fP  6
  441. XThe Plan 9 Unix shell designed by Tom Duff.  A public domain implementation
  442. X(with some enhancements) has been released by Byron Rakitzis.
  443. X.IP \fIperl\fP  6
  444. XLarry Wall's practical extraction and report-generation language. \fIPerl\fP is 
  445. Xnot a "shell" in the same sense as the others but it is a (powerful) language
  446. Xin which Unix scripts may be written.
  447. X.IP \fItcl\fP 6
  448. XJohn K. Ousterhout's Tool Command Language.  Karl Lehenbauer and friends have
  449. Xdeveloped a \fItcl\fP shell based on Ousterhout's command language.
  450. X.RE
  451. X
  452. XIn addition, \fIash\fP is considered by \*(NM to be equivalent to
  453. X\fIsh\fP; and \fItcsh\fP and \fIitcsh\fP are considered to be equivalent to
  454. X\fIcsh\fP.
  455. X
  456. XFor each supported shell, \*(NM will output a combination of
  457. Xshell-variable and/or shell-array settings that correspond to the
  458. Xarguments that were supplied on the command-line.  In addition, if
  459. Xan argument that takes an optional value was given on the command-line
  460. Xbut \s-1NO\s+1 value was supplied, then the shell-variable named
  461. X\fIname\f4_FLAG\fR is assigned the value \s-1TRUE\s+1 (where \fIname\fP
  462. Xwas the name specified in the <\fIarg-name\fP> field of the corresponding
  463. Xargument declaration). If desired, a suffix other than \f4_FLAG\fP may be
  464. Xused by specifying the \fB\-suffix\fP option.
  465. X
  466. XAny desired initial values for variables from the argument declaration
  467. Xstring should be assigned \s-1BEFORE\s+1 invoking \*(NM.
  468. X\*(NM will \s-1NOT\s+1 output variable settings for any arguments
  469. Xthat were \s-1NOT\s+1 supplied on the command-line. The only exception to
  470. Xthis is when a positional argument that corresponds to the positional
  471. Xparameters of the shell-script is \s-1NOT\s+1 supplied on the command-line;
  472. XIn this particular case, the positional parameters of the shell-script are
  473. Xunset (set to an empty list).
  474. X
  475. XThe exact syntax used to set variables and arrays for the corresponding
  476. Xshells is the subject of the next several subsections.
  477. X
  478. X.\"-----------------------------------
  479. X.SS BOURNE SHELL
  480. X.RS
  481. XFor the Bourne shell, shell variables are assigned using the following syntax:
  482. X
  483. X.RS
  484. X.ft 4
  485. Xname='value';
  486. X.ft R
  487. X.RE
  488. X
  489. XShell arrays are assigned using the following syntax:
  490. X
  491. X.XS
  492. Xname='value1 value2 \*(..';
  493. X.XE
  494. X
  495. XIf the \fB\-arrays\fP option was specified then the following syntax is
  496. Xused to set arrays:
  497. X
  498. X.XS
  499. Xname_count=3;
  500. Xname1='value1';
  501. Xname2='value2';
  502. Xname3='value3';
  503. X.XE
  504. X
  505. XIf the <\fIarg-name\fP> field of an argument is one of "\-", "\*(--",
  506. X"*", or "@" then the argument corresponds to the positional parameters
  507. Xof the shell-script and the following syntax is used to set its value(s):
  508. X
  509. X.XS
  510. Xset \*(-- 'value1' 'value2' \*(.. ;
  511. X.XE
  512. X
  513. X.RE
  514. X.\"-----------------------------------
  515. X.SS KORN SHELL
  516. X.RS
  517. XFor the Korn shell, shell variables are assigned using the following syntax:
  518. X
  519. X.RS
  520. X.ft 4
  521. Xname='value';
  522. X.ft R
  523. X.RE
  524. X
  525. XShell arrays are assigned using the following syntax:
  526. X
  527. X.XS
  528. Xset \-A name 'value1' 'value2' \*(.. ;
  529. X.XE
  530. X
  531. XIf the \fB\-arrays\fP option was specified then the following syntax is
  532. Xused to set arrays:
  533. X
  534. X.XS
  535. Xset +A name 'value1' 'value2' \*(.. ;
  536. X.XE
  537. X
  538. XIf the <\fIarg-name\fP> field of an argument is one of "\-", "\*(--",
  539. X"*", or "@" then the argument corresponds to the positional parameters
  540. Xof the shell-script and the following syntax is used to set its value(s):
  541. X
  542. X.XS
  543. Xset \*(-- 'value1' 'value2' \*(.. ;
  544. X.XE
  545. X
  546. X.RE
  547. X.\"-----------------------------------
  548. X.SS C SHELL
  549. X.RS
  550. XFor the C shell, shell variables are assigned using the following syntax:
  551. X
  552. X.RS
  553. X.ft 4
  554. Xset name='value';
  555. X.ft R
  556. X.RE
  557. X
  558. XShell arrays are assigned using the following syntax:
  559. X
  560. X.XS
  561. Xset name=('value1' 'value2' \*(..) ;
  562. X.XE
  563. X
  564. XIf the <\fIarg-name\fP> field of an argument is "\f4argv\fP"
  565. Xthen the argument corresponds to the positional parameters
  566. Xof the script and may be unset.
  567. X
  568. X.RE
  569. X.\"-----------------------------------
  570. X.SS BOURNE AGAIN SHELL
  571. X.RS
  572. XAt present, the Bourne Again shell is treated exactly the same as the
  573. XBourne Shell.
  574. X.RE
  575. X.\"-----------------------------------
  576. X.SS Z SHELL
  577. X.RS
  578. XFor the Z shell, shell variables are assigned using the following syntax:
  579. X
  580. X.RS
  581. X.ft 4
  582. Xname='value';
  583. X.ft R
  584. X.RE
  585. X
  586. XShell arrays are assigned using the following syntax:
  587. X
  588. X.XS
  589. Xname=('value1' 'value2' \*(..) ;
  590. X.XE
  591. X
  592. XIf the <\fIarg-name\fP> field of an argument is one of "\-", "\*(--",
  593. X"*", "@", or "\f4argv\fP" then the argument corresponds to the positional
  594. Xparameters of the shell-script and the following syntax is used to set its
  595. Xvalue(s):
  596. X
  597. X.XS
  598. Xargv=('value1' 'value2' \*(..) ;
  599. X.XE
  600. X.RE
  601. X.\"-----------------------------------
  602. X.SS PLAN 9 SHELL
  603. X.RS
  604. XFor \fIrc\fP (the Plan 9 Shell), shell variables are assigned using the
  605. Xfollowing syntax:
  606. X
  607. X.RS
  608. X.ft 4
  609. Xname='value';
  610. X.ft R
  611. X.RE
  612. X
  613. XShell arrays are assigned using the following syntax:
  614. X
  615. X.XS
  616. Xname=('value1' 'value2' \*(..) ;
  617. X.XE
  618. X
  619. XIf the <\fIarg-name\fP> field of an argument is "\f4*\fP"
  620. Xthen the argument corresponds to the positional parameters
  621. Xof the script and may be unset.
  622. X
  623. X.RE
  624. X.\"-----------------------------------
  625. X.SS PERL
  626. X.RS
  627. XFor Perl, variables are assigned using the following syntax:
  628. X
  629. X.RS
  630. X.ft 4
  631. X$name = 'value';
  632. X.ft R
  633. X.RE
  634. X
  635. Xarrays are assigned using the following syntax:
  636. X
  637. X.XS
  638. X@name = ('value1', 'value2', \*(..) ;
  639. X.XE
  640. X
  641. XIf the <\fIarg-name\fP> field of an argument is "\f4ARGV\fP"
  642. Xthen the argument corresponds to the positional parameters
  643. Xof the script and may be unset.
  644. X
  645. XA \fIperl\fP interface to \*(NM should have been installed in your
  646. Xstandard perl library when \*(NM was installed.  It may be used
  647. Xby saying:
  648. X
  649. X.XS
  650. Xrequire "cmdparse.pl" ;
  651. X.XE
  652. X
  653. Xsomewhere in your perl-script. This will give you access to a perl function
  654. Xnamed "\*(NM" which may be used as follows:
  655. X
  656. X.XS
  657. Xeval &cmdparse("\-decls=$ARGDECLS", $0, @ARGV);
  658. X.XE
  659. X
  660. XWhere \f4$ARGDECLS\fP is a variable containing a string of command-line
  661. Xargument declarations for \*(NM(1). The arguments to the perl function
  662. Xshould be a vector of arguments to pass to \*(NM(1) on the command-line.
  663. XThe file \f4cmdparse.pl\fP in your \fIperl\fP library directory contains
  664. Xthe implementation and documentation for the \fIperl\fP interface to \*(NM.
  665. X
  666. XIf a syntax error occurred on the command-line and \fB\-noabort\fP was
  667. Xnot specified then the \*(NM function will terminate the execution of the
  668. X\fIperl\fP script and will \s-1NOT\s+1 return to the caller.
  669. X
  670. X.RE
  671. X.\"-----------------------------------
  672. X.SS TCL
  673. X.RS
  674. XFor Tcl, variables are assigned using the following syntax:
  675. X
  676. X.RS
  677. X.ft 4
  678. Xset name "value";
  679. X.ft R
  680. X.RE
  681. X
  682. Xarrays are assigned using the following syntax:
  683. X
  684. X.XS
  685. Xset name [ list "value1" "value2" \*(.. ];
  686. X.XE
  687. X
  688. XIf the <\fIarg-name\fP> field of an argument is "\f4argv\fP" or
  689. X"\f4args\fP" then the argument corresponds to the positional
  690. Xparameters of the script and may be unset.
  691. X
  692. XA \fItcl\fP interface to \*(NM should have been installed in your
  693. Xstandard \fItcl\fP library when \*(NM was installed.  It may be used
  694. Xby saying:
  695. X
  696. X.XS
  697. Xload "cmdparse.tcl" ;
  698. X.XE
  699. X
  700. Xsomewhere in your \fItcl\fP script. This will give you access to a \fItcl\fP
  701. Xprocedure named "\*(NM" which may be used as follows:
  702. X
  703. X.XS
  704. Xeval [ cmdparse \-decls=$argDecls $scriptName $argv ];
  705. X.XE
  706. X
  707. XWhere \f4$argDecls\fP is a variable containing a string of command-line
  708. Xargument declarations for \*(NM(1).
  709. X
  710. XThe arguments to the \fItcl\fP \*(NM procedure are exactly the same as for
  711. X\*(NM(1).
  712. XThe file \f4cmdparse.tcl\fP in your \fItcl\fP library directory contains
  713. Xthe implementation and documentation for the \fItcl\fP interface to \*(NM.
  714. X
  715. XIf a syntax error occurred on the command-line and \fB\-noabort\fP
  716. Xwas not specified then the \*(NM procedure will terminate the execution of the
  717. X\fItcl\fP script and will \s-1NOT\s+1 return to the caller.
  718. X
  719. X
  720. X.IP "\fBNote:\fP" 3
  721. XThe \fItcl\fP \*(NM procedure will only work with \fItcl\fP scripts that use
  722. Xa version of the \fItcl\fP shell that contains the \f4execl\fP command!
  723. X
  724. X.RE
  725. X.\"===================================
  726. X.so environ.man
  727. X.\"===================================
  728. X.SH FILES
  729. X.IP \f4\*b/cmdparse\fP
  730. XThe executable file for \*(NM(1).
  731. X.IP \f4\*p/cmdparse.pl\fP
  732. XThe \fIperl\fP interface (including documentation) to \*(NM(1).
  733. X.IP \f4\*t/cmdparse.tcl\fP
  734. XThe \fItcl\fP interface (including documentation) to \*(NM(1).
  735. X.\"===================================
  736. X.SH SEE ALSO
  737. X\f4CmdLine\fP(3\*(C+), \f4cmdargs\fP(3\*(C+)
  738. X.\"===================================
  739. X.so caveats.man
  740. X.\"===================================
  741. X.so bugs.man
  742. X.\"===================================
  743. X.SH AUTHOR
  744. XBrad Appleton, Harris Computer Systems, <\f4brad@ssd.csd.harris.com\fP>.
  745. END_OF_FILE
  746. if test 21692 -ne `wc -c <'doc/cmdparse.man1'`; then
  747.     echo shar: \"'doc/cmdparse.man1'\" unpacked with wrong size!
  748. fi
  749. # end of 'doc/cmdparse.man1'
  750. fi
  751. if test -f 'src/lib/cmdargs.c' -a "${1}" != "-c" ; then 
  752.   echo shar: Will not clobber existing file \"'src/lib/cmdargs.c'\"
  753. else
  754. echo shar: Extracting \"'src/lib/cmdargs.c'\" \(16718 characters\)
  755. sed "s/^X//" >'src/lib/cmdargs.c' <<'END_OF_FILE'
  756. X//------------------------------------------------------------------------
  757. X// ^FILE: cmdargs.c - implement the various predefined CmdArg subclasses
  758. X//
  759. X// ^DESCRIPTION:
  760. X//    This file implements the CmdArg derived classes that are declared
  761. X//    in <cmdargs.h>
  762. X//
  763. X// ^HISTORY:
  764. X//    03/25/92    Brad Appleton    <brad@ssd.csd.harris.com>    Created
  765. X//-^^---------------------------------------------------------------------
  766. X
  767. X#include <stdlib.h>
  768. X#include <iostream.h>
  769. X#include <string.h>
  770. X#include <ctype.h>
  771. X
  772. X#include "cmdargs.h"
  773. X#include "exits.h"
  774. X#include "fifolist.h"
  775. X
  776. X   // return values for operator()
  777. Xenum { SUCCESS = 0, FAILURE = -1 } ;
  778. X
  779. X
  780. X//-----------------------------------------------------------------------------
  781. X// ^FUNCTION: compile, operator() - handle an argument from the command-line
  782. X//
  783. X// ^SYNOPSIS:
  784. X//    int  operator()(arg, cmd);
  785. X//    int  compile(arg, cmd, value);
  786. X//    int  compile(arg, cmd, value, default_value);
  787. X//
  788. X// ^PARAMETERS:
  789. X//    const char * & arg;
  790. X//    -- the prospective value for this command argument.
  791. X//       upon returning this value should be updated to point to the first
  792. X//       character of "arg" that was NOT used as part of the value for this
  793. X//       argument (set "arg" to NULL if all of it was used).
  794. X//
  795. X//    CmdLine & cmd;
  796. X//    -- the command that matched this argument on its command-line
  797. X//
  798. X//    <Type> & value;
  799. X//    -- The internal value (of some appropriate type) that is "managed"
  800. X//       by this command argument.
  801. X//
  802. X//    unsigned  default_value;
  803. X//    -- What to assign to "value" if "arg" is NOT a value for this command
  804. X//       argument.
  805. X//
  806. X// ^DESCRIPTION:
  807. X//    These member functions are responsible for taking whatever action
  808. X//    is appropriate when its corresponding command argument is matched
  809. X//    on the command-line.  For argument-types that simply "compile"
  810. X//    their argument into some kind of internal value, "compile()" does
  811. X//    all the work and operator() merely calls compile() with the proper
  812. X//    value as a reference parameter.
  813. X//
  814. X// ^REQUIREMENTS:
  815. X//    The "arg_flags" data member of this command-argument must have been
  816. X//    set appropriately (by "cmd") to indicate to us exactly how "arg" was
  817. X//    specified on the command-line for this (and only this) occurrence of
  818. X//    "arg".
  819. X//
  820. X// ^SIDE-EFFECTS:
  821. X//    - If (cmd.flags() & QUIET) is NOT TRUE and FAILURE is to be returned,
  822. X//      then error messages should be printed using cmd.error().
  823. X//
  824. X//    - arg is modified to be NULL of to point to the unused portion of itself.
  825. X//      
  826. X//    - If (cmd.flags() & TEMP) is TRUE and we need the value of "arg"
  827. X//      to stick around, then storage is allocated in order to make
  828. X//      a copy of "arg" (and the command-argument is responsible for
  829. X//      de-allocating this storage).
  830. X//
  831. X// ^RETURN-VALUE:
  832. X//    FAILURE (non-zero)  If something went wrong when performing the
  833. X//                        desired actions for this command-argument.
  834. X//                        A common problem would be that "arg" is
  835. X//                        syntactically incorrect.
  836. X//
  837. X//    SUCCESS (zero)  If "arg" is NULL and/or we were able to succesfully
  838. X//                    perform all desired actions for this command argument.
  839. X//-^^--------------------------------------------------------------------------
  840. X
  841. X
  842. X//-------------------------------------------------------------- Dummy Argument
  843. X
  844. XCmdArgDummy::~CmdArgDummy(void)  {}
  845. X
  846. Xint
  847. XCmdArgDummy::is_dummy(void)  { return  1; }
  848. X
  849. X   // For a CmdArgDummy - operator() is a No-OP and should NEVER
  850. X   // be called.
  851. X   //
  852. Xint
  853. XCmdArgDummy::operator()(const char * & , CmdLine & )
  854. X{
  855. X   return  SUCCESS;
  856. X}
  857. X
  858. X//-------------------------------------------------------------- Usage Argument
  859. X
  860. XCmdArgUsage::~CmdArgUsage(void)  {}
  861. X
  862. X   // Just need to call cmd.usage and exit.
  863. X   //
  864. Xint
  865. XCmdArgUsage::operator()(const char * & , CmdLine & cmd)
  866. X{
  867. X   cmd.usage(cmd.error(CmdLine::NOPRINT), CmdLine::VERBOSE_USAGE);
  868. X   ::exit(e_USAGE);
  869. X   return  SUCCESS;  // get the compiler to shut up about NO return value!
  870. X}
  871. X
  872. X//----------------------------------------------------------- Integer Arguments
  873. X
  874. XCmdArgIntCompiler::~CmdArgIntCompiler(void)  {}
  875. X
  876. X   // Compile a string into an integer value.
  877. Xint
  878. XCmdArgIntCompiler::compile(const char * & arg, CmdLine & cmd, int & value)
  879. X{
  880. X   const char * ptr = NULL ;
  881. X   long  result = 0 ;
  882. X
  883. X   if (arg == NULL) {
  884. X      return  SUCCESS ;  // no value given - nothing to do
  885. X   } else if (! *arg) {
  886. X      if (! (cmd.flags() & CmdLine::QUIET)) {
  887. X         cmd.error() << "empty integer value specified." << endl ;
  888. X      }
  889. X      return  FAILURE ;
  890. X   }
  891. X
  892. X   // compile the string into an integer
  893. X   result = ::strtol(arg, (char **) &ptr, 0);  // watch out for -c0xa vs -axc0!
  894. X   if (ptr == arg) {
  895. X      // do we have a valid integer?
  896. X      if (! (cmd.flags() & CmdLine::QUIET)) {
  897. X         cmd.error() << "invalid integer value \"" << arg << "\"." << endl ;
  898. X      }
  899. X      return  FAILURE ;
  900. X   }
  901. X   value = (int) result;
  902. X   arg = ptr;
  903. X
  904. X   return  SUCCESS ;
  905. X}
  906. X
  907. X
  908. XCmdArgInt::~CmdArgInt(void)  {}
  909. X
  910. Xint
  911. XCmdArgInt::operator()(const char * & arg, CmdLine & cmd)
  912. X{
  913. X   return  compile(arg, cmd, val);
  914. X}
  915. X
  916. X
  917. Xostream &
  918. Xoperator<<(ostream & os, const CmdArgInt & int_arg)
  919. X{
  920. X   return  (os << (int) int_arg) ;
  921. X}
  922. X
  923. X//---------------------------------------------------- Floating-point Arguments
  924. X
  925. XCmdArgFloatCompiler::~CmdArgFloatCompiler(void)  {}
  926. X
  927. X   // Compile a string into a floating-point value.
  928. Xint
  929. XCmdArgFloatCompiler::compile(const char * & arg, CmdLine & cmd, float & value)
  930. X{
  931. X   const char * ptr = NULL ;
  932. X   double  result = 0 ;
  933. X
  934. X   if (arg == NULL) {
  935. X      return  SUCCESS ;  // no value given -- nothing to do
  936. X   } else if (! *arg) {
  937. X      if (! (cmd.flags() & CmdLine::QUIET)) {
  938. X         cmd.error() << "empty floating-point value specified." << endl ;
  939. X      }
  940. X      return  FAILURE ;
  941. X   }
  942. X
  943. X   result = ::strtod(arg, (char **) &ptr);  // compile the string into a float
  944. X   if (ptr == arg) {
  945. X      // do we have a valid float?
  946. X      if (! (cmd.flags() & CmdLine::QUIET)) {
  947. X         cmd.error() << "invalid floating-point value \"" << arg << "\"."
  948. X                     << endl ;
  949. X      }
  950. X      return  FAILURE ;
  951. X   }
  952. X   value = (float) result;
  953. X   arg = ptr;
  954. X
  955. X   return  SUCCESS ;
  956. X}
  957. X
  958. X
  959. XCmdArgFloat::~CmdArgFloat(void)  {}
  960. X
  961. Xint
  962. XCmdArgFloat::operator()(const char * & arg, CmdLine & cmd)
  963. X{
  964. X   return  compile(arg, cmd, val);
  965. X}
  966. X
  967. X
  968. Xostream &
  969. Xoperator<<(ostream & os, const CmdArgFloat & float_arg)
  970. X{
  971. X   return  (os << (float) float_arg) ;
  972. X}
  973. X
  974. X//--------------------------------------------------------- Character Argumrnts
  975. X
  976. XCmdArgCharCompiler::~CmdArgCharCompiler(void)  {}
  977. X
  978. Xint
  979. XCmdArgCharCompiler::compile(const char * & arg, CmdLine & cmd, char & value)
  980. X{
  981. X   if (arg == NULL) {
  982. X      return  SUCCESS ;  // no value given - nothing to do
  983. X   }
  984. X
  985. X   // If "arg" contains more than 1 character, then the other characters
  986. X   // are either extraneous, or they are options (bundled together).
  987. X   //
  988. X   if (*arg  &&  *(arg+1)  &&
  989. X        ((! (flags() & CmdArg::OPTION)) || (flags() & CmdArg::VALSEP)))
  990. X   {
  991. X      if (! (cmd.flags() & CmdLine::QUIET)) {
  992. X         cmd.error() << "invalid character value \"" << arg << "\"." << endl ;
  993. X      }
  994. X      return  FAILURE ;
  995. X   }
  996. X
  997. X   value = *arg;
  998. X   if (*arg) {
  999. X      ++arg;
  1000. X   } else {
  1001. X      arg = NULL;
  1002. X   }
  1003. X
  1004. X   return  SUCCESS ;
  1005. X}
  1006. X
  1007. X
  1008. XCmdArgChar::~CmdArgChar(void)  {}
  1009. X
  1010. Xint
  1011. XCmdArgChar::operator()(const char * & arg, CmdLine & cmd)
  1012. X{
  1013. X   return  compile(arg, cmd, val);
  1014. X}
  1015. X
  1016. Xostream &
  1017. Xoperator<<(ostream & os, const CmdArgChar & char_arg)
  1018. X{
  1019. X   return  (os << (char) char_arg) ;
  1020. X}
  1021. X
  1022. X//------------------------------------------------------------ String Arguments
  1023. X
  1024. Xtypedef  CmdArgStrCompiler::string  CmdArgString ;
  1025. X
  1026. XCmdArgString::~string(void)
  1027. X{
  1028. X   if (is_alloc)  delete [] (char *)str;
  1029. X}
  1030. X
  1031. X   // Copy a string (allocating storage if necessary)
  1032. Xvoid
  1033. XCmdArgString::copy(unsigned  is_temporary, const char * s)
  1034. X{
  1035. X   if (is_alloc)  delete  (char *)str;
  1036. X   is_alloc = (is_temporary) ? 1 : 0;
  1037. X   str = s;
  1038. X   if (is_alloc && s) {
  1039. X      char * new_s = new char[::strlen(s) + 1] ;
  1040. X      (void) ::strcpy(new_s, s);
  1041. X      str = new_s;
  1042. X   }
  1043. X}
  1044. X
  1045. X
  1046. XCmdArgStrCompiler::~CmdArgStrCompiler(void)  {}
  1047. X
  1048. Xint
  1049. XCmdArgStrCompiler::compile(const char  * & arg,
  1050. X                           CmdLine       & cmd,
  1051. X                           CmdArgString  & value)
  1052. X{
  1053. X   if (arg == NULL) {
  1054. X      return  SUCCESS;  // no value given -- nothing to do
  1055. X   }
  1056. X
  1057. X   value.copy((cmd.flags() & CmdLine::TEMP), arg);
  1058. X   arg = NULL;
  1059. X
  1060. X   return  SUCCESS;
  1061. X}
  1062. X
  1063. X
  1064. XCmdArgStr::~CmdArgStr(void)  {}
  1065. X
  1066. Xint
  1067. XCmdArgStr::operator()(const char * & arg, CmdLine & cmd)
  1068. X{
  1069. X   return  compile(arg, cmd, val);
  1070. X}
  1071. X
  1072. Xostream &
  1073. Xoperator<<(ostream & os, const CmdArgStrCompiler::string & str)
  1074. X{
  1075. X   return  (os << str.str) ;
  1076. X}
  1077. X
  1078. Xostream &
  1079. Xoperator<<(ostream & os, const CmdArgStr & str_arg)
  1080. X{
  1081. X   return  (os << (const char *) str_arg) ;
  1082. X}
  1083. X
  1084. X//-------------------------------------------------------------- List Arguments
  1085. X
  1086. X          //------------------- Integer List -------------------
  1087. X
  1088. XDECLARE_FIFO_LIST(IntList, int);
  1089. X
  1090. Xstruct CmdArgIntListPrivate {
  1091. X   IntList       list;
  1092. X   IntListArray  array;
  1093. X
  1094. X   CmdArgIntListPrivate(void);
  1095. X} ;
  1096. X
  1097. X
  1098. XCmdArgIntListPrivate::CmdArgIntListPrivate(void)
  1099. X   : array(list)
  1100. X{
  1101. X   list.self_cleaning(1);
  1102. X}
  1103. X
  1104. X   // Compile the argument into an integer and append it to the list
  1105. Xint
  1106. XCmdArgIntList::operator()(const char * & arg, CmdLine & cmd)
  1107. X{
  1108. X   int  value;
  1109. X   const char * save_arg = arg;
  1110. X   int  rc = compile(arg, cmd, value);
  1111. X   if (save_arg && (rc == SUCCESS)) {
  1112. X      if (val == NULL)  val = new CmdArgIntListPrivate;
  1113. X      int * new_value = new int;
  1114. X      *new_value = value;
  1115. X      val->list.add(new_value);
  1116. X   }
  1117. X   return  rc;
  1118. X}
  1119. X
  1120. Xunsigned
  1121. XCmdArgIntList::count(void) const
  1122. X{
  1123. X   return  (val) ? val->list.count() : 0 ;
  1124. X}
  1125. X
  1126. Xint &
  1127. XCmdArgIntList::operator[](unsigned  index)
  1128. X{
  1129. X   return  val->array[index];
  1130. X}
  1131. X
  1132. XCmdArgIntList::~CmdArgIntList(void) {}
  1133. X
  1134. X
  1135. X          //------------------- Float List -------------------
  1136. X
  1137. X
  1138. XDECLARE_FIFO_LIST(FloatList, float);
  1139. X
  1140. Xstruct CmdArgFloatListPrivate {
  1141. X   FloatList       list;
  1142. X   FloatListArray  array;
  1143. X
  1144. X   CmdArgFloatListPrivate(void);
  1145. X} ;
  1146. X
  1147. XCmdArgFloatListPrivate::CmdArgFloatListPrivate(void)
  1148. X   : array(list)
  1149. X{
  1150. X   list.self_cleaning(1);
  1151. X}
  1152. X
  1153. X
  1154. X   // Compile the argument into a float and append it to the list
  1155. Xint
  1156. XCmdArgFloatList::operator()(const char * & arg, CmdLine & cmd)
  1157. X{
  1158. X   float  value;
  1159. X   const char * save_arg = arg;
  1160. X   int  rc = compile(arg, cmd, value);
  1161. X   if (save_arg && (rc == SUCCESS)) {
  1162. X      if (val == NULL)  val = new CmdArgFloatListPrivate;
  1163. X      float * new_value = new float;
  1164. X      *new_value = value;
  1165. X      val->list.add(new_value);
  1166. X   }
  1167. X   return  rc;
  1168. X}
  1169. X
  1170. Xunsigned
  1171. XCmdArgFloatList::count(void) const
  1172. X{
  1173. X   return  (val) ? val->list.count() : 0 ;
  1174. X}
  1175. X
  1176. Xfloat &
  1177. XCmdArgFloatList::operator[](unsigned  index)
  1178. X{
  1179. X   return  val->array[index];
  1180. X}
  1181. X
  1182. XCmdArgFloatList::~CmdArgFloatList(void) {}
  1183. X
  1184. X          //------------------- String List -------------------
  1185. X
  1186. XDECLARE_FIFO_LIST(StringList, CmdArgString);
  1187. X
  1188. Xstruct CmdArgStrListPrivate {
  1189. X   StringList       list;
  1190. X   StringListArray  array;
  1191. X
  1192. X   CmdArgStrListPrivate(void);
  1193. X} ;
  1194. X
  1195. XCmdArgStrListPrivate::CmdArgStrListPrivate(void)
  1196. X   : array(list)
  1197. X{
  1198. X   list.self_cleaning(1);
  1199. X}
  1200. X
  1201. Xint
  1202. XCmdArgStrList::operator()(const char * & arg, CmdLine & cmd)
  1203. X{
  1204. X   CmdArgString * value = new CmdArgString ;
  1205. X   const char * save_arg = arg;
  1206. X   int  rc = compile(arg, cmd, *value);
  1207. X   if (save_arg && (rc == SUCCESS)) {
  1208. X      if (val == NULL)  val = new CmdArgStrListPrivate;
  1209. X      val->list.add(value);
  1210. X   } else {
  1211. X      delete  value;
  1212. X   }
  1213. X   return  rc;
  1214. X}
  1215. X
  1216. Xunsigned
  1217. XCmdArgStrList::count(void) const
  1218. X{
  1219. X   return  (val) ? val->list.count() : 0 ;
  1220. X}
  1221. X
  1222. XCmdArgString &
  1223. XCmdArgStrList::operator[](unsigned  index)
  1224. X{
  1225. X   return  val->array[index];
  1226. X}
  1227. X
  1228. XCmdArgStrList::~CmdArgStrList(void) {}
  1229. X
  1230. X//----------------------------------------------------------- Boolean Arguments
  1231. X
  1232. XCmdArgBoolCompiler::~CmdArgBoolCompiler(void)  {}
  1233. X
  1234. Xint
  1235. XCmdArgBoolCompiler::compile(const char  * & arg,
  1236. X                            CmdLine       & cmd,
  1237. X                            unsigned      & value,
  1238. X                            unsigned        default_value)
  1239. X{
  1240. X   if (arg == NULL) {
  1241. X         // if no argument was given use the default
  1242. X      value = default_value ;
  1243. X   } else {
  1244. X      char ch = *arg;
  1245. X      const char * kwd = arg++;
  1246. X
  1247. X         // Map the argument to the corresponding value. We will accept
  1248. X         // the following (case insensitive):
  1249. X         //
  1250. X         //     "+", "1", "ON", or "YES"  means set the value
  1251. X         //     "-", "0", "OFF", or "NO"  means clear the value
  1252. X         //     "~", "^", or "!" means toggle the value
  1253. X         //
  1254. X         // Anything else is considered to be an argument that is NOT
  1255. X         // meant for us but for some other argument so we just use the
  1256. X         // default value that was supplied and return SUCCESS.
  1257. X         //
  1258. X      if (isupper(ch))  ch = tolower(ch);
  1259. X      switch(ch) {
  1260. X         case '1' :
  1261. X         case '+' : value = 1 ; break;
  1262. X
  1263. X         case '0' :
  1264. X         case '-' : value = 0 ; break;
  1265. X
  1266. X         case '~' :
  1267. X         case '^' :
  1268. X         case '!' : value = (! value) ; break;
  1269. X
  1270. X         default:
  1271. X            if (flags() & CmdArg::KEYWORD) {
  1272. X               char ch2 = *arg;
  1273. X               arg = NULL;
  1274. X               if (cmd.strmatch(kwd, "yes") != CmdLine::str_NONE) {
  1275. X                  value = 1 ;
  1276. X                  return  SUCCESS ;
  1277. X               } else if (cmd.strmatch(kwd, "no") != CmdLine::str_NONE) {
  1278. X                  value = 0 ;
  1279. X                  return  SUCCESS ;
  1280. X               } else if (cmd.strmatch(kwd, "true") != CmdLine::str_NONE) {
  1281. X                  value = 1 ;
  1282. X                  return  SUCCESS ;
  1283. X               } else if (cmd.strmatch(kwd, "false") != CmdLine::str_NONE) {
  1284. X                  value = 0 ;
  1285. X                  return  SUCCESS ;
  1286. X               } else if ((ch == 'o') && (! ch2)) {
  1287. X                  // ambiguous - could be "ON" or "OFF"
  1288. X                  if (! (cmd.flags() & CmdLine::QUIET)) {
  1289. X                     cmd.error() << "ambiguous boolean value \"" << kwd
  1290. X                                 << "\"." << endl ;
  1291. X                  }
  1292. X                  return  FAILURE ;
  1293. X               } else if (cmd.strmatch(kwd, "on") != CmdLine::str_NONE) {
  1294. X                  value = 1 ;
  1295. X                  return  SUCCESS ;
  1296. X               } else if (cmd.strmatch(kwd, "off") != CmdLine::str_NONE) {
  1297. X                  value = 0 ;
  1298. X                  return  SUCCESS ;
  1299. X               } else {
  1300. X                  // unknown
  1301. X                  if (! (cmd.flags() & CmdLine::QUIET)) {
  1302. X                     cmd.error() << "unknown boolean value \"" << kwd
  1303. X                                 << "\"." << endl ;
  1304. X                  }
  1305. X                  return  FAILURE ;
  1306. X               }
  1307. X            } //if keyword
  1308. X            arg = kwd;  // no characters used!
  1309. X            value = default_value ;
  1310. X            break;
  1311. X      } //switch
  1312. X   } //else
  1313. X
  1314. X   return  SUCCESS ;
  1315. X}
  1316. X
  1317. Xostream &
  1318. Xoperator<<(ostream & os, const CmdArgBool & bool_arg)
  1319. X{
  1320. X   return  (os << ((int)bool_arg)) ;
  1321. X}
  1322. X
  1323. X//------------------------------------------------------------------ CmdArgBool
  1324. X
  1325. XCmdArgBool::~CmdArgBool(void)  {}
  1326. X
  1327. Xint
  1328. XCmdArgBool::operator()(const char * & arg, CmdLine & cmd)
  1329. X{
  1330. X   unsigned  value = val;
  1331. X   int  rc = compile(arg, cmd, value, 1);
  1332. X   val = value;
  1333. X   return  rc;
  1334. X}
  1335. X
  1336. X//----------------------------------------------------------------- CmdArgClear
  1337. X
  1338. XCmdArgClear::~CmdArgClear(void)  {}
  1339. X
  1340. Xint
  1341. XCmdArgClear::operator()(const char * & arg, CmdLine & cmd)
  1342. X{
  1343. X   unsigned  value = val;
  1344. X   int  rc = compile(arg, cmd, value, 0);
  1345. X   val = value;
  1346. X   return  rc;
  1347. X}
  1348. X
  1349. X//---------------------------------------------------------------- CmdArgToggle
  1350. X
  1351. XCmdArgToggle::~CmdArgToggle(void)  {}
  1352. X
  1353. Xint
  1354. XCmdArgToggle::operator()(const char * & arg, CmdLine & cmd)
  1355. X{
  1356. X   unsigned  value = val;
  1357. X   int  rc = compile(arg, cmd, value, (! value));
  1358. X   val = value;
  1359. X   return  rc;
  1360. X}
  1361. X
  1362. X//--------------------------------------------------------------- CmdArgBoolRef
  1363. X
  1364. XCmdArgBoolRef::~CmdArgBoolRef(void)  {}
  1365. X
  1366. Xint
  1367. XCmdArgBoolRef::operator()(const char * & arg, CmdLine & cmd)
  1368. X{
  1369. X   unsigned  val = ref;
  1370. X   int rc = ref.compile(arg, cmd, val, 1);
  1371. X   ref = val;
  1372. X   return  rc;
  1373. X}
  1374. X
  1375. X//-------------------------------------------------------------- CmdArgClearRef
  1376. X
  1377. XCmdArgClearRef::~CmdArgClearRef(void)  {}
  1378. X
  1379. Xint
  1380. XCmdArgClearRef::operator()(const char * & arg, CmdLine & cmd)
  1381. X{
  1382. X   unsigned  val = ref;
  1383. X   int rc = ref.compile(arg, cmd, val, 0);
  1384. X   ref = val;
  1385. X   return  rc;
  1386. X}
  1387. X
  1388. X//------------------------------------------------------------- CmdArgToggleRef
  1389. X
  1390. XCmdArgToggleRef::~CmdArgToggleRef(void)  {}
  1391. X
  1392. Xint
  1393. XCmdArgToggleRef::operator()(const char * & arg, CmdLine & cmd)
  1394. X{
  1395. X   unsigned  val = ref;
  1396. X   int rc = ref.compile(arg, cmd, val, (! val));
  1397. X   ref = val;
  1398. X   return  rc;
  1399. X}
  1400. X
  1401. END_OF_FILE
  1402. if test 16718 -ne `wc -c <'src/lib/cmdargs.c'`; then
  1403.     echo shar: \"'src/lib/cmdargs.c'\" unpacked with wrong size!
  1404. fi
  1405. # end of 'src/lib/cmdargs.c'
  1406. fi
  1407. if test -f 'src/lib/private.c' -a "${1}" != "-c" ; then 
  1408.   echo shar: Will not clobber existing file \"'src/lib/private.c'\"
  1409. else
  1410. echo shar: Extracting \"'src/lib/private.c'\" \(19806 characters\)
  1411. sed "s/^X//" >'src/lib/private.c' <<'END_OF_FILE'
  1412. X//------------------------------------------------------------------------
  1413. X// ^FILE: private.c - private/protected functions used by the CmdLine library
  1414. X//
  1415. X// ^DESCRIPTION:
  1416. X//  This file implements functions that are for the exclusive use of
  1417. X//  the CmdLine library.  The following functions are implemented:
  1418. X//
  1419. X//      ck_need_val()  --  see if we left an argument without a value
  1420. X//      handle_arg()   --  compile the string value of an argument
  1421. X//      syntax()       --  find out the desired syntax for usage messages
  1422. X//      missing_args() --  check for missing required arguments
  1423. X//      opt_match()    --  match an option
  1424. X//      kwd_match()    --  match a keyword
  1425. X//      pos_match()    --  match a positional parameter
  1426. X//
  1427. X// ^HISTORY:
  1428. X//    01/09/92    Brad Appleton    <brad@ssd.csd.harris.com>    Created
  1429. X//-^^---------------------------------------------------------------------
  1430. X
  1431. X#include <iostream.h>
  1432. X#include <strstream.h>
  1433. X#include <fstream.h>
  1434. X#include <stdlib.h>
  1435. X#include <string.h>
  1436. X#include <ctype.h>
  1437. X
  1438. Xextern "C" {
  1439. X  int  isatty(int fd);
  1440. X
  1441. X#ifdef GNU_READLINE
  1442. X# include <readline.h>
  1443. X#endif
  1444. X
  1445. X}
  1446. X
  1447. X#ifndef GNU_READLINE
  1448. X# ifdef unix
  1449. X#  include <malloc.h>
  1450. X# else
  1451. X   extern "C" void * malloc(size_t);
  1452. X   extern "C" void   free(void *);
  1453. X# endif
  1454. X#endif
  1455. X
  1456. X
  1457. X#include "cmdline.h"
  1458. X#include "states.h"
  1459. X#include "arglist.h"
  1460. X
  1461. X
  1462. X// Need a portable version of tolower
  1463. X//
  1464. X//   NOTE:: I would make this inline except that cfront refuses
  1465. X//          to inline it because it is used twice in expressions
  1466. X//
  1467. X#define TO_LOWER(c)  ((isupper(c)) ? tolower(c) : c)
  1468. X
  1469. X#ifdef vms
  1470. X#  define  getenv  getsym
  1471. X   extern  const char * getsym(const char *);
  1472. X#endif
  1473. X
  1474. X//-------
  1475. X// ^FUNCTION: CmdLine::handle_arg - compile the string value of an argument
  1476. X//
  1477. X// ^SYNOPSIS:
  1478. X//    extern int CmdLine::handle_arg(cmdarg, arg);
  1479. X//
  1480. X// ^PARAMETERS:
  1481. X//    CmdArg * cmdarg;
  1482. X//    -- the matched argument whose value is to be "handled"
  1483. X//
  1484. X//    const char * & arg;
  1485. X//    -- the string value for the argument (from the command-line).
  1486. X//       upon exit, this will be NULL (if all of "arg" was used) or will
  1487. X//       point to the first character or "arg" that was not used by the
  1488. X//       argument's "compile" function.
  1489. X//
  1490. X// ^DESCRIPTION:
  1491. X//    After we have matched an argument on the command-line to an argument
  1492. X//    in the "cmd" object, we need to "handle" the value supplied for that
  1493. X//    argument. This entails updating the state of the argument and calling
  1494. X//    its "compile" function as well as updating the state of the command.
  1495. X//
  1496. X// ^REQUIREMENTS:
  1497. X//    None that weren't covered in the PARAMETERS section.
  1498. X//
  1499. X// ^SIDE-EFFECTS:
  1500. X//    - modifies the value pointed to by "arg"
  1501. X//    - prints a message on stderr if "arg" is invalid and QUIET is NOT set.
  1502. X//    - modifies the state of "cmd".
  1503. X//    - modifies the "value" and "flags" of "cmdarg".
  1504. X//
  1505. X// ^RETURN-VALUE:
  1506. X//    The value returned by calling the "compile" function associated
  1507. X//    with the argument "cmdarg".
  1508. X//
  1509. X// ^ALGORITHM:
  1510. X//    - if this is a cmdargUsage argument then print usage and call exit(3C)
  1511. X//    - call the operator() of "cmdarg" and save the result.
  1512. X//    - if the above call returned SUCCESS then set the GIVEN and VALGIVEN
  1513. X//      flags of the argument.
  1514. X//    - update the parse_state of "cmd" if we were waiting for this value.
  1515. X//    - if "cmdarg" corresponds to a LIST then set things up so that succeeding
  1516. X//      arguments will be values for this "cmdarg"'s list.
  1517. X//-^^----
  1518. Xint
  1519. XCmdLine::handle_arg(CmdArg * cmdarg, const char * & arg)
  1520. X{
  1521. X   int  bad_val ;
  1522. X
  1523. X   // call the argument compiler
  1524. X   const char * save_arg = arg ;  // just in case someone forgets to set it
  1525. X   bad_val = (*cmdarg)(arg, *this);
  1526. X   if (! bad_val) {
  1527. X      cmdarg->set(CmdArg::GIVEN) ;
  1528. X      if (arg != save_arg) {
  1529. X         cmdarg->set(CmdArg::VALGIVEN) ;
  1530. X      }
  1531. X   }
  1532. X
  1533. X   // if we were waiting for a value - we just got it
  1534. X   if (arg != save_arg) {
  1535. X      if (cmdarg == cmd_matched_arg)  cmd_parse_state = cmd_START_STATE ;
  1536. X   }
  1537. X
  1538. X   // if this is a list - optional values may follow the one given
  1539. X   if ((cmdarg->syntax() & CmdArg::isLIST) && (arg != save_arg)) {
  1540. X      cmd_matched_arg = cmdarg ;
  1541. X      cmd_parse_state = cmd_WANT_VAL ;
  1542. X   }
  1543. X
  1544. X   return  bad_val ;
  1545. X}
  1546. X
  1547. X
  1548. X//-------
  1549. X// ^FUNCTION: CmdLine::ck_need_val - See if an argument needs a value
  1550. X//
  1551. X// ^SYNOPSIS:
  1552. X//    extern void CmdLine::ck_needval(void)
  1553. X//
  1554. X// ^PARAMETERS:
  1555. X//    NONE.
  1556. X//
  1557. X// ^DESCRIPTION:
  1558. X//    We parse command-lines using something akin to a deterministic
  1559. X//    finite state machine. Each argv[] element on the command-line is
  1560. X//    considered a single input to the machine and we keep track of an
  1561. X//    associated machine-state that tells us what to do next for a given
  1562. X//    input.
  1563. X//
  1564. X//    In this function, we are merely trying to query the "state" of the
  1565. X//    machine by asking it if it is expecting to see a value for an
  1566. X//    argument that was matched in a previous argv[] element.
  1567. X//
  1568. X//    It is assumed that this function is called only after it has already
  1569. X//    been determined that the current argv[] element is NOT an argument
  1570. X//    value.
  1571. X//
  1572. X// ^REQUIREMENTS:
  1573. X//
  1574. X// ^SIDE-EFFECTS:
  1575. X//    - updates the "state" of the command.
  1576. X//    - updates the "status" of the command.
  1577. X//    - modifies the last matched argument if it takes an optional value.
  1578. X//    - prints a message on stderr if cmd_QUIET is NOT set and we were
  1579. X//      expecting a required value.
  1580. X//
  1581. X// ^RETURN-VALUE:
  1582. X//    None.
  1583. X//
  1584. X// ^ALGORITHM:
  1585. X//    If we were expecting an optional value then
  1586. X//    - set the GIVEN flag of the last arg we matched (DO NOT set VALGIVEN).
  1587. X//    - call the compiler-function of the last-matched arg using NULL
  1588. X//      as the argument (unless the arg is a LIST and VALGIVEN is set).
  1589. X//    - reset the command-state
  1590. X//    Else if we were expecting a required value then
  1591. X//    - print a an error message if cmd_QUIET is not set
  1592. X//    - set the command-status to VAL_MISSING
  1593. X//    - reset the command-state
  1594. X//    Endif
  1595. X//-^^----
  1596. Xvoid
  1597. XCmdLine::ck_need_val(void)
  1598. X{
  1599. X   const char * null_str = NULL;
  1600. X   if (cmd_parse_state == cmd_WANT_VAL) {
  1601. X      // argument was given but optional value was not
  1602. X      cmd_matched_arg->set(CmdArg::GIVEN) ;
  1603. X      if ((! (cmd_matched_arg->syntax() & CmdArg::isLIST)) ||
  1604. X          (! (cmd_matched_arg->flags()  & CmdArg::VALGIVEN))) {
  1605. X         (void) handle_arg(cmd_matched_arg, null_str) ;
  1606. X      }
  1607. X      cmd_parse_state = cmd_START_STATE ;
  1608. X   } else if (cmd_parse_state == cmd_NEED_VAL) {
  1609. X      // argument was given but required value was not
  1610. X      if (! (cmd_flags & QUIET)) {
  1611. X         arg_error("value required for", cmd_matched_arg) << "." << endl ;
  1612. X      }
  1613. X      cmd_status |= VAL_MISSING ;
  1614. X      cmd_parse_state = cmd_START_STATE ;
  1615. X   }
  1616. X}
  1617. X
  1618. X
  1619. X#ifndef GNU_READLINE
  1620. X//
  1621. X// readline() -- indigent person's version of the GNU readline() function
  1622. X//
  1623. X
  1624. X#define PROMPT_BUFSIZE 256
  1625. X
  1626. Xstatic char *
  1627. Xreadline(const char * prompt)
  1628. X{
  1629. X   char * buf = (char *) ::malloc(PROMPT_BUFSIZE);
  1630. X   if (buf == NULL)  return  NULL ;
  1631. X   *buf = '\0';
  1632. X
  1633. X   // prompt the user and collect input
  1634. X   cerr << prompt << flush ;
  1635. X   cin.getline(buf, PROMPT_BUFSIZE);
  1636. X
  1637. X   return  buf ;
  1638. X}
  1639. X#endif // ! GNU_READLINE
  1640. X
  1641. X
  1642. X//-------
  1643. X// ^FUNCTION: CmdLine::prompt_user - prompt the user for a missing argument
  1644. X//
  1645. X// ^SYNOPSIS:
  1646. X//    unsigned CmdLine::prompt_user(cmdarg);
  1647. X//
  1648. X// ^PARAMETERS:
  1649. X//    CmdArg * cmdarg;
  1650. X//    -- the argument that we need to prompt for
  1651. X//
  1652. X// ^DESCRIPTION:
  1653. X//    If cin is connected to a terminal, then we will prompt the user
  1654. X//    for an argument corresponding to "cmdarg" and attempt to "compile" it
  1655. X//    into the desired internal format. The user only has one chance
  1656. X//    to get the "argument" right; we do not continue prompting if the
  1657. X//    value that was entered is invalid.
  1658. X//
  1659. X// ^REQUIREMENTS:
  1660. X//    "cmdarg" should be a REQUIRED argument that has already been determined
  1661. X//    to be missing from the command-line.
  1662. X//
  1663. X// ^SIDE-EFFECTS:
  1664. X//    - modifies the status of the command.
  1665. X//    - modifies "cmdarg".
  1666. X//    - prints a prompt on cerr and reads from cin
  1667. X//
  1668. X// ^RETURN-VALUE:
  1669. X//    0 if the argument was succesfully entered by the user,
  1670. X//    ARG_MISSING otherwise.
  1671. X//
  1672. X// ^ALGORITHM:
  1673. X//    - if cin is not a terminal return ARG_MISSING.
  1674. X//    - if "cmdarg" is a LIST, make sure we prompt the use once for each
  1675. X//      possible value in the list.
  1676. X//    - prompt the user for an argument and read the result.
  1677. X//    - if the user just typed <RETURN> return ARG_MISSING.
  1678. X//    - "handle" the value that was entered.
  1679. X//    - continue prompting if we are a LIST and a valid, non-empty,
  1680. X//      value was given
  1681. X//    - if an invalid value was given return ARG_MISSING
  1682. X//    - else return 0
  1683. X//-^^----
  1684. Xunsigned
  1685. XCmdLine::prompt_user(CmdArg * cmdarg)
  1686. X{
  1687. X   // dont prompt if cin or cerr is not interactive
  1688. X   int fd = ((filebuf *)(cin.rdbuf()))->fd();
  1689. X   if (! ::isatty(fd))  return  ARG_MISSING ;
  1690. X
  1691. X   fd = ((filebuf *)(cerr.rdbuf()))->fd();
  1692. X   if (! ::isatty(fd))  return  ARG_MISSING ;
  1693. X
  1694. X   // if we have a list, need to prompt repeatedly
  1695. X   if (cmdarg->syntax() & CmdArg::isLIST) {
  1696. X      cerr << "Enter one " << cmdarg->value_name() << " per line "
  1697. X           << "(enter a blank-line to stop)." << endl ;
  1698. X   }
  1699. X   char prompt[256], * buf = NULL;
  1700. X   ostrstream  oss(prompt, sizeof(prompt));
  1701. X   oss << "\rEnter " << cmdarg->value_name() << ": " << ends ;
  1702. X   int  errs = 0, first = 1;
  1703. X   do {  // need repeated prompting for a LIST
  1704. X      if (buf)  ::free(buf);
  1705. X      buf = ::readline(prompt) ;
  1706. X      if (buf == NULL)  return  ARG_MISSING ;
  1707. X
  1708. X      // make sure we read something!
  1709. X      if (! *buf) {
  1710. X         if (first) {
  1711. X            error() << "error - no " << cmdarg->value_name()
  1712. X                    << " given!" << endl ;
  1713. X            ++errs;
  1714. X         }
  1715. X         continue;
  1716. X      }
  1717. X
  1718. X#ifdef GNU_READLINE
  1719. X      // add this line to the history list
  1720. X      ::add_history(buf);
  1721. X#endif
  1722. X
  1723. X      // try to handle the value we read (remember - buf is temporary)
  1724. X      if (! errs) {
  1725. X         const char * arg = buf;
  1726. X         unsigned  save_cmd_flags = cmd_flags;
  1727. X         cmd_flags |= TEMP;
  1728. X         errs = handle_arg(cmdarg, arg);
  1729. X         if (errs) {
  1730. X            arg_error("bad value for", cmdarg) << "." << endl ;
  1731. X         }
  1732. X         cmd_flags = save_cmd_flags;
  1733. X      }
  1734. X
  1735. X      first = 0;
  1736. X   } while (!errs && (cmdarg->syntax() & CmdArg::isLIST) &&  *buf);
  1737. X
  1738. X   if (! errs)  cmdarg->set(CmdArg::VALSEP);
  1739. X
  1740. X   if (buf)  ::free(buf);
  1741. X   return  (errs) ? ARG_MISSING : NO_ERROR ;
  1742. X}
  1743. X
  1744. X//-------
  1745. X// ^FUNCTION: CmdLine::syntax - determine usage message syntax
  1746. X//
  1747. X// ^SYNOPSIS:
  1748. X//    CmdLine::CmdLineSyntax CmdLine::syntax(void);
  1749. X//
  1750. X// ^PARAMETERS:
  1751. X//
  1752. X// ^DESCRIPTION:
  1753. X//    One of the things we keep track of in the CmdLine object is whether
  1754. X//    options and/or keywords (long-options) were used on the command-line.
  1755. X//    If a command-line syntax error occurs and only options (keywords)
  1756. X//    were used then the usage message will only contain option (keyword)
  1757. X//    syntax. If BOTH were used or if usage was specifically requested via
  1758. X//    a cmdargUsage option (which we also keep track of) then we want the
  1759. X//    the usage message to contain the syntac for both options and keywords.
  1760. X//
  1761. X//    If neither options nor keywords were given (meaning only positional
  1762. X//    parameters were used) then we only use option-syntax (for brevity).
  1763. X//
  1764. X// ^REQUIREMENTS:
  1765. X//
  1766. X// ^SIDE-EFFECTS:
  1767. X//    None.
  1768. X//
  1769. X// ^RETURN-VALUE:
  1770. X//    The desired usage message syntax to use.
  1771. X//
  1772. X// ^ALGORITHM:
  1773. X//    Trivial.
  1774. X//-^^----
  1775. XCmdLine::CmdLineSyntax
  1776. XCmdLine::syntax(void) const
  1777. X{
  1778. X   if (cmd_flags & KWDS_ONLY) {
  1779. X      return  cmd_KWDS_ONLY;
  1780. X   } else if (cmd_flags & OPTS_ONLY) {
  1781. X      return  cmd_OPTS_ONLY;
  1782. X   } else if ((cmd_state & cmd_OPTIONS_USED) &&
  1783. X              (cmd_state & cmd_KEYWORDS_USED)) {
  1784. X      return  cmd_BOTH ;
  1785. X   } else if (cmd_state & cmd_KEYWORDS_USED) {
  1786. X      return  cmd_KWDS_ONLY ;
  1787. X   } else {
  1788. X      return  cmd_OPTS_ONLY ;
  1789. X   }
  1790. X}
  1791. X
  1792. X
  1793. X//-------
  1794. X// ^FUNCTION: CmdLine::missing_args - check for missing required arguments
  1795. X//
  1796. X// ^SYNOPSIS:
  1797. X//    unsigned CmdLine::missing_args(void);
  1798. X//
  1799. X// ^PARAMETERS:
  1800. X//
  1801. X// ^DESCRIPTION:
  1802. X//    This function checks to see if there is a required argument in the
  1803. X//    CmdLine object that was NOT specified on the command. If this is
  1804. X//    the case and PROMPT_USER is set (or $PROMPT_USER exists and is
  1805. X//    non-empty) then we attempt to prompt the user for the missing argument.
  1806. X//
  1807. X// ^REQUIREMENTS:
  1808. X//
  1809. X// ^SIDE-EFFECTS:
  1810. X//    - modifies the status of "cmd".
  1811. X//    - terminates execution by calling exit(3C) if cmd_NOABORT is NOT
  1812. X//      set and a required argument (that was not properly supplied by
  1813. X//      the user) is not given.
  1814. X//    - prints on stderr if an argument is missing and cmd_QUIET is NOT set.
  1815. X//    - also has the side-effects of prompt_user() if we need to prompt
  1816. X//      the user for input.
  1817. X//
  1818. X// ^RETURN-VALUE:
  1819. X//    The current value of the (possibly modified) command status. This is a
  1820. X//    combination of bitmasks of type cmdline_flags_t defined in <cmdline.h>
  1821. X//
  1822. X// ^ALGORITHM:
  1823. X//    Foreach argument in cmd
  1824. X//       if argument is required and was not given
  1825. X//          if required, prompt for the missing argument
  1826. X//             if prompting was unsuccesful add ARG_MISSING to cmd-status
  1827. X//             endif
  1828. X//          else add ARG_MISSING to cmd-status
  1829. X//          endif
  1830. X//       endif
  1831. X//    endfor
  1832. X//    return the current cmd-status
  1833. X//-^^----
  1834. Xunsigned
  1835. XCmdLine::missing_args(void)
  1836. X{
  1837. X   char buf[256];
  1838. X
  1839. X   CmdArgListListIter  list_iter(cmd_args);
  1840. X   for (CmdArgList * alist = list_iter() ; alist ; alist = list_iter()) {
  1841. X      CmdArgListIter  iter(alist);
  1842. X      for (CmdArg * cmdarg = iter() ; cmdarg ; cmdarg = iter()) {
  1843. X         if (cmdarg->is_dummy())  continue;
  1844. X         if ((cmdarg->syntax() & CmdArg::isREQ) &&
  1845. X             (! (cmdarg->flags() & CmdArg::GIVEN)))
  1846. X         {
  1847. X            if (! (cmd_flags & QUIET)) {
  1848. X               fmt_arg(cmdarg,  buf, sizeof(buf), syntax(), TERSE_USAGE);
  1849. X               error() << buf << " required." << endl ;
  1850. X            }
  1851. X            if (cmd_status & ARG_MISSING) {
  1852. X               // user didnt supply the missing argument
  1853. X               return  cmd_status ;
  1854. X            } else if ((! (cmd_flags & NO_ABORT)) && cmd_status) {
  1855. X               // other problems
  1856. X               return  cmd_status ;
  1857. X            } else if (cmd_flags & PROMPT_USER) {
  1858. X               cmd_status |= prompt_user(cmdarg);
  1859. X            } else {
  1860. X               char * env = ::getenv("PROMPT_USER");
  1861. X               if (env && *env) {
  1862. X                  cmd_status |= prompt_user(cmdarg);
  1863. X               } else {
  1864. X                  cmd_status |= ARG_MISSING ;
  1865. X               }
  1866. X            }
  1867. X         } //if
  1868. X      } //for iter
  1869. X   } //for list_iter
  1870. X
  1871. X   return  cmd_status ;
  1872. X}
  1873. X
  1874. X
  1875. X//-------
  1876. X// ^FUNCTION: CmdLine::opt_match - attempt to match on option
  1877. X//
  1878. X// ^SYNOPSIS:
  1879. X//    CmdArg * CmdLine::opt_match(optchar);
  1880. X//
  1881. X// ^PARAMETERS:
  1882. X//    char optchar;
  1883. X//    -- a possible option for "cmd"
  1884. X//
  1885. X// ^DESCRIPTION:
  1886. X//    If "cmd" has an argument that has "optchar" as a single-character
  1887. X//    option then this function will find and return that argument.
  1888. X//
  1889. X// ^REQUIREMENTS:
  1890. X//
  1891. X// ^SIDE-EFFECTS:
  1892. X//    None.
  1893. X//
  1894. X// ^RETURN-VALUE:
  1895. X//    If we find a match, then we return a pointer to its argdesc,
  1896. X//    otherwise we return NULL.
  1897. X//
  1898. X// ^ALGORITHM:
  1899. X//    Trivial.
  1900. X//-^^----
  1901. XCmdArg *
  1902. XCmdLine::opt_match(char optchar) const
  1903. X{
  1904. X   CmdArgListListIter  list_iter(cmd_args);
  1905. X   for (CmdArgList * alist = list_iter() ; alist ; alist = list_iter()) {
  1906. X      CmdArgListIter  iter(alist);
  1907. X      for (CmdArg * cmdarg = iter() ; cmdarg ; cmdarg = iter()) {
  1908. X         if (cmdarg->is_dummy())  continue;
  1909. X         if (optchar == cmdarg->char_name()) {
  1910. X            // exact match
  1911. X            return  cmdarg ;
  1912. X         } else if (cmd_flags & ANY_CASE_OPTS) {
  1913. X            // case-insensitive match
  1914. X            if (TO_LOWER(optchar) == TO_LOWER(cmdarg->char_name())) {
  1915. X               return  cmdarg ;
  1916. X            }
  1917. X         }
  1918. X      } //for iter
  1919. X   } //for list_iter
  1920. X   return  NULL ;
  1921. X}
  1922. X
  1923. X//-------
  1924. X// ^FUNCTION: CmdLine::kwd_match - purpose
  1925. X//
  1926. X// ^SYNOPSIS:
  1927. X//    extern CmdArg * CmdLine::kwd_match(kwd, len, is_ambiguous, match_value);
  1928. X//
  1929. X// ^PARAMETERS:
  1930. X//    const char * kwd;
  1931. X//    -- a possible kewyord of "cmd"
  1932. X//
  1933. X//    int len;
  1934. X//    -- the number of character of "kwd" to consider (< 0 if all characters
  1935. X//       of "kwd" should be used).
  1936. X//
  1937. X//    int & is_ambiguous;
  1938. X//    -- upon return, the value pointed to is set to 1 if the keyword
  1939. X//       matches more than 1 keyword in "cmd"; Otherwise it is set to 0.
  1940. X//
  1941. X//    int match_value;
  1942. X//    -- if this is non-zero, then if a keyword_name is NULL use the 
  1943. X//       value_name instead.
  1944. X//
  1945. X// ^DESCRIPTION:
  1946. X//    If "cmd" has an argument that matches "kwd" as a kewyord
  1947. X//    then this function will find and return that argument.
  1948. X//
  1949. X// ^REQUIREMENTS:
  1950. X//
  1951. X// ^SIDE-EFFECTS:
  1952. X//    None.
  1953. X//
  1954. X// ^RETURN-VALUE:
  1955. X//    If we find a match, then we return a pointer to its argdesc,
  1956. X//    otherwise we return NULL.
  1957. X//
  1958. X// ^ALGORITHM:
  1959. X//    Set is_ambigous to 0.
  1960. X//    For each argument in cmd
  1961. X//       if argument's keyword-name matches kwd then
  1962. X//          if this was an exact match then return this argument
  1963. X//          else if we had a previous partial match of this argument then
  1964. X//             if argument is a default argument return the previous match
  1965. X//             else set is_ambiguous to 1 and return NULL
  1966. X//          else remember we had a partial match here and keep trying
  1967. X//          endif
  1968. X//       endif
  1969. X//    end for
  1970. X//    if we has a partial match and we get to here then it is NOT ambiguous do
  1971. X//       go ahead and return the argument we matched.
  1972. X//-^^----
  1973. XCmdArg *
  1974. XCmdLine::kwd_match(const char * kwd,
  1975. X                   int          len,
  1976. X                   int &        is_ambiguous,
  1977. X                   int          match_value) const
  1978. X{
  1979. X   CmdArg * matched = NULL;
  1980. X
  1981. X   is_ambiguous = 0 ;
  1982. X
  1983. X   CmdArgListListIter  list_iter(cmd_args);
  1984. X   for (CmdArgList * alist = list_iter() ; alist ; alist = list_iter()) {
  1985. X      CmdArgListIter  iter(alist);
  1986. X      for (CmdArg * cmdarg = iter() ; cmdarg ; cmdarg = iter()) {
  1987. X         if (cmdarg->is_dummy())  continue;
  1988. X
  1989. X         // attempt to match this keyword
  1990. X         strmatch_t  result ;
  1991. X         const char * source = cmdarg->keyword_name();
  1992. X         if (source && *source) {
  1993. X            result = strmatch(source, kwd, len) ;
  1994. X         } else if (match_value) {
  1995. X            result = strmatch(cmdarg->value_name(), kwd, len) ;
  1996. X         }
  1997. X
  1998. X         if (result == str_EXACT) {
  1999. X            return  cmdarg ;
  2000. X         } else if (result == str_PARTIAL) {
  2001. X            if (matched) {
  2002. X               is_ambiguous = 1 ;
  2003. X               return  NULL ;  // ambiguous keyword
  2004. X            }
  2005. X            matched = cmdarg ;  // we matched this one
  2006. X         }
  2007. X      } //for iter
  2008. X      if (matched) break;
  2009. X   } //for list_iter
  2010. X   return  matched ;
  2011. X}
  2012. X
  2013. X//-------
  2014. X// ^FUNCTION: CmdLine::pos_match - match a positional argument
  2015. X//
  2016. X// ^SYNOPSIS:
  2017. X//    CmdArg * CmdLine::pos_match(void)
  2018. X//
  2019. X// ^PARAMETERS:
  2020. X//
  2021. X// ^DESCRIPTION:
  2022. X//    If "cmd" has an positional argument that has not yet been given
  2023. X//    then this function will find and return the first such argument.
  2024. X//
  2025. X// ^REQUIREMENTS:
  2026. X//
  2027. X// ^SIDE-EFFECTS:
  2028. X//    None.
  2029. X//
  2030. X// ^RETURN-VALUE:
  2031. X//    If we find a match, then we return a pointer to its argument,
  2032. X//    otherwise we return NULL.
  2033. X//
  2034. X// ^ALGORITHM:
  2035. X//    Trivial.
  2036. X//-^^----
  2037. XCmdArg *
  2038. XCmdLine::pos_match(void) const
  2039. X{
  2040. X   CmdArgListListIter  list_iter(cmd_args);
  2041. X   for (CmdArgList * alist = list_iter() ; alist ; alist = list_iter()) {
  2042. X      CmdArgListIter  iter(alist);
  2043. X      for (CmdArg * cmdarg = iter() ; cmdarg ; cmdarg = iter()) {
  2044. X         if (cmdarg->is_dummy())  continue;
  2045. X         if ((cmdarg->syntax() & CmdArg::isPOS) &&
  2046. X             (! (cmdarg->flags() & CmdArg::GIVEN)))
  2047. X         {
  2048. X            return  cmdarg ;
  2049. X         }
  2050. X      } //for iter
  2051. X   } //for list_iter
  2052. X   return  NULL ;
  2053. X}
  2054. END_OF_FILE
  2055. if test 19806 -ne `wc -c <'src/lib/private.c'`; then
  2056.     echo shar: \"'src/lib/private.c'\" unpacked with wrong size!
  2057. fi
  2058. # end of 'src/lib/private.c'
  2059. fi
  2060. echo shar: End of archive 5 \(of 7\).
  2061. cp /dev/null ark5isdone
  2062. MISSING=""
  2063. for I in 1 2 3 4 5 6 7 ; do
  2064.     if test ! -f ark${I}isdone ; then
  2065.     MISSING="${MISSING} ${I}"
  2066.     fi
  2067. done
  2068. if test "${MISSING}" = "" ; then
  2069.     echo You have unpacked all 7 archives.
  2070.     rm -f ark[1-9]isdone
  2071. else
  2072.     echo You still need to unpack the following archives:
  2073.     echo "        " ${MISSING}
  2074. fi
  2075. ##  End of shell archive.
  2076. exit 0
  2077.  
  2078. exit 0 # Just in case...
  2079.