home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume31 / cmdline / part05 < prev    next >
Text File  |  1992-07-27  |  63KB  |  2,073 lines

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