home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume29 / parsearg / part09 < prev    next >
Encoding:
Text File  |  1992-05-18  |  77.6 KB  |  2,409 lines

  1. Newsgroups: comp.sources.misc
  2. From: brad@hcx1.ssd.csd.harris.com (Brad Appleton)
  3. Subject:  v29i124:  parseargs - functions to parse command line arguments, Part09/10
  4. Message-ID: <1992May17.182540.29086@sparky.imd.sterling.com>
  5. X-Md4-Signature: 291b96e1994335992598e3a066160c9e
  6. Date: Sun, 17 May 1992 18:25:40 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: brad@hcx1.ssd.csd.harris.com (Brad Appleton)
  10. Posting-number: Volume 29, Issue 124
  11. Archive-name: parseargs/part09
  12. Environment: UNIX, VMS, MS-DOS, OS/2, Amiga
  13. Supersedes: parseargs: Volume 17, Issue 46-57
  14.  
  15. #! /bin/sh
  16. # This is a shell archive.  Remove anything before this line, then unpack
  17. # it by saving it into a file and typing "sh file".  To overwrite existing
  18. # files, type "sh file -c".  You can also feed this as standard input via
  19. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  20. # will see the following message at the end:
  21. #        "End of archive 9 (of 10)."
  22. # Contents:  xparse.c
  23. # Wrapped by brad@hcx1 on Thu May  7 12:12:29 1992
  24. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  25. if test -f 'xparse.c' -a "${1}" != "-c" ; then 
  26.   echo shar: Will not clobber existing file \"'xparse.c'\"
  27. else
  28. echo shar: Extracting \"'xparse.c'\" \(75200 characters\)
  29. sed "s/^X//" >'xparse.c' <<'END_OF_FILE'
  30. X/*************************************************************************
  31. X** ^FILE: xparse.c - library functions for the parsargs(3) package
  32. X**
  33. X** ^DESCRIPTION:
  34. X**    This file implements the following functions in the parseargs library:
  35. X**
  36. X**       init_args()  -- constructor for a command-object
  37. X**       usage()      -- pretty-print the command-usage
  38. X**       parsecntl()  -- control parsing, get/set command-attributes
  39. X**       parseargs()  -- parse arguments from a string vector
  40. X**       fparseargs() -- parse arguments from a file pointer
  41. X**       lparseargs() -- parse arguments from an arglist
  42. X**       sparseargs() -- parse arguyments in a string
  43. X**       vparseargs() -- parse arguments from a variable argument list
  44. X**
  45. X**    It should be noted that sparseargs() splits the given string up into
  46. X**    a whitespace separated series of tokens, whereas vparseargs assumes
  47. X**    that each parameter is already a single token (hence performs no
  48. X**    token splitting).
  49. X**
  50. X**    Each of these functions returns 0 upon success and non-zero otherwise
  51. X**    (except for usage() & init_args, which have no return value).
  52. X**
  53. X** ^SIDE-EFFECTS:
  54. X**    Each of the functions in the parseargs library will set the external
  55. X**    character string ProgName to be the name of the last command that was
  56. X**    operated upon by any of the library routines.
  57. X**
  58. X**    When an argument-descriptor array is first encountered by any of the
  59. X**    parseargs library routines, it is initially compiled into an inter-
  60. X**    mediate form that is more convenient to manipulate. As a direct
  61. X**    result, it is not advisable to attempt to index directly into the
  62. X**    array to manipulate one of the argument descriptors (because the
  63. X**    argdesc that you thought was there may actually be somewhere else).
  64. X**    After the array has been given its initial value(s), only parsecntl(3)
  65. X**    should be used to manipulate or query the attributes of an argument
  66. X**    descriptor.
  67. X**
  68. X** ^FILES:
  69. X**    <useful.h>
  70. X**    <parseargs.h>
  71. X**
  72. X** ^SEE_ALSO:
  73. X**    argtype(3), parseargs(1), parseargs(3)
  74. X**
  75. X** ^CAVEATS:
  76. X**    Because of the way argument parsing is implemented under UNIX, MS-DOS
  77. X**    and OS/2, option arguments which contain a leading dash (`-') (or
  78. X**    whatever the option prefix character is defined to be) may not be
  79. X**    specified as a separate argument on the command line, it must be part
  80. X**    of the same argument.  That is to say that if a program has a -f option
  81. X**    that requires a string argument, then the following:
  82. X**          -f-arg
  83. X**
  84. X**    will properly assign the string "-arg" to the option whereas the
  85. X**    following:
  86. X**          -f -arg
  87. X**
  88. X**    will be interpreted by parseargs as two option strings: the first of
  89. X**    which ("-f") is missing a required argument and the second of which
  90. X**    ("-arg") will most likely be flagged as an invalid option.
  91. X**
  92. X**    Similarly, if the user requires an ARGLIST option to take multiple
  93. X**    arguments with leading dashes then the following method must be used:
  94. X**    It is a "feature" of parseargs that ARGLIST arguments are always
  95. X**    appended to the current list of arguments for the given option. Thus,
  96. X**    if "-f" is an option taking a list of arguments, then the following
  97. X**    are all equivalent:
  98. X**          -farg1 arg2
  99. X**          -f arg1 arg2
  100. X**          -farg1 -farg2
  101. X**          -f arg1 -f arg2
  102. X**
  103. X**     Hence multiple "leading dash" arguments may specified as follows:
  104. X**          -f-dash_arg1 -f-dash_arg2  ...
  105. X**
  106. X** ^BUGS:
  107. X**    When a non-multivalued argument appears more than once on the
  108. X**    command-line then only the last value supplied is used. A problem
  109. X**    occurs however in the following scenario: suppose `-s' is an option
  110. X**    that takes an optional string argument (and suppose `-x' is some
  111. X**    boolean flag). Then if the following command-line is issued:
  112. X**
  113. X**         command  -s string  -x  -s
  114. X**
  115. X**    then, the argument flags will properly correspond to the second
  116. X**    instance of the `-s' option (namely ARGGIVEN will be set but ARGVAL-
  117. X**    GIVEN will be unset) but the value associated with the option will be
  118. X**    "string" (because the first instance overwrote the default).
  119. X**    Because of this, it may be safest to reassign the default value if
  120. X**    ARGGIVEN is set but ARGVALGIVEN is unset.
  121. X**
  122. X** ^HISTORY:
  123. X**    01/02/91     Brad Appleton     <brad@ssd.csd.harris.com>     Created
  124. X**
  125. X**    04/03/91     Brad Appleton     <brad@ssd.csd.harris.com>
  126. X**    - fixed bug in [fvsl]parseargs() and parseargs().
  127. X**      previous parse-flags should not be reset until AFTER required
  128. X**      arguments are checked for, otherwise we may forget to prompt
  129. X**      for them if $PARSECNTL asked us to do so.
  130. X**
  131. X**    08/27/91     Earl Chew     <cechew@bruce.cs.monash.edu.au>
  132. X**    - split out get_description().
  133. X**    - add ProgNameLen
  134. X**    - support for non-writable strings
  135. X**    - allow sparseargs() to parse empty strings like parseargs()
  136. X**
  137. X**    04/03/91     Brad Appleton     <brad@ssd.csd.harris.com>
  138. X**    - changed vms_style stuff to use ps_NOTCMDLINE
  139. X***^^**********************************************************************/
  140. X
  141. X#include <stdio.h>
  142. X#include <ctype.h>
  143. X#include <useful.h>
  144. X#include "strfuncs.h"
  145. X#include "exit_codes.h"
  146. X
  147. X#define PARSEARGS_PRIVATE   /* include private definitions */
  148. X#define PARSEARGS_NEXTERNS  /* exclude external declarations */
  149. X#include "parseargs.h"
  150. X
  151. X#ifdef amiga_style
  152. X#  define  pa_DEFAULTS  0x000
  153. X#  define  parse_argv_style   amiga_parse
  154. X#  define  print_usage_style  amiga_usage
  155. X   EXTERN  int   amiga_parse  ARGS(( char **, ARGDESC * ));
  156. X   EXTERN  VOID  amiga_usage  ARGS(( const ARGDESC *, argMask_t ));
  157. X#endif
  158. X#ifdef ibm_style
  159. X#  define  pa_DEFAULTS  pa_ANYCASE
  160. X#  define  parse_argv_style   ibm_parse
  161. X#  define  print_usage_style  ibm_usage
  162. X   EXTERN  int   ibm_parse  ARGS(( char **, ARGDESC * ));
  163. X   EXTERN  VOID  ibm_usage  ARGS(( const ARGDESC *, argMask_t ));
  164. X#endif
  165. X#ifdef unix_style
  166. X#  define  pa_DEFAULTS  pa_FLAGS1ST
  167. X#  define  parse_argv_style   unix_parse
  168. X#  define  print_usage_style  unix_usage
  169. X   EXTERN  int   unix_parse   ARGS(( char **, ARGDESC * ));
  170. X   EXTERN  VOID  unix_usage   ARGS(( const ARGDESC *, argMask_t ));
  171. X#endif
  172. X#ifdef vms_style
  173. X#  define  pa_DEFAULTS  pa_PROMPT
  174. X#  define  parse_argv_style   vms_parse
  175. X#  define  print_usage_style  vms_usage
  176. X   EXTERN  int   vms_parse    ARGS(( char **, ARGDESC * ));
  177. X   EXTERN  VOID  vms_usage    ARGS(( const ARGDESC *, argMask_t ));
  178. X#endif
  179. X
  180. X
  181. X#ifdef vms
  182. X#  define  USER_VARIABLE "symbol"
  183. X#else
  184. X#  define  USER_VARIABLE "environment variable"
  185. X#endif
  186. X
  187. X
  188. X/***************************************************************************
  189. X** ^MACRO: SYNTAX_ERROR -  check for syntax errors & missing required arguments
  190. X**
  191. X** ^SYNOPSIS:
  192. X**    SYNTAX_ERROR(status, argd)
  193. X**
  194. X** ^PARAMETERS:
  195. X**    status
  196. X**    -- current parsing status returned by last xparsexxx() call
  197. X**
  198. X**    argd
  199. X**    --argdesc-array
  200. X**
  201. X** ^RETURN-VALUE:
  202. X**    Evaluates to TRUE if need to exit, FALSE otherwise
  203. X**
  204. X** ^ALGORITHM:
  205. X**    - if (!pa_NOCHECK) and (verify_argreqs == error) then return TRUE
  206. X**    - else return FALSE
  207. X***^^**********************************************************************/
  208. X#define  SYNTAX_ERROR(status, argd)  ( !verify_argreqs(argd, &status) )
  209. X
  210. X
  211. X/***************************************************************************
  212. X** ^GLOBAL-VARIABLE: ProgName, ProgNameLen
  213. X**
  214. X** ^VISIBILITY:
  215. X**    external global (visible to functions in all files)
  216. X**
  217. X** ^DESCRIPTION:
  218. X**    ProgName (which is initially NULL) will be used to point to the
  219. X**    command-name (specified on the command-line) of the command that
  220. X**    has most recently invoked a function in the parseargs library.
  221. X**    ProgNameLen will be set to the length of the string.
  222. X***^^**********************************************************************/
  223. XCONST char *ProgName = CHARNULL;
  224. Xint ProgNameLen = 0;
  225. X
  226. XEXTERN  VOID  syserr   ARGS((const char *, ...));
  227. XEXTERN  VOID  usrerr   ARGS((const char *, ...));
  228. XEXTERN  VOID  eprintf  ARGS((const char *, ...));
  229. X
  230. X#ifdef vms_style
  231. X   EXTERN BOOL argInput        ARGS((ARGDESC *, char *, BOOL));
  232. X   EXTERN BOOL argOutput       ARGS((ARGDESC *, char *, BOOL));
  233. X#endif
  234. X
  235. X#define  MAXLINE  256
  236. X
  237. X
  238. X/* override argument descriptor, if none given by user */
  239. Xstatic ARGDESC  Empty_ArgDesc[] = { START_ARGUMENTS, END_ARGUMENTS };
  240. X
  241. X/***************************************************************************
  242. X** ^SECTION: DEFAULT-ARGUMENTS
  243. X**    Each argdesc-array has an initial default argument list (which may be
  244. X**    reset using the pc_DEFARGS function code with parsecntl). This initial
  245. X**    default argument-list contains `?' and `H' which may be used as single
  246. X**    character keywords to display command-usage for all command-line
  247. X**    styles.  Similarly, "?", "H", and "Help" may be used as long-keywords
  248. X**    to display command-usage for all command-line styles.  In Addition,
  249. X**    for VMS style commands, the qualifiers /INPUT=file, /OUTPUT=file, and
  250. X**    /ERROR=file, may be used to redirect stdin, stdout, and stderr
  251. X**    (respectively) to a file.  For AmigaDOS style commands, the keyword
  252. X**    "ENDKWDS" may be used to disable parsing for any more keywords on
  253. X**    the command-line.
  254. X***^^**********************************************************************/
  255. Xstatic  ARGDESC  Default_ArgDesc[] = {
  256. X   START_ARGUMENTS,
  257. X
  258. X/* <name> <flags>    <type>     <valp>         <prompt>      */
  259. X   { '?', ARGHIDDEN, argUsage, __ NULL,    "? (print usage and exit)" },
  260. X   { 'H', ARGHIDDEN, argUsage, __ NULL,    "Help (print usage and exit)" },
  261. X
  262. X#ifdef amiga_style
  263. X   { '-', ARGHIDDEN, argEnd,   __ NULL,    "ENDKeyWorDS" },
  264. X#endif
  265. X
  266. X#ifdef vms_style
  267. X# ifdef vms
  268. X   { '<', ARGHIDDEN, argInput, __ &stdin,   "sysINPUT (redirect SYS$INPUT)" },
  269. X   { '>', ARGHIDDEN, argOutput, __ &stdout, "sysOUTPUT (redirect SYS$OUTPUT)" },
  270. X   { '%', ARGHIDDEN, argOutput, __ &stderr, "sysERROR (redirect SYS$ERROR)" },
  271. X# else
  272. X   { '<', ARGHIDDEN, argInput, __ stdin,   "sysINPUT (redirect SYS$INPUT)" },
  273. X   { '>', ARGHIDDEN, argOutput, __ stdout, "sysOUTPUT (redirect SYS$OUTPUT)" },
  274. X   { '%', ARGHIDDEN, argOutput, __ stderr, "sysERROR (redirect SYS$ERROR)" },
  275. X# endif
  276. X#endif
  277. X
  278. X   END_ARGUMENTS
  279. X};
  280. X
  281. X
  282. X#ifdef AmigaDOS
  283. X#  define  getenv(s)   CHARNULL
  284. X#  define  envfree(s)  s = CHARNULL
  285. X#endif
  286. X
  287. X#if ( defined(MSDOS) || defined(OS2) )
  288. X   EXTERN  char *getenv ARGS(( const char * ));
  289. X#  define  envfree(s)  s = CHARNULL
  290. X#endif
  291. X
  292. X#ifdef unix
  293. X   EXTERN  char *getenv ARGS(( const char * ));
  294. X#  define  envfree(s)  s = CHARNULL
  295. X#endif
  296. X
  297. X#ifdef vms
  298. X#  define  getenv(s)   get_symbol(s)
  299. X#  define  envfree(s)  (s) = ( !(s) ) ? CHARNULL : (free(s), CHARNULL)
  300. X#  include <descrip.h>
  301. X#  include <libdef.h>
  302. X
  303. X#  define  MAXLEN 255
  304. X
  305. X   /***************************************************************************
  306. X   ** ^FUNCTION: get_symbol - retrieve the value of a VMS symbol
  307. X   **
  308. X   ** ^SYNOPSIS:
  309. X   */
  310. X#  ifndef __ANSI_C__
  311. X      char *get_symbol( sym_name )
  312. X   /*
  313. X   ** ^PARAMETERS:
  314. X   */
  315. X      char *sym_name;
  316. X   /*    -- name of the symbol to retrieve
  317. X   */
  318. X#  endif  /* !__ANSI_C__ */
  319. X
  320. X   /* ^DESCRIPTION:
  321. X   **    Get_symbol will lookup the named symbol and return its value
  322. X   **    as a string.
  323. X   **
  324. X   ** ^REQUIREMENTS:
  325. X   **    sym_name should correspond to the name of a pre-defined symbol.
  326. X   **
  327. X   ** ^SIDE-EFFECTS:
  328. X   **    None.
  329. X   **
  330. X   ** ^RETURN-VALUE:
  331. X   **    NULL if the symbol is not found, otherwise it copies the symbol
  332. X   **    value and returns the address of the copy (which may later be
  333. X   **    deallocated using free()).
  334. X   **
  335. X   ** ^ACKNOWLEDGEMENTS:
  336. X   **    Thanx to Jim Barbour for writing most of this code. --BDA
  337. X   **
  338. X   ** ^ALGORITHM:
  339. X   **    Trivial - just use the LIB$GET_SYMBOL system service.
  340. X   ***^^**********************************************************************/
  341. X#  ifdef __ANSI_C__
  342. X      char *get_symbol( const char *sym_name )
  343. X#  endif
  344. X   {
  345. X      unsigned long stat, lib$get_symbol();
  346. X      unsigned short buflen;
  347. X      char sym_value[ MAXLEN ];
  348. X      $DESCRIPTOR( sym_name_d, sym_name );
  349. X      $DESCRIPTOR( sym_value_d, sym_value );
  350. X
  351. X      sym_value_d.dsc$w_length =  MAXLEN;
  352. X      sym_name_d.dsc$w_length = strlen( sym_name );
  353. X      stat = lib$get_symbol( &sym_name_d, &sym_value_d, &buflen, (void *)0 );
  354. X      if ( stat == LIB$_NOSUCHSYM ) {
  355. X         return  CHARNULL;
  356. X      }
  357. X      else if ( ! (stat & 1) ) {
  358. X         exit(stat);
  359. X      }
  360. X      sym_value[ buflen ] = '\0';
  361. X      return  strdup( sym_value );
  362. X   }
  363. X#endif /* vms */
  364. X
  365. X
  366. X/***************************************************************************
  367. X** ^FUNCTION: is_interactive - determine if a stream is "interactive"
  368. X**
  369. X** ^SYNOPSIS:
  370. X*/
  371. X#ifndef __ANSI_C__
  372. X   static BOOL is_interactive( fd )
  373. X/*
  374. X** ^PARAMETERS:
  375. X*/
  376. X   int fd;
  377. X/*    -- file descriptor associated with the input stream
  378. X*/
  379. X#endif  /* !__ANSI_C__ */
  380. X
  381. X/* ^DESCRIPTION:
  382. X**    Is_interactive determines whether or not the given i/o stream is
  383. X**    associated with a terminal.
  384. X**
  385. X** ^REQUIREMENTS:
  386. X**    Fd must correspond to a valid, open, file-descriptor.
  387. X**
  388. X** ^SIDE-EFFECTS:
  389. X**    None.
  390. X**
  391. X** ^RETURN-VALUE:
  392. X**    TRUE if fd is associated with a terminal, FALSE otherwise.
  393. X**
  394. X** ^ALGORITHM:
  395. X**    Trivial - just use isatty and restore errno if necessary
  396. X***^^**********************************************************************/
  397. X#ifdef __ANSI_C__
  398. X   static BOOL is_interactive( int fd )
  399. X#endif
  400. X{
  401. X#ifdef unix
  402. X   EXTERN int isatty  ARGS((int));
  403. X   extern int errno;
  404. X   int saverr = errno;  /* save errno */
  405. X
  406. X   if ( isatty(fd) )
  407. X      return  TRUE;
  408. X   else {
  409. X      errno = saverr;
  410. X      return  FALSE;
  411. X   }
  412. X#else
  413. X#ifdef vms
  414. X   EXTERN int isatty  ARGS((int));
  415. X   int ret = isatty( fd );
  416. X
  417. X   if ( ret == -1 ) /* error with fd */
  418. X      syserr( "error on file descriptor #%d", fd );
  419. X   else if ( ret )
  420. X      return  TRUE;
  421. X   else
  422. X      return  FALSE;
  423. X#else
  424. X   return  TRUE;
  425. X#endif
  426. X#endif
  427. X}
  428. X
  429. X
  430. X/***************************************************************************
  431. X** ^FUNCTION: init_args - Initialize the command object
  432. X**
  433. X** ^SYNOPSIS:
  434. X*/
  435. X#ifndef __ANSI_C__
  436. X   VOID init_args( argd )
  437. X/*
  438. X** ^PARAMETERS:
  439. X*/
  440. X   ARGDESC argd[];
  441. X/*    -- the array of command-arguments to initialize.
  442. X*/
  443. X#endif  /* !__ANSI_C__ */
  444. X
  445. X/* ^DESCRIPTION:
  446. X**    Init_args performs all the actions that are required to prepare an
  447. X**    argdesc-array for use by any of the parseargs functions. Storrage
  448. X**    is allocated and initialized and argument descriptions are compiled.
  449. X**
  450. X** ^REQUIREMENTS:
  451. X**    <argd> must point to an array that has been declared using the CMD_XXXX
  452. X**    macros, or using the ENDOFARGS (and optionally STARTOFARGS) macro.
  453. X**
  454. X** ^SIDE-EFFECTS:
  455. X**    The argd is initialized for use.
  456. X**
  457. X** ^RETURN-VALUE:
  458. X**    None.
  459. X**
  460. X** ^ALGORITHM:
  461. X**    - compile the command name, purpose, and description if they were given
  462. X**    - if ENDOFARGS was used without STARTOFARGS, then shift each item in
  463. X**      the array down by one position.
  464. X**    - initialize the parse-flags to the default settings
  465. X**    - initialize the default argument search-list
  466. X**    - allocate and initialize the command-context
  467. X**    - for each command-line argument in argd
  468. X**      - compile the ad_prompt field and set the default initial ARGXXX flags
  469. X**      end-for
  470. X***^^**********************************************************************/
  471. X#ifdef __ANSI_C__
  472. X   void init_args( ARGDESC argd[] )
  473. X#endif
  474. X{
  475. X   register ARGDESC *ad, *anchor;
  476. X   int  ad_count = 0;
  477. X   BOOL old_style = FALSE;
  478. X   char *description = CHARNULL, *purpose = CHARNULL;
  479. X   int  desclen;
  480. X
  481. X   if ( !argd )  return;
  482. X
  483. X      /* dont initialize if its already been done */
  484. X   if ( CMD_isINIT(argd) )  return;
  485. X
  486. X   if ( !ARG_isEND(argd) )  old_style = TRUE;
  487. X
  488. X      /* determine the argument count and preprocess each ad-entry */
  489. X   anchor = ( old_style ) ? argd : ARG_FIRST(argd);
  490. X   for ( ad = anchor ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) )  {
  491. X      ad_count++;
  492. X
  493. X         /* set-up any positional args that we know of */
  494. X      if ( ARG_isPOSONLY(ad) )  BSET( arg_flags(ad), ARGPOS );
  495. X
  496. X         /* set-up any default ARGNOVALs that we know of */
  497. X      if (ARG_isBOOLEAN(ad) || ARG_isPSEUDOARG(ad))
  498. X         BSET( arg_flags(ad), ARGNOVAL );
  499. X
  500. X      if ( get_argdesc( (char *)arg_sname(ad), &desclen ) )
  501. X         BSET(arg_flags(ad), ARGDESCRIBED);
  502. X   }
  503. X
  504. X      /* shift all the entries down one to make room for a new 1st-entry
  505. X      ** It would've been nice to just swap the 1st and last entries but
  506. X      ** I have to preserve the order that all positional parameters are
  507. X      ** given in.
  508. X      */
  509. X   if ( old_style  &&  ad_count > 0 ) {
  510. X      anchor = ad + 1;  /* save this position */
  511. X      for ( ; ad > argd ; ARG_RETREAT(ad) ) {
  512. X         memcpy( (ARBPTR)ad, (ARBPTR)(ad - 1), sizeof(ARGDESC) );
  513. X      }/*for*/
  514. X      memcpy( (ARBPTR)argd, (ARBPTR)anchor, sizeof(ARGDESC) );
  515. X   }
  516. X   else  anchor = ad;
  517. X
  518. X     /* set default parse-flags */
  519. X#ifndef ibm_style
  520. X   cmd_flags(argd) = pa_DEFAULTS;
  521. X#else
  522. X   {
  523. X      char *pfx = getenv( "SWITCHAR" );
  524. X      if ( pfx  &&  *pfx == '-' )
  525. X         cmd_flags(argd) = pa_FLAGS1ST;
  526. X      else
  527. X         cmd_flags(argd) = pa_DEFAULTS;
  528. X   }
  529. X#endif
  530. X
  531. X   if ( cmd_name(argd) )  cmd_name(argd) = strdup( cmd_name(argd) );
  532. X     /* if new-style, get the purpose from the command name */
  533. X   if ( !old_style  &&  cmd_name(argd) ) {
  534. X      purpose = cmd_name(argd);
  535. X   }
  536. X
  537. X      /* set the program name */
  538. X   if ( ProgName  &&  *ProgName  &&  !cmd_name(argd) ) {
  539. X      cmd_name(argd) = ProgName;
  540. X   }
  541. X
  542. X      /* set context */
  543. X   if ( !cmd_context(argd) )  {
  544. X      cmd_context(argd)  = (CTXDESC *) anchor;
  545. X      cmd_state(argd)    = ( old_style ) ? ps_OLDSTYLE : (ps_flags_t) 0;
  546. X      cmd_argv0(argd)    = cmd_name(argd);
  547. X      cmd_purpose(argd)  = purpose;
  548. X      cmd_ptrs(argd) = (ARGDPTRS *)malloc( sizeof(ARGDPTRS) );
  549. X      if ( !cmd_ptrs(argd) ) {
  550. X         syserr( "malloc failed in init_args()" );
  551. X      }
  552. X      if ( argd == Default_ArgDesc ) {
  553. X         cmd_defargs(argd)  = ARGDESCNULL;
  554. X      }
  555. X      else {
  556. X         if ( !CMD_isINIT(Default_ArgDesc) )  init_args( Default_ArgDesc );
  557. X         cmd_defargs(argd)  = Default_ArgDesc;
  558. X      }
  559. X      cmd_list(argd) = ARGDESCNULL;
  560. X#ifdef amiga_style
  561. X      cmd_prev(argd) = ARGDESCNULL;
  562. X#endif
  563. X   }
  564. X}
  565. X
  566. X
  567. X/***************************************************************************
  568. X** ^FUNCTION: reset_args - (re)set a command for parsing
  569. X**
  570. X** ^SYNOPSIS:
  571. X*/
  572. X#ifndef __ANSI_C__
  573. X   static VOID reset_args( argd )
  574. X/*
  575. X** ^PARAMETERS:
  576. X*/
  577. X   ARGDESC argd[];
  578. X/*    -- array or command-line arguments to be reset
  579. X*/
  580. X#endif  /* !__ANSI_C__ */
  581. X
  582. X/* ^DESCRIPTION:
  583. X**    Reset_args will prepare a command for parsing. The command-state is
  584. X**    initialized and each argument is reset to "unmatched".
  585. X**
  586. X** ^REQUIREMENTS:
  587. X**    <argd> must point to an array that has been declared using the CMD_XXXX
  588. X**    macros, or using the ENDOFARGS (and optionally STARTOFARGS) macro.
  589. X**
  590. X** ^SIDE-EFFECTS:
  591. X**    resets the ARG flags of each argument and the command-state of argd.
  592. X**
  593. X** ^RETURN-VALUE:
  594. X**    None.
  595. X**
  596. X** ^ALGORITHM:
  597. X**    - reset the command-context to be (as of yet) unparsed
  598. X**    - reset the ARG flags of the programmer & default argument descriptors
  599. X***^^**********************************************************************/
  600. X
  601. X   /* arg-flags to be reset before parsing a new command-line */
  602. X#define  ARGDEFAULTS  ( ARGGIVEN | ARGVALGIVEN | ARGKEYWORD | ARGVALSEP )
  603. X
  604. X#ifdef __ANSI_C__
  605. X   static void reset_args( ARGDESC argd[] )
  606. X#endif
  607. X{
  608. X   register ARGDESC *args, *ad;
  609. X
  610. X   if ( !CMD_isINIT(argd) )  init_args(argd);
  611. X
  612. X      /* reset the command context */
  613. X   BCLEAR( cmd_state(argd), (ps_NOFLAGS|ps_NOCMDENV|ps_NOPARSECNTL) );
  614. X   cmd_list(argd) = ARGDESCNULL;
  615. X#ifdef amiga_style
  616. X   cmd_prev(argd) = ARGDESCNULL; /* No argument requested */
  617. X#endif
  618. X
  619. X      /* clear out any cruft in the argument descriptors */
  620. X   for ( args = argd ; args ; args = cmd_defargs(args) ) {
  621. X      for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
  622. X         BCLEAR( arg_flags(ad), ARGDEFAULTS );
  623. X
  624. X#if ( defined(vms_style)  ||  defined(amiga_style) )
  625. X            /* vms and amiga use keywords only */
  626. X         BSET( arg_flags(ad), ARGKEYWORD );
  627. X#endif
  628. X      }/*for*/
  629. X   }/*for*/
  630. X}
  631. X
  632. X#undef ARGDEFAULTS
  633. X
  634. X
  635. X/***************************************************************************
  636. X** ^FUNCTION: prompt_user - prompt the user for a missing argument
  637. X**
  638. X** ^SYNOPSIS:
  639. X*/
  640. X#ifndef __ANSI_C__
  641. X   static BOOL prompt_user( ad, argname )
  642. X/*
  643. X** ^PARAMETERS:
  644. X*/
  645. X   ARGDESC *ad;
  646. X/*    -- pointer to the argument to be supplied by the user
  647. X*/
  648. X   char *argname;
  649. X/*    -- name of the argument to be supplied by the user
  650. X*/
  651. X#endif  /* !__ANSI_C__ */
  652. X
  653. X/* ^DESCRIPTION:
  654. X**    Prompt_user will attempt to prompt the user to supply (on standard input)
  655. X**    the value for the given argument. If the argument is a list, then each
  656. X**    item of the list should be given on a separate line (with a blank line
  657. X**    terminating the list).
  658. X**
  659. X**    No special "escaping" or translation is performed on the resulting user
  660. X**    input, hence any whitespace ro quotes will be considered as part of the
  661. X**    argument value.
  662. X**
  663. X**    If stdin is NOT associated with a terminal then no prompting is performed
  664. X**    and FALSE is returned.  If the user enters in invalid value for the
  665. X**    argument then the value is discarded and FALSE is returned (so you
  666. X**    better get it right the first time).
  667. X**
  668. X** ^REQUIREMENTS:
  669. X**    Only the first 255 characters of user input is used.
  670. X**
  671. X** ^SIDE-EFFECTS:
  672. X**    Modifies <ad> accordingly.
  673. X**
  674. X** ^RETURN-VALUE:
  675. X**    FALSE if there is an error, TRUE otherwise.
  676. X**
  677. X** ^ALGORITHM:
  678. X**    - if stdin is not connected to a terminal return FALSE
  679. X**    - if argument is not a list then
  680. X**      - get string from user
  681. X**      - attempt to convert the string
  682. X**      - return TRUE upon success and FALSE upon failure
  683. X**    - else (the argument is a list)
  684. X**      - while (user has not entered a blank line) do
  685. X**        - get string from user
  686. X**        - attempt to convert the string
  687. X**        - return FALSE upon failure (otherwise continue to loop)
  688. X**        end-while
  689. X**      end-if
  690. X***^^**********************************************************************/
  691. X#ifdef __ANSI_C__
  692. X   static BOOL prompt_user( ARGDESC *ad, const char *argname )
  693. X#endif
  694. X{
  695. X   BOOL  error = FALSE, first = TRUE;
  696. X   int   end;
  697. X   char  buf[ MAXLINE ];
  698. X
  699. X   if ( !is_interactive(STDIN) )  return  FALSE;
  700. X
  701. X   if ( ARG_isMULTIVAL(ad) ) {
  702. X      fprintf(stderr, "Enter one %s per-line ", argname);
  703. X      fprintf(stderr, "(enter a blank line to stop).\n");
  704. X   }
  705. X
  706. X   do {  /* need repeated prompting for an ARGLIST or an ARGVEC */
  707. X      /* get argument from user */
  708. X      *buf='\0';
  709. X#ifdef vms_style
  710. X      fprintf(stderr, "\r%s> ", argname);
  711. X#else
  712. X      fprintf(stderr, "\rEnter %s: ", argname);
  713. X#endif
  714. X      fflush( stderr );
  715. X      if ( !fgets(buf, MAXLINE, stdin) )  *buf = '\0';
  716. X
  717. X      /* discard the newline */
  718. X      end = strlen(buf) - 1;
  719. X      if ( end >= 0  &&  buf[end] == '\n' )
  720. X         buf[ end ] = '\0';
  721. X
  722. X      /* make sure we read something! */
  723. X      if ( *buf == '\0' ) {
  724. X         if ( first ) {
  725. X            usrerr( "error - no %s given", argname );
  726. X            error = TRUE;
  727. X         }
  728. X         continue;
  729. X      }
  730. X
  731. X      /* try to convert what we read (remember - buf is transient) */
  732. X      if (  (*arg_type(ad))(ad, buf, TRUE) )
  733. X         BSET(arg_flags(ad), ARGGIVEN | ARGVALGIVEN);
  734. X      else
  735. X         error = TRUE;
  736. X
  737. X      first = FALSE;
  738. X   } while ( !error &&  ARG_isMULTIVAL(ad)  &&  *buf );
  739. X
  740. X   return  (error) ? FALSE : TRUE;
  741. X}
  742. X
  743. X
  744. X/***************************************************************************
  745. X** ^FUNCTION: verify_argreqs - check for any missing required arguments
  746. X**
  747. X** ^SYNOPSIS:
  748. X*/
  749. X#ifndef __ANSI_C__
  750. X   static BOOL verify_argreqs( cmd, parse_status )
  751. X/*
  752. X** ^PARAMETERS:
  753. X*/
  754. X   ARGDESC *cmd;
  755. X/*    -- the argdesc-array of command-line arguments.
  756. X*/
  757. X   int *parse_status;
  758. X/*    -- address of current parse_status
  759. X*/
  760. X#endif  /* !__ANSI_C__ */
  761. X
  762. X/* ^DESCRIPTION:
  763. X**    Verify_argreqs will reset parse_status to a success-value if it 
  764. X**    previously indicated a syntax error but pa_IGNORE is set to ignore
  765. X**    syntax error.  Verify_argreqs will then verify that any required
  766. X**    command-line arguments have been supplied (if they were not and
  767. X**    pa_PROMPT is set, then the missing values will be prompted for).
  768. X**
  769. X** ^REQUIREMENTS:
  770. X**    <cmd> must point to an array that has been declared using the CMD_XXXX
  771. X**    macros, or using the ENDOFARGS (and optionally STARTOFARGS) macro.
  772. X**
  773. X**    parse_status should be a pointer to the result of a previous call to
  774. X**    {f,l,s,v,}parseargs.
  775. X**
  776. X** ^SIDE-EFFECTS:
  777. X**    The arg-descs for missing arguments may be modified by prompt_user.
  778. X**    parse_status will be modified to indicate whether or not a syntax
  779. X**    error really has occurred (it will be pe_SUCCESS if all is hunky-dory).
  780. X**
  781. X** ^RETURN-VALUE:
  782. X**    FALSE if there is an error, TRUE otherwise.
  783. X**
  784. X** ^ALGORITHM:
  785. X**    - if parse_status is a syntax error but pa_IGNORE is set
  786. X**      - ignore the error by resetting the status to pe_SUCCESS
  787. X**      end-if
  788. X**    - if pa_NOCHECK is not set then check for any missing required
  789. X**      arguments (using prompt_user to get the values if pa_PROMPT is set).
  790. X***^^**********************************************************************/
  791. X#ifdef __ANSI_C__
  792. X   static BOOL verify_argreqs( ARGDESC *cmd, int *parse_status )
  793. X#endif
  794. X{
  795. X   register ARGDESC *ad;
  796. X   BOOL error;
  797. X   argName_t  s;
  798. X
  799. X   if ( !CMD_isINIT(cmd) )  init_args(cmd);
  800. X
  801. X   if ( *parse_status == pe_SYNTAX  &&  BTEST(cmd_flags(cmd), pa_IGNORE) ) {
  802. X      *parse_status = pe_SUCCESS;
  803. X   }
  804. X   error = ( *parse_status != pe_SUCCESS ) ? TRUE : FALSE;
  805. X
  806. X   if ( !BTEST(cmd_flags(cmd), pa_NOCHECK) ) {
  807. X      for (ad = ARG_FIRST(cmd) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad)) {
  808. X         if (arg_type(ad) == argDummy)  continue;
  809. X
  810. X         if ( ARG_isREQUIRED(ad)  &&  !ARG_isGIVEN(ad) ) {
  811. X               /* still didn't get a value... sigh */
  812. X            if ( ARG_isPOSITIONAL(ad) ) {
  813. X               (VOID) get_argname( arg_sname(ad), s );
  814. X               usrerr("%s required", s);
  815. X            }
  816. X            else {
  817. X#ifdef amiga_style
  818. X               (VOID) get_kwdname( arg_sname(ad), s );
  819. X               usrerr("argument required for %s keyword", s);
  820. X#endif
  821. X#ifdef ibm_style
  822. X               (VOID) get_argname( arg_sname(ad), s );
  823. X               {
  824. X                  char c, *pfx = getenv( "SWITCHAR" );
  825. X                  c = ( pfx &&  *pfx ) ? *pfx : '/';
  826. X                  usrerr("%s required for %c%c switch", s, c, arg_cname(ad));
  827. X               }
  828. X#endif
  829. X#ifdef unix_style
  830. X               (VOID) get_argname( arg_sname(ad), s );
  831. X               usrerr("%s required for %c%c flag", s, c_OPT_PFX, arg_cname(ad));
  832. X#endif
  833. X#ifdef vms_style
  834. X               (VOID) get_kwdname( arg_sname(ad), s );
  835. X               usrerr("value required for %c%s qualifier", *s_KWD_PFX, s);
  836. X#endif
  837. X            }
  838. X
  839. X            if ( !error  &&  BTEST(cmd_flags(cmd), pa_PROMPT) ) {
  840. X               if ( !prompt_user(ad, s) )  error = TRUE;
  841. X            }
  842. X            else if ( !error ) {
  843. X               error = TRUE;
  844. X            }
  845. X         }/*if*/
  846. X      }/*for*/
  847. X   }/*if*/
  848. X
  849. X   return  (error) ? FALSE : TRUE;
  850. X}
  851. X
  852. X
  853. X/***************************************************************************
  854. X** ^FUNCTION: read_flags - read bitmask-flags in a string
  855. X**
  856. X** ^SYNOPSIS:
  857. X*/
  858. X#ifndef __ANSI_C__
  859. X   static argMask_t read_flags( str, c_tbl, m_tbl )
  860. X/*
  861. X** ^PARAMETERS:
  862. X*/
  863. X   char *str;
  864. X/*    -- the string to parse
  865. X*/
  866. X   char c_tbl[];
  867. X/*    -- a (NUL-terminated) array of alpha-numeric characters Each character
  868. X**    is the first letter/number of a token.  If the character is lowercase,
  869. X**    then the corresponding mask is set, if it is uppercase, the corresponding
  870. X**    mask is cleared.
  871. X*/
  872. X   argMask_t m_tbl[];
  873. X/*    -- a table of bitmasks for the given character-table. The mask to use
  874. X**       for c_tbl[i] is m_tbl[i].
  875. X*/
  876. X#endif  /* !__ANSI_C__ */
  877. X
  878. X/* ^DESCRIPTION:
  879. X**    Read_flags will parse the given string for any flags present in c_tbl[].
  880. X**    When a flag is matched, its corresponding entry in m_tbl[] is set (or
  881. X**    cleared) in the currently matched set of flags.
  882. X**
  883. X**    When the given string has been completely scanned, the resulting
  884. X**    combination of masks that were matched is returned.
  885. X**
  886. X** ^REQUIREMENTS:
  887. X**    A '\0' or a ';' indicates the end of parsing. A token/mask may be negated
  888. X**    by preceding it with one of '!', '^', or '~'. Tokens must be separated by
  889. X**    one or more non-alphanumerics (other than '!', '~', and '^').
  890. X**
  891. X** ^SIDE-EFFECTS:
  892. X**    None.
  893. X**
  894. X** ^RETURN-VALUE:
  895. X**    The combination of bitmasks indicated by the given string.
  896. X**
  897. X** ^ALGORITHM:
  898. X**    - set masks = 0
  899. X**    - for each "token" in str
  900. X**      - if token doesnt match any entries in c_tbl then continue
  901. X**      - let i = index of matched token in c_tbl
  902. X**      - if c_tbl[i] is lowercase then OR masks with m_tbl[i]
  903. X**      - if c_tbl[i] is uppercase then AND masks with NOT(m_tbl[i])
  904. X**      end-for
  905. X**    - return masks
  906. X***^^**********************************************************************/
  907. X
  908. X      /* macros for parsing flags */
  909. X#define  IS_NEGCHAR(c)  ( c == '!' || c == '^' || c == '~' )
  910. X#define  SKIP_TOK(s)    while ( isalnum(*s) || *s == '_' || *s == '-' ) s++
  911. X#define  SKIP_SEP(s)    while ( *s && !IS_NEGCHAR(*s) && !isalnum(*s) ) s++
  912. X#define  NEXT_TOK(s)    SKIP_TOK(s) ; SKIP_SEP(s)
  913. X#define  TOGGLE(x)      x = (x) ? FALSE : TRUE
  914. X
  915. X#ifdef __ANSI_C__
  916. X   static argMask_t read_flags(
  917. X      const char *str, const char c_tbl[], const argMask_t m_tbl[]
  918. X   )
  919. X#endif
  920. X{
  921. X   char *pos = CHARNULL;
  922. X   BOOL  negated = FALSE;
  923. X   argMask_t  mask = 0, flags = 0;
  924. X
  925. X   while ( *str  &&  *str != ';' ) {
  926. X      mask = 0;
  927. X      negated = FALSE;
  928. X
  929. X      while ( IS_NEGCHAR(*str) ) {
  930. X         TOGGLE(negated);
  931. X         ++str;
  932. X         SKIP_SEP(str);
  933. X      }
  934. X
  935. X      if ( (pos = strchr( c_tbl, TOLOWER(*str) )) != CHARNULL ) {
  936. X         mask = m_tbl[ (int)(pos - (char *)c_tbl) ];
  937. X      }
  938. X      else if ( (pos = strchr( c_tbl, TOUPPER(*str) )) != CHARNULL ) {
  939. X         TOGGLE(negated);
  940. X         mask = m_tbl[ (int)(pos - (char *)c_tbl) ];
  941. X      }
  942. X      else {
  943. X         negated = FALSE;
  944. X      }
  945. X
  946. X      NEXT_TOK(str);
  947. X
  948. X      if ( mask || negated ) {
  949. X         if   (   negated  )  BCLEAR(flags, mask);
  950. X         else /* !negated */  BSET(flags, mask);
  951. X      }/*if*/
  952. X   }/*while*/
  953. X
  954. X   return  flags;
  955. X}
  956. X
  957. X#undef  IS_NEGCHAR
  958. X#undef  SKIP_TOK
  959. X#undef  SKIP_SEP
  960. X#undef  NEXT_TOK
  961. X#undef  TOGGLE
  962. X
  963. X
  964. X/***************************************************************************
  965. X** ^FUNCTION: get_usage_flags - determine user-defined usage-message format
  966. X**
  967. X** ^SYNOPSIS:
  968. X*/
  969. X#ifndef __ANSI_C__
  970. X   static argMask_t get_usage_flags( cmd )
  971. X/*
  972. X** ^PARAMETERS:
  973. X*/
  974. X   ARGDESC *cmd;
  975. X/*    -- command-structure to determine usage-flags for
  976. X*/
  977. X#endif  /* !__ANSI_C__ */
  978. X
  979. X/* ^DESCRIPTION:
  980. X**    Through the use of an environment variable (or a VMS symbol), the user
  981. X**    may control the syntax and the verbosity of the command-usage messages
  982. X**    that are printed by parseargs. The desired level of verbosity may be
  983. X**    set by defining the environment variable "USAGECNTL" to be a com-
  984. X**    bination of strings (case insensitive). The value of each string con-
  985. X**    trols one of three different "modes" of behavior in the displaying
  986. X**    of usage messages:  The first "mode" is "verbose" mode, which con-
  987. X**    trols whether or not a detailed description of each argument should
  988. X**    accompany the usual command-line sysnopsis. If verbose mode is
  989. X**    "off", then only a command-line synopsis is printed (this is also
  990. X**    refferred to as "terse" mode). The other two "modes" control the
  991. X**    displaying of option syntax and long-option syntax. A mode may be
  992. X**    explicitly disabled by preceding its corresponding string with the `!'
  993. X**    or `-' character. The "modes" which correspond to the possible values of
  994. X**    the "USAGECNTL" environment variable are given by the following table.
  995. X**
  996. X**    "Quiet"
  997. X**       No usage message of any kind is displayed.
  998. X**
  999. X**    "Silent"
  1000. X**       Same as Quiet.
  1001. X**
  1002. X**    "Paged"
  1003. X**       The usage message is piped to a pager. The pager used is named by
  1004. X**       the "USAGE_PAGER" environment variable. If this variable is unset
  1005. X**       or empty (or is not the name of an executable program), the pager
  1006. X**       named by the "PAGER" environment variable us used.  If this variable
  1007. X**       is unset or empty (or is not the name of an executable program) then
  1008. X**       the program "/usr/ucb/more" is used.
  1009. X**
  1010. X**    "Description"
  1011. X**       The command description is printed.
  1012. X**
  1013. X**    "Terse"
  1014. X**       Terse mode, just print command-line synopsis.
  1015. X**
  1016. X**    "Verbose"
  1017. X**       Verbose mode, print descriptions for each argument
  1018. X**
  1019. X**    "Options"
  1020. X**       Option syntax is displayed.
  1021. X**
  1022. X**    "LongOpts"
  1023. X**       Long-option syntax is displayed.
  1024. X**
  1025. X**    "KeyWords"
  1026. X**       Same as "LongOpts".
  1027. X**
  1028. X**    If the environment variable "USAGECNTL" is empty or undefined, then
  1029. X**    the default usage level (which is presently "Verbose + Options")
  1030. X**    will be used.
  1031. X**
  1032. X** ^REQUIREMENTS:
  1033. X**    <cmd> must point to an array that has been declared using the CMD_XXXX
  1034. X**    macros, or using the ENDOFARGS (and optionally STARTOFARGS) macro.
  1035. X**
  1036. X** ^SIDE-EFFECTS:
  1037. X**    None.
  1038. X**
  1039. X** ^RETURN-VALUE:
  1040. X**    The usage-flags corresponding to the value of $USAGECNTL
  1041. X**
  1042. X** ^ALGORITHM:
  1043. X**    - If $USAGECNTL is NULL or empty, return the default flags
  1044. X**    - get the value of $USAGECNTL and call read_flags to parse it.
  1045. X**    - return the resulting flags.
  1046. X***^^**********************************************************************/
  1047. X#ifdef __ANSI_C__
  1048. X   static argMask_t get_usage_flags( const ARGDESC *cmd )
  1049. X#endif
  1050. X{
  1051. X   register  char  *usage_env;
  1052. X   argMask_t  usg_ctl = 0;
  1053. X   static CONST char  usage_tokens[] = {
  1054. X      'n', 'q', 's',
  1055. X      'T', 'v',
  1056. X      'o',
  1057. X      'l', 'k',
  1058. X      'd',
  1059. X      'p',
  1060. X      '\0'
  1061. X   };
  1062. X   static CONST argMask_t  usage_masks[] = {
  1063. X      usg_NONE,     usg_NONE,     usg_NONE,
  1064. X      usg_VERBOSE,  usg_VERBOSE,
  1065. X      usg_OPTS,
  1066. X      usg_LONGOPTS, usg_LONGOPTS,
  1067. X      usg_DESCRIPTION,
  1068. X      usg_PAGED
  1069. X   };
  1070. X
  1071. X   usage_env = getenv("USAGECNTL");
  1072. X   if ( !usage_env ) {
  1073. X      usg_ctl = usg_VERBOSE;
  1074. X   }
  1075. X   else {
  1076. X      usg_ctl = read_flags( usage_env, usage_tokens, usage_masks );
  1077. X   }
  1078. X
  1079. X   envfree( usage_env );
  1080. X
  1081. X#ifdef unix_style
  1082. X      /* make sure we print at least one of options/keywords */
  1083. X   if ( !BTEST(usg_ctl, usg_OPTS|usg_LONGOPTS) ) {
  1084. X      if ( BTEST(cmd_flags(cmd), pa_KWDSONLY) ) {
  1085. X         BSET(usg_ctl, usg_LONGOPTS);
  1086. X      }
  1087. X      else {
  1088. X         BSET(usg_ctl, usg_OPTS);
  1089. X      }
  1090. X   }
  1091. X#endif /* unix_style */
  1092. X
  1093. X   return  usg_ctl;
  1094. X}
  1095. X
  1096. X
  1097. X#ifndef LITE
  1098. X
  1099. X/***************************************************************************
  1100. X** ^FUNCTION: get_parse_flags - determine user-defined parsing behavior
  1101. X**
  1102. X** ^SYNOPSIS:
  1103. X*/
  1104. X#ifndef __ANSI_C__
  1105. X   static VOID get_parse_flags( cmd )
  1106. X/*
  1107. X** ^PARAMETERS:
  1108. X*/
  1109. X   ARGDESC *cmd;
  1110. X/*    -- command-structure to determine parse-flags for
  1111. X*/
  1112. X#endif  /* !__ANSI_C__ */
  1113. X
  1114. X/* ^DESCRIPTION:
  1115. X**    The programmer may control parsing behavior through the use of
  1116. X**    parsecntl(3). The user may set this behavior through the use of the
  1117. X**    PARSECNTL environment variable.  By indicating any number of flags
  1118. X**    (possibly negated) the user will directly modify the behavior of the
  1119. X**    parseargs library. Flags may be combined by placing a `+' or `|'
  1120. X**    character in between flags. A switch is negated by immediately preceding
  1121. X**    it with a `!' or `-' character.  The possible "flags" are given by
  1122. X**    the following table. Flags are case-insensitive.
  1123. X**
  1124. X**    "Prompt"
  1125. X**       Prompt the user for any missing arguments that are required on the
  1126. X**       command-line. No special escaping or quoting is performed on the
  1127. X**       user input. Required arguments that expect a list of values will
  1128. X**       be repeatedly prompted for (one item per line) until a blank line
  1129. X**       (followed by a carriage return) is entered.
  1130. X**
  1131. X**    "Ignore"
  1132. X**       Ignore any unrecognized or improperly specified command-line arguments
  1133. X**       and continue execution of the program. Normally, if a required
  1134. X**       argument is unmatched (or an argument is improperly specified), a
  1135. X**       usage message is printed and program execution is terminated.
  1136. X**
  1137. X**    "OptsOnly"
  1138. X**       Under UNIX, setting this flag will disable the parsing of long-option
  1139. X**       syntax. This will cause all arguments starting with '+' to always be
  1140. X**       treated as a positional parameter (instead of a long-option).
  1141. X**
  1142. X**    "KwdsOnly"
  1143. X**       Under UNIX, setting this flag disables the parsing of single-character
  1144. X**       options.  This will cause all arguments starting with '-' to always be
  1145. X**       treated as a positional parameter (instead of an option).
  1146. X**
  1147. X**    "LoptsOnly"
  1148. X**       Same as KwdsOnly.
  1149. X**
  1150. X**    "Flags1st"
  1151. X**       Setting this flag causes the parseargs library to force any and all
  1152. X**       non-positional arguments to be specified before any positional ones.
  1153. X**       As an example, under UNIX, if this flag is SET then parseargs will
  1154. X**       consider the command line "cmd -x arg" to consist of one option and
  1155. X**       one positional argument; however the command line "cmd arg -x" would
  1156. X**       be considered to consist of two positional arguments (the -x option
  1157. X**       will be unmatched).
  1158. X**
  1159. X**       If this flag is UNSET, then both of the previous examples are
  1160. X**       considered to consist of one option and one positional argument.
  1161. X**
  1162. X**    "CaseIgnore"
  1163. X**       Setting this flag causes character-case to be ignored when attempting
  1164. X**       to match single-character argument names (i.e. causes "-i" and "-I"
  1165. X**       will be considered equivalent).
  1166. X**
  1167. X**    If the environment variable "PARSECNTL" is empty or undefined, then the
  1168. X**    parsing behavior set by the programmer is used.  If the programmer has
  1169. X**    not explicitly used parsecntl(3) to modify the parsing behavior, then
  1170. X**    the default behavior will be "Flags1st" for Unix Systems,
  1171. X**    "!Prompt + !Ignore" for AmigaDOS systems, "Prompt" for VMS systems,
  1172. X**    and "CaseIgnore" for MS-DOS and OS/2 systems.
  1173. X**
  1174. X** ^REQUIREMENTS:
  1175. X**    <cmd> must point to an array that has been declared using the CMD_XXXX
  1176. X**    macros, or using the ENDOFARGS (and optionally STARTOFARGS) macro.
  1177. X**
  1178. X** ^SIDE-EFFECTS:
  1179. X**    Modifies the parse-flags of <cmd> is $PARSECNTL is non-null & non-empty.
  1180. X**
  1181. X** ^RETURN-VALUE:
  1182. X**    None.
  1183. X**
  1184. X** ^ALGORITHM:
  1185. X**    - If $PARSECNTL is NULL or empty, return
  1186. X**    - Else turn off all flags that may be set by $PARSECNTL
  1187. X**    - get the value of $PARSECNTL and call read_flags to parse it.
  1188. X**    - set the returned flags in the cmd-structure.
  1189. X**    - return the resulting flags.
  1190. X***^^**********************************************************************/
  1191. X
  1192. X   /* the combination of parse-flags that may be set via $PARSECNTL */
  1193. X#define  pa_USRFLAGS \
  1194. X   (pa_PROMPT|pa_IGNORE|pa_ANYCASE|pa_OPTSONLY|pa_KWDSONLY|pa_FLAGS1ST)
  1195. X
  1196. X#ifdef __ANSI_C__
  1197. X   static void get_parse_flags( ARGDESC *cmd )
  1198. X#endif
  1199. X{
  1200. X   register argMask_t  flags = 0;
  1201. X   char *parse_env;
  1202. X   static CONST char  parse_tokens[] = {
  1203. X      'c',
  1204. X      'd',
  1205. X      'f',
  1206. X      'i',
  1207. X      'p',
  1208. X      'o',
  1209. X      'l','k',
  1210. X      '\0'
  1211. X   };
  1212. X   static CONST argMask_t  parse_masks[] = {
  1213. X      pa_ANYCASE,
  1214. X      pa_DEFAULTS,
  1215. X      pa_FLAGS1ST,
  1216. X      pa_IGNORE,
  1217. X      pa_PROMPT,
  1218. X      pa_OPTSONLY,
  1219. X      pa_KWDSONLY, pa_KWDSONLY
  1220. X   };
  1221. X
  1222. X   if ( !CMD_isINIT(cmd) )  init_args( cmd );
  1223. X
  1224. X   if ( (parse_env = getenv("PARSECNTL"))  &&  *parse_env ) {
  1225. X      flags = read_flags( parse_env, parse_tokens, parse_masks );
  1226. X
  1227. X         /*
  1228. X         ** mask off all the flags that may be set by $PARSECNTL
  1229. X         ** (including any default flags).
  1230. X         */
  1231. X      BCLEAR( cmd_flags(cmd), pa_USRFLAGS );
  1232. X
  1233. X      cmd_flags(cmd) |= flags;
  1234. X   }/*if*/
  1235. X
  1236. X   envfree( parse_env );
  1237. X}
  1238. X
  1239. X#undef  pa_USRFLAGS
  1240. X
  1241. X
  1242. X/***************************************************************************
  1243. X** ^FUNCTION: parse_user_defaults - parse user-supplied default arguments
  1244. X**
  1245. X** ^SYNOPSIS:
  1246. X*/
  1247. X#ifndef __ANSI_C__
  1248. X   static VOID parse_user_defaults( cmd )
  1249. X/*
  1250. X** ^PARAMETERS:
  1251. X*/
  1252. X   ARGDESC *cmd;
  1253. X/*    -- the command-line object to parse
  1254. X*/
  1255. X#endif  /* !__ANSI_C__ */
  1256. X
  1257. X/* ^DESCRIPTION:
  1258. X**    Programs that use parseargs may be given default arguments under
  1259. X**    Unix and PCs through the use of environment variables (symbols
  1260. X**    are used for VMS systems). If a  C-program or shell-script uses
  1261. X**    parseargs to implement a command named "cmd" then the environment
  1262. X**    variable CMD_ARGS will be parsed for any "default" arguments before
  1263. X**    the command-line is parsed.  The command-line will over-ride any
  1264. X**    options that are specified in this environment variable (except that
  1265. X**    ARGLISTs and ARGVECs set in "CMD_ARGS" will be appended from the
  1266. X**    command-line if they are selected).
  1267. X**
  1268. X**    It is important to note that the contents of the CMD_ARGS environ-
  1269. X**    ment variable are NOT expanded by the shell and hence any special
  1270. X**    characters (such as quotes or back-slashes) will NOT be escaped or
  1271. X**    removed by parseargs. Furthermore, it will not be possible to try and
  1272. X**    use a tab, space, or newline character in the environment variable as
  1273. X**    anything other than an argument separator.
  1274. X**
  1275. X**    Lastly, parts of an option specification in CMD_ARGS may NOT be
  1276. X**    continued on the command-line. As an example, if -f requires an
  1277. X**    argument and CMD_ARGS="-f", then the command-line "cmd  bah" will
  1278. X**    NOT assign "bah" as the argument to -f but will instead complain
  1279. X**    about a missing argument for -f. Similarly, if -l takes a list of
  1280. X**    arguments and CMD_ARGS="-l item1 item2", then the command-line
  1281. X**    "cmd  bah", will NOT assign "bah" to the end of the list containing
  1282. X**    "item1" and "item2" but will instead treat "bah" as the first
  1283. X**    positional parameter on the command-line.
  1284. X**
  1285. X** ^REQUIREMENTS:
  1286. X**    <cmd> should be an array of ARGDESCs declared using the CMD_XXXX macros
  1287. X**    or with the ENDOFARGS (and possible STARTOFARGS) macros.
  1288. X**
  1289. X** ^SIDE-EFFECTS:
  1290. X**    Any matched arguments have their ARGDESCs modified accordingly.
  1291. X**    Also, the command-state is changed to reflect the fact that the
  1292. X**    environment variable has been parsed. Also, after parsing the
  1293. X**    variable, the command is partially parsed. Hence the pa_CONTINUE
  1294. X**    is set to prevent arguments from being reset when the actual command
  1295. X**    line is parsed.
  1296. X**
  1297. X** ^RETURN-VALUE:
  1298. X**    None.
  1299. X**
  1300. X** ^ALGORITHM:
  1301. X**    - Get the value of the environment variable
  1302. X**    - if the variable is null or empty then return.
  1303. X**    - turn OFF the VARIABLE-NOT-YET-PARSED flag
  1304. X**    - turn on the NOCHECK flag so we dont check for missing required
  1305. X**      arguments in the variable (there may be more on the command-line).
  1306. X**    - parse the string and convert any arguments matched
  1307. X**    - set the NOCHECK flag back to its previous setting
  1308. X**    - set the CONTINUE flag since the command-line is now partially parsed.
  1309. X**    - return
  1310. X***^^**********************************************************************/
  1311. X
  1312. X#define  ENV_SUFFIX  "_ARGS"  /* suffix for env-variable with default args */
  1313. X
  1314. X#ifdef __ANSI_C__
  1315. X   static VOID parse_user_defaults( ARGDESC *cmd )
  1316. X#endif
  1317. X{
  1318. X   int  rc;
  1319. X   char      *env_args;
  1320. X   argName_t  env_name;
  1321. X   VOID usage();
  1322. X
  1323. X   if ( !CMD_isINIT(cmd) )  init_args( cmd );
  1324. X
  1325. X      /* if ignoring the <CMD>_ARGS variable then just return */
  1326. X   if ( BTEST(cmd_state(cmd), ps_NOCMDENV) )  return;
  1327. X
  1328. X      /* build the name of the environment variable */
  1329. X   strncpy( env_name, ProgName, ProgNameLen );
  1330. X   env_name[ProgNameLen] = 0;
  1331. X   (VOID) strupr( env_name );
  1332. X   strcat( env_name, ENV_SUFFIX );
  1333. X
  1334. X      /* get the value of the environment variable,
  1335. X      ** split it up into tokens, and parse it.
  1336. X      */
  1337. X   env_args = getenv(env_name);
  1338. X   if ( env_args ) {
  1339. X      char **argv = (char **)NULL;
  1340. X      char *env_val = strdup( env_args );
  1341. X      argMask_t  saveflags = cmd_flags(cmd);
  1342. X
  1343. X      BSET( cmd_flags(cmd), pa_NOCHECK | pa_ARGV0 | pa_COPYF );
  1344. X      BSET( cmd_state(cmd), ps_NOCMDENV );
  1345. X
  1346. X          /* split line up into whitespace separated tokens */
  1347. X      if ( !strsplit( &argv, env_val, CHARNULL ) ) {
  1348. X         free( argv );
  1349. X         return;
  1350. X      }
  1351. X
  1352. X#ifdef vms_style
  1353. X      BSET( cmd_state(cmd), ps_NOTCMDLINE );
  1354. X#endif
  1355. X
  1356. X      rc = parse_argv_style( argv, cmd );
  1357. X      free( argv );
  1358. X      cmd_list(cmd) = ARGDESCNULL;  /* dont allow lists to continue on */
  1359. X#ifdef amiga_style
  1360. X      cmd_prev(cmd) = ARGDESCNULL;
  1361. X#endif
  1362. X
  1363. X#ifdef vms_style
  1364. X      BCLEAR( cmd_state(cmd), ps_NOTCMDLINE );
  1365. X#endif
  1366. X
  1367. X         /* check for errors */
  1368. X      if ( rc  &&  !BTEST(cmd_flags(cmd), pa_IGNORE) ) {
  1369. X         eprintf( "%.*s: syntax-error in %s \"%s\".\n",
  1370. X                  ProgNameLen, ProgName, USER_VARIABLE, env_name );
  1371. X         eprintf( "\t%s = \"%s\"\n\n", env_name, env_args );
  1372. X         free( env_val );
  1373. X         usage( cmd );
  1374. X         exit( exit_SYNTAX );
  1375. X      }
  1376. X
  1377. X      free( env_val );
  1378. X      cmd_flags(cmd) = (saveflags | pa_CONTINUE);
  1379. X   }
  1380. X
  1381. X   envfree( env_args );
  1382. X}
  1383. X
  1384. X#undef ENV_SUFFIX
  1385. X
  1386. X#endif /* ! LITE */
  1387. X
  1388. X/***************************************************************************
  1389. X** ^FUNCTION: parse_init -- initialize an ARGDESC for parsing
  1390. X**
  1391. X** ^SYNOPSIS:
  1392. X*/
  1393. X#ifndef __ANSI_C__
  1394. X   static ARGDESC *parse_init( argdp )
  1395. X/*
  1396. X** ^PARAMETERS:
  1397. X*/
  1398. X   ARGDESC *argdp[];
  1399. X/*    -- pointer to the argument descriptor array.
  1400. X*/
  1401. X#endif  /* !__ANSI_C__ */
  1402. X
  1403. X/* ^DESCRIPTION:
  1404. X**    Parse_init will perform the usual pre-parsing actions such as checking
  1405. X**    $PARSECNTL, parsing $<NAME>_ARGS, and resetting the command-line.
  1406. X**
  1407. X** ^REQUIREMENTS:
  1408. X**    <argdp> should point to an array of ARGDESCs declared using the CMD_XXXX
  1409. X**    macros or with the ENDOFARGS (and possible STARTOFARGS) macros.
  1410. X**
  1411. X** ^SIDE-EFFECTS:
  1412. X**    Initialize argd and parses any default arguments.
  1413. X**
  1414. X** ^RETURN-VALUE:
  1415. X**    pointer to the arg-descriptors
  1416. X**
  1417. X** ^ALGORITHM:
  1418. X**    - check for a NULL argdesc-array
  1419. X**    - initialize the command-object if necessary
  1420. X**    - set ProgName
  1421. X**    - read $PARSECNTL
  1422. X**    - reset the command-line if necessary (and parse $<NAME>_ARGS)
  1423. X**    - return the command-object
  1424. X***^^**********************************************************************/
  1425. X#ifdef __ANSI_C__
  1426. X   static ARGDESC *parse_init( ARGDESC *argdp[] )
  1427. X#endif
  1428. X{
  1429. X   register ARGDESC *cmd;
  1430. X   BOOL  unnamed = FALSE;
  1431. X
  1432. X      /* allow null argument descriptor */
  1433. X   if ( !(*argdp) )  *argdp = Empty_ArgDesc;
  1434. X
  1435. X      /* initialize command-structure */
  1436. X   if ( !CMD_isINIT(*argdp) )  init_args( *argdp );
  1437. X   cmd = *argdp;
  1438. X
  1439. X      /* save the name of this program (for error messages) */
  1440. X   if ( cmd_argv0(cmd)  &&  *(cmd_argv0(cmd)) ) {
  1441. X      ProgName = cmd_argv0(cmd);
  1442. X      ProgNameLen = get_argpfx(ProgName);
  1443. X   }
  1444. X   else if ( cmd_name(cmd)  &&  *(cmd_name(cmd)) ) {
  1445. X      ProgName = cmd_name(cmd);
  1446. X      ProgNameLen = get_argpfx(ProgName);
  1447. X   }
  1448. X   else {
  1449. X      unnamed = TRUE;
  1450. X   }
  1451. X
  1452. X#ifndef LITE
  1453. X      /* read PARSECNTL environment variable */
  1454. X   if ( !BTEST(cmd_state(cmd), ps_NOPARSECNTL) ) {
  1455. X      get_parse_flags(*argdp);
  1456. X   }
  1457. X#endif
  1458. X
  1459. X      /* reset argd if necessary */
  1460. X   if ( !BTEST(cmd_flags(cmd), pa_CONTINUE) )  {
  1461. X      reset_args( *argdp );
  1462. X
  1463. X#ifndef LITE
  1464. X         /* get any options from <CMDNAME>_ARGS environment variable */
  1465. X      if ( !BTEST(cmd_flags(cmd), pa_NOCMDENV)  &&  !unnamed )  {
  1466. X         parse_user_defaults( *argdp );
  1467. X      }
  1468. X#endif
  1469. X   }
  1470. X
  1471. X   return  *argdp;
  1472. X}
  1473. X
  1474. X
  1475. X/***************************************************************************
  1476. X** ^FUNCTION: usage -- print a usage message
  1477. X**
  1478. X** ^SYNOPSIS:
  1479. X*/
  1480. X#ifndef __ANSI_C__
  1481. X   VOID usage( argd )
  1482. X/*
  1483. X** ^PARAMETERS:
  1484. X*/
  1485. X   ARGDESC argd[];
  1486. X/*    -- the description of expected arguments.
  1487. X*/
  1488. X#endif  /* !__ANSI_C__ */
  1489. X
  1490. X/* ^DESCRIPTION:
  1491. X**    Given an argdesc array, usage will print the usage for the given
  1492. X**    command in the format specified by the user's USAGECNTL environment
  1493. X**    variable.
  1494. X**
  1495. X** ^REQUIREMENTS:
  1496. X**    <argd> should be an array of ARGDESCs declared using the CMD_XXXX macros
  1497. X**    or with the ENDOFARGS (and possible STARTOFARGS) macros.
  1498. X**
  1499. X** ^SIDE-EFFECTS:
  1500. X**    Prints on stderr.
  1501. X**
  1502. X** ^RETURN-VALUE:
  1503. X**    None.
  1504. X**
  1505. X** ^ALGORITHM:
  1506. X**    - initialize the command-object
  1507. X**    - set ProgName
  1508. X**    - read $USAGECNTL
  1509. X**    - call <os>_usage()
  1510. X***^^**********************************************************************/
  1511. X#ifdef __ANSI_C__
  1512. X   void usage( const ARGDESC argd[] )
  1513. X#endif
  1514. X{
  1515. X   register CONST ARGDESC *cmd;
  1516. X   argMask_t  usg_ctl = 0;
  1517. X
  1518. X      /* allow null argument descriptor */
  1519. X   if ( !argd )  argd = Empty_ArgDesc;
  1520. X
  1521. X   if ( !CMD_isINIT(argd) )   init_args( (ARGDESC *)argd );
  1522. X   cmd = argd;
  1523. X
  1524. X   if ( cmd_argv0(cmd) && *(cmd_argv0(cmd)) ) {
  1525. X      ProgName = cmd_argv0(cmd);
  1526. X      ProgNameLen = get_argpfx(ProgName);
  1527. X   }
  1528. X   else if ( cmd_name(cmd) && *(cmd_name(cmd)) ) {
  1529. X      ProgName = cmd_name(cmd);
  1530. X      ProgNameLen = get_argpfx(ProgName);
  1531. X   }
  1532. X
  1533. X   usg_ctl = get_usage_flags(cmd);
  1534. X   if ( !BTEST(usg_ctl, usg_NONE) )  print_usage_style( argd, usg_ctl );
  1535. X}
  1536. X
  1537. X
  1538. X/***************************************************************************
  1539. X** ^FUNCTION: parsecntl - control various aspects of command-line parsing
  1540. X**
  1541. X** ^SYNOPSIS:
  1542. X*/
  1543. X#ifndef __ANSI_C__
  1544. X   int  parsecntl( argd, cntl, mode, va_alist )
  1545. X/*
  1546. X** ^PARAMETERS:
  1547. X*/
  1548. X   ARGDESC *argd;
  1549. X/*    --  The command-object to operate upon
  1550. X*/
  1551. X   parsecntl_t cntl;
  1552. X/*    --  The control-code corresponding to the desired operation
  1553. X*/
  1554. X   parsemode_t mode;
  1555. X/*    --  The mode of the operation (read, write, or both)
  1556. X*/
  1557. X   va_dcl
  1558. X/*    -- any further args followed by the item to be read/written
  1559. X*/
  1560. X#endif  /* !__ANSI_C__ */
  1561. X  
  1562. X/* ^DESCRIPTION:
  1563. X**    Parsecntl will read and/or write the desired attributes of the given
  1564. X**    command-object. The attributes to be operated upon are specified by
  1565. X**    the second parameter to parsecntl. The desired mode (read, write, or
  1566. X**    both) are specified by the third parameter to parsecntl. If the
  1567. X**    operation to be performed is pc_ARGFLAGS, then the fourth argument to
  1568. X**    parsecntl should be the keyword name of the argument whose flags are to
  1569. X**    be retrieved.  The last parameter to parsecntl is always the object to
  1570. X**    contain the attribute(s) to be read/written.  If the attribute(s) are
  1571. X**    to be read (regardless of whether or not they are also being changed)
  1572. X**    then the last argument should be a pointer to an object, otherwise the
  1573. X**    last argument should be the object itself.
  1574. X**
  1575. X**    If mode is pc_READ, then the desired attributes are copied into the
  1576. X**    object pointed to by the last parameter. If the mode is pc_WRITE, then
  1577. X**    the attributes from the last parameter are copied to the command-
  1578. X**    object. If mode is pc_RDWR, then the attributes pointed to by the last
  1579. X**    parameter are copied to the command-object, and then the previous
  1580. X**    value of these attributes (before they were overwritten) is copied
  1581. X**    into the object pointed to by the last parameter.
  1582. X**
  1583. X**    If cntl is pc_ARGFLAGS, then the only valid mode pc_READ. All other
  1584. X**    attributes may be written or read by parsecntl.
  1585. X**
  1586. X** ^REQUIREMENTS:
  1587. X**    If mode is READ or READ+WRITE then the last argument should be the
  1588. X**    address of the desired object, otherwise it should be the object itself.
  1589. X**
  1590. X** ^SIDE-EFFECTS:
  1591. X**    None if the mode is READ, otherwise, the desired attibutes are (re)set
  1592. X**
  1593. X** ^RETURN-VALUE:
  1594. X**    pe_SYSTEM
  1595. X**       -- If a system error occurred
  1596. X** 
  1597. X**    pe_SUCCESS
  1598. X**       -- success, no errors encountered.
  1599. X** 
  1600. X**    pe_DEFARGS
  1601. X**       -- an attempt (using parsecntl()) was made to change the
  1602. X**          default arg-search list of a command to point to an argdesc-array
  1603. X**          which already has the given command on its default arg-search list
  1604. X**          (which would cause an infinite loop when attempting to match an
  1605. X**          unknown command-line argument).
  1606. X** 
  1607. X**    pe_NOMATCH
  1608. X**       -- unable to match the named argument for the pc_ARGFLAGS cntl
  1609. X** 
  1610. X**    pe_BADMODE
  1611. X**       -- bad mode for given command in parsecntl()
  1612. X** 
  1613. X**    pe_BADCNTL
  1614. X**       -- bad command for parsecntl
  1615. X**
  1616. X** ^ALGORITHM:
  1617. X**    - if cntl is pc_ARGFLAGS
  1618. X**      - if mode is pc_WRITE or pc_RDWR then return pe_BADMODE
  1619. X**      - get the argument name and try to match it.
  1620. X**      - if no match, then return pe_NOMATCH
  1621. X**      - copy the flags for the matched argument
  1622. X**      - return pe_SUCCESS
  1623. X**    - else if cntl is pc_PARSEFLAGS
  1624. X**      - save the current parseflags.
  1625. X**      - if requested, (re)set the current flags
  1626. X**      - if requested, copy the old flags
  1627. X**      - return pe_SUCCESS
  1628. X**    - else if cntl is pc_DEFARGS
  1629. X**      - save the current default-args
  1630. X**      - make sure the given default-args does not already contain argd
  1631. X**      - if the above assertion failed, return pe_DEFARGS
  1632. X**      - if requested, (re)set the default-args
  1633. X**      - if requested, copy the old default-args
  1634. X**      - return pe_SUCCESS
  1635. X**    - else ( cntl must be in {pc_NAME, pc_PURPOSE, pc_DESCRIPTION} )
  1636. X**      - save the current setting of the attribute-string
  1637. X**      - if requested, (re)set the current attribute-string
  1638. X**      - if requested, copy the old attribute-string
  1639. X**      - return pe_SUCCESS
  1640. X**      endif
  1641. X***^^**********************************************************************/
  1642. X
  1643. X   /*
  1644. X   ** define some convenience macros to determine if we are
  1645. X   ** reading/writing from/to the argdesc-array.
  1646. X   */
  1647. X#define isREADING(pmode)  (pmode == pc_READ  || pmode == pc_RDWR)
  1648. X#define isWRITING(pmode)  (pmode == pc_WRITE || pmode == pc_RDWR)
  1649. X
  1650. X#ifdef __ANSI_C__
  1651. X   int parsecntl( ARGDESC *argd, parsecntl_t cntl, parsemode_t mode, ... )
  1652. X#endif
  1653. X{
  1654. X   register ARGDESC  *cmd;
  1655. X   register int  rc = pe_SUCCESS;
  1656. X   va_list   ap;
  1657. X
  1658. X   if ( !argd )   return   rc;
  1659. X   if ( !CMD_isINIT(argd) )   init_args(argd);
  1660. X   cmd = argd;
  1661. X   VA_START( ap, mode );   /* get argument to match */
  1662. X
  1663. X      /* now figure out what to do and go do it! */
  1664. X   switch( cntl ) {
  1665. X      case  pc_ARGFLAGS :  /* get/set arg-flags */
  1666. X         {
  1667. X            register ARGDESC *ad, *args;
  1668. X            char *name = VA_ARG( ap, char * );
  1669. X            argMask_t  *argflags;
  1670. X            BOOL  is_match = FALSE;
  1671. X
  1672. X               /* first we have to find the argument whose flags we need */
  1673. X            for (args = argd ; args  &&  !is_match ; args = cmd_defargs(args)) {
  1674. X               for (ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad)) {
  1675. X                  if ( arg_type(ad) == argDummy )  continue;
  1676. X
  1677. X                  if ( match(name, arg_sname(ad)) == 0 ) {
  1678. X                     is_match = TRUE;
  1679. X                     break;
  1680. X                  }/*if*/
  1681. X               }/*foreach arg*/
  1682. X            }/*foreach argdesc*/
  1683. X
  1684. X            if ( !is_match ) {
  1685. X               VA_END(ap);
  1686. X               return  pe_NOMATCH;
  1687. X            }
  1688. X
  1689. X               /* now that we found it - retrieve the argument flags */
  1690. X            if ( isREADING(mode) ) {
  1691. X              argflags = VA_ARG( ap, argMask_t * );
  1692. X              *argflags = arg_flags(ad);
  1693. X            }
  1694. X            else {
  1695. X              rc = pe_BADMODE;  /* parsecntl() wont set ARGFLAGS */
  1696. X            }
  1697. X         }/*block*/
  1698. X         break;
  1699. X
  1700. X      case  pc_PARSEFLAGS : /* get/set the parse-flags */
  1701. X         {
  1702. X            argMask_t *pflags, flags;
  1703. X
  1704. X               /* get value from call-stack (dependent on the mode) */
  1705. X            if ( isREADING(mode) ) {
  1706. X              pflags = VA_ARG( ap, argMask_t * );
  1707. X              flags = cmd_flags(cmd);
  1708. X            }
  1709. X            else {
  1710. X              flags = (argMask_t) VA_ARG( ap, int );
  1711. X              pflags = &flags;
  1712. X            }
  1713. X
  1714. X               /* perform the desired action(s) */
  1715. X            if ( isWRITING(mode) )  cmd_flags(cmd) = *pflags;
  1716. X            if ( isREADING(mode) )  *pflags = flags;
  1717. X         }/*block*/
  1718. X         break;
  1719. X
  1720. X      case  pc_DEFARGS : /* get/set the default arguments */
  1721. X         {
  1722. X            ARGDESC **pdefargd, *defargd;
  1723. X
  1724. X               /* get value from call-stack (dependent on the mode) */
  1725. X            if ( isREADING(mode) ) {
  1726. X               pdefargd = VA_ARG( ap, ARGDESC ** );
  1727. X               defargd = cmd_defargs(cmd);
  1728. X            }
  1729. X            else {
  1730. X               defargd = VA_ARG( ap, ARGDESC * );
  1731. X               pdefargd = &defargd;
  1732. X            }
  1733. X
  1734. X            if ( isWRITING(mode) ) {
  1735. X               ARGDESC *args;
  1736. X
  1737. X               if ( !CMD_isINIT(*pdefargd) )  init_args( *pdefargd );
  1738. X
  1739. X                  /* make sure we are not on the default-argdesc's
  1740. X                  ** default-argument hierarchy (or an infinite loop
  1741. X                  ** will result).
  1742. X                  */
  1743. X               for ( args = *pdefargd; rc && args; args = cmd_defargs(args) ) {
  1744. X                  if ( args == cmd )  rc = pe_DEFARGS;
  1745. X               }
  1746. X               if ( !rc )  cmd_defargs(cmd) = *pdefargd;  /* set new defaults */
  1747. X            }/*if*/
  1748. X
  1749. X            if ( isREADING(mode) )  *pdefargd = defargd;
  1750. X         }
  1751. X         break;
  1752. X
  1753. X      case  pc_NAME :  /* get/set name */
  1754. X      case  pc_PURPOSE :  /* get/set purpose */
  1755. X      case  pc_DESCRIPTION :  /* get/set description */
  1756. X         {
  1757. X            CONST char *str, **pstr;
  1758. X
  1759. X               /* get value from call-stack (dependent on the mode) */
  1760. X            if ( isREADING(mode) ) {
  1761. X               pstr = VA_ARG( ap, CONST char ** );
  1762. X               if      ( cntl == pc_NAME ) {
  1763. X                  if ( !BTEST(cmd_state(cmd), ps_USERNAME|ps_FREENAME) ) {
  1764. X                     if ( cmd_name(argd) ) {
  1765. X                        int  n;
  1766. X                        char  *p;
  1767. X
  1768. X                        n = get_argpfx( (char *)cmd_name(argd) );
  1769. X                        p = (char *)malloc( n+1 );
  1770. X                        if ( !p ) {
  1771. X                           syserr( "malloc failed in parsecntl()" );
  1772. X                        }
  1773. X                        strncpy(p, (char *)cmd_name(argd), n);
  1774. X                        p[n] = 0;
  1775. X                        cmd_name(argd) = p;
  1776. X                        BSET(cmd_state(cmd), ps_FREENAME);
  1777. X                     }
  1778. X                  }
  1779. X                  str = cmd_name(cmd);
  1780. X               }
  1781. X               else if ( cntl == pc_PURPOSE ) {
  1782. X                  if ( !BTEST(cmd_state(cmd), ps_USERPURPOSE|ps_FREEPURPOSE) ) {
  1783. X                     if ( cmd_purpose(argd) ) {
  1784. X                        int  n;
  1785. X                        char  *p, *q;
  1786. X
  1787. X                        p = get_argdesc( (char *)cmd_purpose(argd), &n );
  1788. X                        if ( p ) {
  1789. X                           q = (char *)malloc( n+1 );
  1790. X                           if ( !q ) {
  1791. X                              syserr( "malloc failed in parsecntl()" );
  1792. X                           }
  1793. X                           strncpy(q, p, n);
  1794. X                           q[n] = 0;
  1795. X                           p = q;
  1796. X                           BSET(cmd_state(cmd), ps_FREEPURPOSE);
  1797. X                        }
  1798. X                        cmd_purpose(cmd) = p;
  1799. X                     }
  1800. X                  }
  1801. X                  str = cmd_purpose(cmd);
  1802. X               }
  1803. X               else /* cntl == pc_DESCRIPTION */  str = cmd_description(cmd);
  1804. X            }
  1805. X            else {
  1806. X               str = VA_ARG( ap, CONST char * );
  1807. X               pstr = &str;
  1808. X            }
  1809. X
  1810. X               /* perform the desired action(s) */
  1811. X            if ( isWRITING(mode) )  {
  1812. X               if ( cntl == pc_NAME ) {
  1813. X                  if ( BTEST(cmd_state(cmd), ps_FREENAME) )
  1814. X                     free( cmd_name(cmd) );
  1815. X                     BCLEAR( cmd_state(cmd), ps_FREENAME );
  1816. X                     BSET( cmd_state(cmd), ps_USERNAME );
  1817. X                     cmd_name(cmd) = *pstr;
  1818. X                  }
  1819. X               else if ( cntl == pc_PURPOSE ) {
  1820. X                  if ( BTEST(cmd_state(cmd), ps_FREEPURPOSE) ) {
  1821. X                     free( cmd_purpose(cmd) );
  1822. X                  }
  1823. X                  BCLEAR( cmd_state(cmd), ps_FREEPURPOSE );
  1824. X                  BSET( cmd_state(cmd), ps_USERPURPOSE );
  1825. X                  cmd_purpose(cmd) = *pstr;
  1826. X               }
  1827. X               else /* cntl == pc_DESCRIPTION */  cmd_description(cmd) = *pstr;
  1828. X            }
  1829. X            if ( isREADING(mode) )  *pstr = str;
  1830. X         }/*block*/
  1831. X         break;
  1832. X
  1833. X      default :
  1834. X         rc = pe_BADCNTL;
  1835. X         break;
  1836. X   }/*switch*/
  1837. X
  1838. X   VA_END( ap );
  1839. X   return   rc;
  1840. X}
  1841. X
  1842. X#undef  isREADING
  1843. X#undef  isWRITING
  1844. X
  1845. X
  1846. X#ifndef LITE
  1847. X
  1848. X/***************************************************************************
  1849. X** ^FUNCTION: sparseargs - parse arguments in a string
  1850. X**
  1851. X** ^SYNOPSIS:
  1852. X*/
  1853. X#ifndef __ANSI_C__
  1854. X   int sparseargs( str, argd )
  1855. X/*
  1856. X** ^PARAMETERS:
  1857. X*/
  1858. X   char    *str;
  1859. X/*    -- string to parse
  1860. X*/
  1861. X   ARGDESC *argd;
  1862. X/*    -- pointer to argument descriptor table
  1863. X*/
  1864. X#endif  /* !__ANSI_C__ */
  1865. X  
  1866. X/* ^DESCRIPTION:
  1867. X**    Given a single string and an argdesc array, sparseargs will parse
  1868. X**    arguments from a string in the same manner as parseargs.
  1869. X**    Sparseargs will split the given string up into a vector of whitespace
  1870. X**    separated tokens and then attempt to parse the resultant vector as if
  1871. X**    it were given as argv[] on the command-line.  NO special treatment is
  1872. X**    given to characters such as single-quotes, double-quotes, or anything
  1873. X**    else. Sparseargs will always assume that any whitespace characters are
  1874. X**    intended as argument separators.
  1875. X**
  1876. X** ^REQUIREMENTS:
  1877. X**    <str> should be non-NULL and non-empty
  1878. X**
  1879. X** ^SIDE-EFFECTS:
  1880. X**    <str> is modified by strsplit().
  1881. X**    <argd> is modified accordingly as arguments are matched.
  1882. X**
  1883. X** ^RETURN-VALUE:
  1884. X**    pe_SYSTEM
  1885. X**       -- If a system error occurred
  1886. X** 
  1887. X**    pe_SUCCESS
  1888. X**       -- success, no errors encountered.
  1889. X** 
  1890. X**    pe_SYNTAX
  1891. X**       -- If a syntax error occurs in <str>
  1892. X**
  1893. X** ^ALGORITHM:
  1894. X**    - save current parse-flags
  1895. X**    - add pa_ARGV0 to current parse-flags
  1896. X**    - split string up into a vector of tokens
  1897. X**    - call parse init and then parse the arguments
  1898. X**    - if syntax-error, print usage and exit
  1899. X**    - restore parse-flags
  1900. X**    - return the status from parsing the vector
  1901. X***^^**********************************************************************/
  1902. X#ifdef __ANSI_C__
  1903. X   int sparseargs( char *str, ARGDESC *argd )
  1904. X#endif
  1905. X{
  1906. X   argMask_t  saveflags;
  1907. X   char **argv;
  1908. X   int  rc = 0;
  1909. X
  1910. X   if ( !argd )  return  pe_SUCCESS;
  1911. X
  1912. X   if ( !CMD_isINIT(argd) )  init_args(argd);
  1913. X
  1914. X      /* save old flags & initialize set parse flags */
  1915. X   saveflags = cmd_flags(argd);
  1916. X   BSET(cmd_flags(argd), pa_ARGV0);
  1917. X
  1918. X      /* split line up into whitespace separated tokens */
  1919. X   (void) strsplit( &argv, str, CHARNULL );
  1920. X
  1921. X#ifdef vms_style
  1922. X   BSET( cmd_state(argd), ps_NOTCMDLINE );
  1923. X#endif
  1924. X
  1925. X   rc = parse_argv_style( argv, parse_init( &argd ) );
  1926. X   free( argv );
  1927. X
  1928. X#ifdef vms_style
  1929. X   BCLEAR( cmd_state(argd), ps_NOTCMDLINE );
  1930. X#endif
  1931. X
  1932. X      /* scan for missing required arguments */
  1933. X   if ( SYNTAX_ERROR(rc, argd) ) {
  1934. X      fputc( '\n', stderr );
  1935. X      usage( argd );
  1936. X      exit( exit_SYNTAX );
  1937. X   }
  1938. X
  1939. X      /* reset previous parse flags */
  1940. X   cmd_flags(argd)  =  saveflags;
  1941. X
  1942. X   return  rc;
  1943. X}
  1944. X
  1945. X
  1946. X/***************************************************************************
  1947. X** ^FUNCTION: fparseargs - parse arguments from a file
  1948. X**
  1949. X** ^SYNOPSIS:
  1950. X*/
  1951. X#ifndef __ANSI_C__
  1952. X   int fparseargs( fp, argd )
  1953. X/*
  1954. X** ^PARAMETERS:
  1955. X*/
  1956. X   FILE    *fp;
  1957. X/*    -- pointer to file to read (must already be open)
  1958. X*/
  1959. X   ARGDESC *argd;
  1960. X/*    -- pointer to argument descriptor table
  1961. X*/
  1962. X#endif  /* !__ANSI_C__ */
  1963. X
  1964. X/* ^DESCRIPTION:
  1965. X**    Given a readable input stream and an argdesc array, fparseargs will
  1966. X**    parse arguments in a file in the same manner as parseargs.  A
  1967. X**    maximum-line length of 255 characters is imposed.  NO "escaping" of
  1968. X**    any kind is performed. Comments of a limited form are permitted: if
  1969. X**    the first non-whitespace character on a line is a '#' (or '!' for VMS)
  1970. X**    then that entire line is considered a comment and is ignored.  If a
  1971. X**    value is provided for an argument that is NOT a list or a vector, then
  1972. X**    the value MUST be on the same line as the argument (in other words,
  1973. X**    "-v val" is fine but "-v\nval" is a not).
  1974. X**
  1975. X** ^REQUIREMENTS:
  1976. X**    <fp> should be non-NULL, already opened-for-reading, file-pointer
  1977. X**
  1978. X** ^SIDE-EFFECTS:
  1979. X**    <argd> is modified accordingly as arguments are matched.
  1980. X**
  1981. X** ^RETURN-VALUE:
  1982. X**    pe_SYSTEM
  1983. X**       -- If a system error occurred
  1984. X** 
  1985. X**    pe_SUCCESS
  1986. X**       -- success, no errors encountered.
  1987. X** 
  1988. X**    pe_SYNTAX
  1989. X**       -- if a syntax error occurs in the file
  1990. X**
  1991. X** ^ALGORITHM:
  1992. X**    - save current parse-flags
  1993. X**    - add pa_ARGV0 to current parse-flags
  1994. X**    - add pa_NOCHECK to current parse-flags (dont check until eof)
  1995. X**    - call parse init
  1996. X**    - parse the first line of the file
  1997. X**    - add pa_CONTINUE to current parse-flags
  1998. X**    - parse the rest of the file
  1999. X**    - restore parse-flags
  2000. X**    - now check for missing args if required
  2001. X**    - if syntax-error, print usage and exit
  2002. X**    - return
  2003. X***^^**********************************************************************/
  2004. X
  2005. X#ifdef vms_style
  2006. X#  define  c_COMMENT  '!'
  2007. X#else
  2008. X#  define  c_COMMENT  '#'
  2009. X#endif
  2010. X
  2011. X#ifdef __ANSI_C__
  2012. X   int fparseargs( FILE *fp, ARGDESC *argd )
  2013. X#endif
  2014. X{
  2015. X   int  rc;
  2016. X   char  text[ MAXLINE ];
  2017. X   argMask_t  saveflags;
  2018. X
  2019. X   if ( !argd )  return  0;
  2020. X
  2021. X   if ( !CMD_isINIT(argd) )  init_args(argd);
  2022. X
  2023. X      /* We want the following scenario for the various calls to sparseargs():
  2024. X      ** assume there are N lines in the input file. Then there will be N
  2025. X      ** calls to sparseargs(). For all calls, we want pa_ARGV0 and pa_COPYF
  2026. X      ** to be ON. Then for the ALL but the very last call, we want pa_NOCHECK
  2027. X      ** to be off. For all but the very first call - we want pa_CONTINUE to
  2028. X      ** be turned ON. So we have the following table:
  2029. X      **
  2030. X      **     Parse     ||           invocation of sparseargs
  2031. X      **      Flag     ||   0    |     1     |     2 .. N-1    |     N
  2032. X      **   ============++========+===========+=================+=============== 
  2033. X      **      ARGV0    ||   on   |    on     |       on        |     on
  2034. X      **   ------------++--------+-----------+-----------------+--------------- 
  2035. X      **      COPYF    ||   on   |    on     |       on        |     on
  2036. X      **   ------------++--------+-----------+-----------------+--------------- 
  2037. X      **      NOCHECK  ||   on   |    on     |       on        |     OFF
  2038. X      **   ------------++--------+-----------+-----------------+--------------- 
  2039. X      **      CONTINUE ||   OFF  |    on     |       on        |     on
  2040. X      **   ============++========+===========+=================+=============== 
  2041. X      */
  2042. X      
  2043. X      /* save old flags & initialize parse flags for first call */
  2044. X   saveflags = cmd_flags(argd);
  2045. X   BSET(cmd_flags(argd), pa_ARGV0 | pa_NOCHECK | pa_COPYF);
  2046. X
  2047. X   while ( !feof( fp ) ) {
  2048. X      if ( !fgets( text, MAXLINE, fp ) ) {
  2049. X         if ( ferror( fp ) )  {
  2050. X            cmd_flags(argd)  =  saveflags;
  2051. X            return  pe_SYSTEM;
  2052. X         }
  2053. X      }/*if*/
  2054. X
  2055. X         /* trim leading and trailing whitespace and check for comments */
  2056. X      (VOID) strtrim( text, CHARNULL );
  2057. X      if ( !text  ||  !(*text)  ||  *text == c_COMMENT )  continue;
  2058. X
  2059. X      rc = sparseargs( text, argd );
  2060. X
  2061. X         /* set up parseflags for next call */
  2062. X      if ( !BTEST(cmd_flags(argd), pa_CONTINUE) ) {
  2063. X         BSET(cmd_flags(argd), pa_CONTINUE);
  2064. X      }
  2065. X   }/*while !EOF*/
  2066. X
  2067. X   if ( !BTEST(saveflags, pa_NOCHECK) )  BCLEAR(cmd_flags(argd), pa_NOCHECK);
  2068. X
  2069. X      /* scan for missing required args */
  2070. X   if ( SYNTAX_ERROR(rc, argd) ) {
  2071. X      fputc('\n', stderr);
  2072. X      usage( argd );
  2073. X      exit( exit_SYNTAX );
  2074. X   }
  2075. X
  2076. X      /* reset previous parse flags */
  2077. X   cmd_flags(argd)  =  saveflags;
  2078. X
  2079. X   return  rc;
  2080. X}
  2081. X
  2082. X#undef  c_COMMENT
  2083. X
  2084. X
  2085. X/***************************************************************************
  2086. X** ^FUNCTION: lparseargs - parse arguments from a list
  2087. X**
  2088. X** ^SYNOPSIS:
  2089. X*/
  2090. X#ifndef __ANSI_C__
  2091. X   int lparseargs( argls, argd )
  2092. X/*
  2093. X** ^PARAMETERS:
  2094. X*/
  2095. X   ArgList *argls;
  2096. X/*    -- linked list of args to parse
  2097. X*/
  2098. X   ARGDESC *argd;
  2099. X/*    -- pointer to argument descriptor table
  2100. X*/
  2101. X#endif  /* !__ANSI_C__ */
  2102. X  
  2103. X/* ^DESCRIPTION:
  2104. X**    Given an ArgList and an argdesc array, lparseargs will parse arguments
  2105. X**    in an ArgList in the same manner as parseargs.
  2106. X**
  2107. X** ^REQUIREMENTS:
  2108. X**    <argls> should be an ArgList of strings
  2109. X**
  2110. X** ^SIDE-EFFECTS:
  2111. X**    <argd> is modified accordingly as arguments are matched.
  2112. X**
  2113. X** ^RETURN-VALUE:
  2114. X**    pe_SYSTEM
  2115. X**       -- If a system error occurred
  2116. X** 
  2117. X**    pe_SUCCESS
  2118. X**       -- success, no errors encountered.
  2119. X** 
  2120. X**    pe_SYNTAX
  2121. X**       -- if a syntax error occurs
  2122. X**
  2123. X** ^ALGORITHM:
  2124. X**    - save current parse-flags
  2125. X**    - add pa_ARGV0 to current parse-flags
  2126. X**    - make a vector out of the ArgList
  2127. X**    - call parse init
  2128. X**    - restore parse-flags
  2129. X**    - if syntax-error, print usage and exit
  2130. X**    - return
  2131. X***^^**********************************************************************/
  2132. X#ifdef __ANSI_C__
  2133. X   int lparseargs( ArgList *argls, ARGDESC *argd )
  2134. X#endif
  2135. X{
  2136. X   int   i, argc = 0, rc = 0;
  2137. X   char **argv = (char **)NULL;
  2138. X   argMask_t   saveflags;
  2139. X   register    ArgList *ls;
  2140. X
  2141. X   if ( !argd )  return  0;
  2142. X   if ( !CMD_isINIT(argd) )   init_args(argd);
  2143. X
  2144. X      /* make 1st pass to count the args */
  2145. X   for ( ls = argls; ls ; ls = L_NEXT(ls) ) {
  2146. X      argc++;
  2147. X   }
  2148. X
  2149. X      /* allocate a NULL terminated arg-vector */
  2150. X   argv = (char **)malloc( (argc + 1) * sizeof(char *) );
  2151. X   if ( !argv )  return  pe_SYSTEM;
  2152. X   argv[ argc ] = CHARNULL;
  2153. X
  2154. X      /* make 2nd pass to assign the elements of the vector */
  2155. X   for ( ls = argls, i = 0 ; ls ; ls = L_NEXT(ls), i++ ) {
  2156. X      argv[i] = L_STRING(ls);
  2157. X   }
  2158. X
  2159. X#ifdef vms_style
  2160. X   BSET( cmd_state(argd), ps_NOTCMDLINE );
  2161. X#endif
  2162. X
  2163. X      /* parse the list */
  2164. X   saveflags = cmd_flags(argd);
  2165. X   BSET(cmd_flags(argd), pa_ARGV0);
  2166. X   rc = parse_argv_style( argv, parse_init( &argd ) );
  2167. X   free( argv );
  2168. X
  2169. X#ifdef vms_style
  2170. X   BCLEAR( cmd_state(argd), ps_NOTCMDLINE );
  2171. X#endif
  2172. X
  2173. X      /* scan for missing required arguments */
  2174. X   if ( SYNTAX_ERROR(rc, argd) ) {
  2175. X      fputc( '\n', stderr );
  2176. X      usage( argd );
  2177. X      exit( exit_SYNTAX );
  2178. X   }
  2179. X
  2180. X      /* reset previous parse-flags */
  2181. X   cmd_flags(argd) = saveflags;
  2182. X
  2183. X   return   rc;
  2184. X}
  2185. X
  2186. X
  2187. X/***************************************************************************
  2188. X** ^FUNCTION: vparseargs - parse a variable-argument list
  2189. X**
  2190. X** ^SYNOPSIS:
  2191. X*/
  2192. X#ifndef __ANSI_C__
  2193. X   int vparseargs( argd, argc, va_alist )
  2194. X/*
  2195. X** ^PARAMETERS:
  2196. X*/
  2197. X   ARGDESC  *argd;
  2198. X/*    -- 
  2199. X*/
  2200. X   int  argc;
  2201. X/*    -- number of arguments to parse
  2202. X*/
  2203. X   va_dcl
  2204. X/*    -- the variable-list of arguments to parse
  2205. X*/
  2206. X#endif  /* !__ANSI_C__ */
  2207. X
  2208. X/* ^DESCRIPTION:
  2209. X**    Vparseargs takes an argdesc array, the number of arguments to parse,
  2210. X**    and a (possibly NULL terminated) list of argument-strings and parses
  2211. X**    them in the same manner as parseargs.  Unlike sparseargs,
  2212. X**    vparseargs assumes that all parameters are already split up into
  2213. X**    tokens, hence any whitespace characters contained in any of the
  2214. X**    string-parameters are used as is (and will be considered a part of
  2215. X**    an argument name or value).
  2216. X**
  2217. X**
  2218. X** ^REQUIREMENTS:
  2219. X**    argc must contain the number of arguments to be parsed (NOT including
  2220. X**    any terminating NULL pointer).  If a NULL pointer is given as one of
  2221. X**    the arguments, and this NULL pointer appears before argc indicated
  2222. X**    the last argument would appear, then the NULL pointer will end the
  2223. X**    the list of arguments and argc is ignored.
  2224. X**    
  2225. X** ^SIDE-EFFECTS:
  2226. X**    <argd> is modified accordingly as arguments are matched.
  2227. X**
  2228. X** ^RETURN-VALUE:
  2229. X**    pe_SYSTEM
  2230. X**       -- If a system error occurred
  2231. X** 
  2232. X**    pe_SUCCESS
  2233. X**       -- success, no errors encountered.
  2234. X** 
  2235. X**    pe_SYNTAX
  2236. X**       -- if a syntax error occurs
  2237. X**
  2238. X** ^ALGORITHM:
  2239. X**    - save current parse-flags
  2240. X**    - add pa_ARGV0 to current parse-flags
  2241. X**    - make a vector out of the variable list
  2242. X**    - call parse init
  2243. X**    - restore parse-flags
  2244. X**    - if syntax-error, print usage and exit
  2245. X**    - return
  2246. X***^^**********************************************************************/
  2247. X#ifdef __ANSI_C__
  2248. X   int vparseargs( ARGDESC *argd, int argc, ... )
  2249. X#endif
  2250. X{
  2251. X   register char   *arg;
  2252. X   int   i, rc = 0;
  2253. X   argMask_t   saveflags;
  2254. X   char **argv = (char **)NULL;
  2255. X   va_list   ap;
  2256. X
  2257. X   if ( !argd )   return   0;
  2258. X   if ( !CMD_isINIT(argd) )   init_args(argd);
  2259. X
  2260. X   saveflags = cmd_flags(argd);
  2261. X   BSET(cmd_flags(argd), pa_ARGV0 | pa_COPYF);
  2262. X
  2263. X      /* allocate a NULL terminated arg-vector */
  2264. X   argv = (char **) malloc( (argc + 1) * sizeof(char *) );
  2265. X   if ( !argv )  return  pe_SYSTEM;
  2266. X   argv[ argc ] = CHARNULL;
  2267. X
  2268. X      /* assign the string into the array */
  2269. X   VA_START(ap, argc);
  2270. X   for ( i = 0; i < argc  &&  (arg = VA_ARG(ap, char *)) ; i++ ) {
  2271. X      argv[i] = arg;
  2272. X   }
  2273. X   VA_END(ap);
  2274. X
  2275. X#ifdef vms_style
  2276. X   BSET( cmd_state(argd), ps_NOTCMDLINE );
  2277. X#endif
  2278. X
  2279. X      /* parse the arguments */
  2280. X   rc = parse_argv_style( argv, parse_init( &argd ) );
  2281. X   free( argv );
  2282. X
  2283. X#ifdef vms_style
  2284. X   BCLEAR( cmd_state(argd), ps_NOTCMDLINE );
  2285. X#endif
  2286. X
  2287. X      /* scan for missing required arguments */
  2288. X   if ( SYNTAX_ERROR(rc, argd) ) {
  2289. X      fputc( '\n', stderr );
  2290. X      usage( argd );
  2291. X      exit( exit_SYNTAX );
  2292. X   }
  2293. X
  2294. X      /* reset previous parse-flags */
  2295. X   cmd_flags(argd) = saveflags;
  2296. X
  2297. X   return   rc;
  2298. X}
  2299. X
  2300. X#endif /* ! LITE */
  2301. X
  2302. X
  2303. X/***************************************************************************
  2304. X** ^FUNCTION: parseargs -- parse an argument vector
  2305. X**
  2306. X** ^SYNOPSIS:
  2307. X*/
  2308. X#ifndef __ANSI_C__
  2309. X   int parseargs( argv, argd )
  2310. X/*
  2311. X** ^PARAMETERS:
  2312. X*/
  2313. X   char  *argv[];
  2314. X/*    -- pointer to the argument vector as passed to main().
  2315. X*/
  2316. X  ARGDESC argd[];
  2317. X/*    -- the argument descriptor array.
  2318. X*/
  2319. X#endif  /* !__ANSI_C__ */
  2320. X
  2321. X/* ^DESCRIPTION:
  2322. X**    Given a vector of string-valued arguments such as that passed to main
  2323. X**    and a vector describing the possible arguments, parseargs matches
  2324. X**    actual arguments to possible arguments, converts values to the
  2325. X**    desired type, and diagnoses problems such as missing arguments, extra
  2326. X**    arguments, and argument values that are syntactically incorrect.
  2327. X**
  2328. X** ^REQUIREMENTS:
  2329. X**    <argv> must be non-NULL and have a NULL pointer as its last item.
  2330. X**
  2331. X** ^SIDE-EFFECTS:
  2332. X**    <argd> is modified accordingly as arguments are matched.
  2333. X**
  2334. X** ^RETURN-VALUE:
  2335. X**    pe_SYSTEM
  2336. X**       -- If a system error occurred
  2337. X** 
  2338. X**    pe_SUCCESS
  2339. X**       -- success, no errors encountered.
  2340. X** 
  2341. X**    pe_SYNTAX
  2342. X**       -- if a syntax error occurs
  2343. X**
  2344. X** ^ALGORITHM:
  2345. X**    - call parse init
  2346. X**    - if syntax-error, print usage and exit
  2347. X**    - return
  2348. X***^^**********************************************************************/
  2349. X#ifdef __ANSI_C__
  2350. X   int parseargs( char *argv[], ARGDESC argd[] )
  2351. X#endif
  2352. X{
  2353. X   register ARGDESC *cmd;
  2354. X   register char **av = argv;
  2355. X   int rc = pe_SUCCESS;
  2356. X   argMask_t  saveflags;
  2357. X
  2358. X      /* allow null argument descriptor */
  2359. X   if ( !argd )  argd = Empty_ArgDesc;
  2360. X
  2361. X      /* initialize command-structure */
  2362. X   if ( !CMD_isINIT(argd) )  init_args( argd );
  2363. X   cmd = argd;
  2364. X   saveflags = cmd_flags(cmd);
  2365. X
  2366. X   if ( argv  &&  !BTEST(pa_ARGV0, cmd_flags(cmd)) ) {
  2367. X      cmd_argv0(cmd) = basename( *av++ );
  2368. X   }/*if*/
  2369. X
  2370. X   rc = parse_argv_style( av, parse_init( &argd ) );
  2371. X
  2372. X      /* scan for missing required arguments */
  2373. X   if ( SYNTAX_ERROR(rc, argd) ) {
  2374. X      fputc( '\n', stderr );
  2375. X      usage( argd );
  2376. X      exit( exit_SYNTAX );
  2377. X   }
  2378. X
  2379. X      /* reset previous parse-flags */
  2380. X   cmd_flags(cmd) = saveflags;
  2381. X
  2382. X   return  rc;
  2383. X}
  2384. END_OF_FILE
  2385. if test 75200 -ne `wc -c <'xparse.c'`; then
  2386.     echo shar: \"'xparse.c'\" unpacked with wrong size!
  2387. fi
  2388. # end of 'xparse.c'
  2389. fi
  2390. echo shar: End of archive 9 \(of 10\).
  2391. cp /dev/null ark9isdone
  2392. MISSING=""
  2393. for I in 1 2 3 4 5 6 7 8 9 10 ; do
  2394.     if test ! -f ark${I}isdone ; then
  2395.     MISSING="${MISSING} ${I}"
  2396.     fi
  2397. done
  2398. if test "${MISSING}" = "" ; then
  2399.     echo You have unpacked all 10 archives.
  2400.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2401. else
  2402.     echo You still need to unpack the following archives:
  2403.     echo "        " ${MISSING}
  2404. fi
  2405. ##  End of shell archive.
  2406. exit 0
  2407.  
  2408. exit 0 # Just in case...
  2409.