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

  1. Newsgroups: comp.sources.misc
  2. From: brad@hcx1.ssd.csd.harris.com (Brad Appleton)
  3. Subject:  v29i120:  parseargs - functions to parse command line arguments, Part05/10
  4. Message-ID: <1992May17.182408.28783@sparky.imd.sterling.com>
  5. X-Md4-Signature: 2c6176341eb2a2a36383088be53ba8e9
  6. Date: Sun, 17 May 1992 18:24:08 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 120
  11. Archive-name: parseargs/part05
  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 5 (of 10)."
  22. # Contents:  amiga_args.c argtype.c unix_args.c
  23. # Wrapped by brad@hcx1 on Thu May  7 12:12:24 1992
  24. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  25. if test -f 'amiga_args.c' -a "${1}" != "-c" ; then 
  26.   echo shar: Will not clobber existing file \"'amiga_args.c'\"
  27. else
  28. echo shar: Extracting \"'amiga_args.c'\" \(18431 characters\)
  29. sed "s/^X//" >'amiga_args.c' <<'END_OF_FILE'
  30. X/*************************************************************************
  31. X** ^FILE: amiga_args.c - parse AmigaDOS argument vectors
  32. X**
  33. X** ^DESCRIPTION:
  34. X**    This file contains the routines used to parse AmigaDOS argument
  35. X**    vectors and to print AmigaDOS usage messages.
  36. X**
  37. X** ^HISTORY:
  38. X**    27/08/91     Earl Chew     <cechew@bruce.cs.monash.edu.au>
  39. X**    - Use ProgNameLen when accessing ProgName
  40. X**    - Use get_argdesc() to access description
  41. X**
  42. X**    01/02/91     Brad Appleton     <brad@ssd.csd.harris.com>
  43. X**    - Added structured block comments
  44. X**    - Added optional arguments to keywords
  45. X**
  46. X**    --/--/--  Peter da Silva  <peter@ferranti.com>    Created
  47. X***^^**********************************************************************/
  48. X
  49. X#include <ctype.h>
  50. X#include <useful.h>
  51. X#include "strfuncs.h"
  52. X#include "pgopen.h"
  53. X#include "exit_codes.h"
  54. X
  55. X#define PARSEARGS_PRIVATE   /* include private definitions */
  56. X#include "parseargs.h"
  57. X
  58. XEXTERN  VOID  syserr       ARGS((const char *, ...));
  59. XEXTERN  VOID  usrerr       ARGS((const char *, ...));
  60. XEXTERN  char *getenv       ARGS((const char *));
  61. XEXTERN  VOID  get_winsize  ARGS((int, int *, int *));
  62. X
  63. XVERSIONID("$Header: parseargs.c,v 2.1 89/12/30 20:59:48 eric Exp $");
  64. X
  65. X/***************************************************************************
  66. X** ^GLOBAL-VARIABLE: Usage_Requested
  67. X**
  68. X** ^VISIBILITY:
  69. X**    static-global (visible to all functions in this file).
  70. X**
  71. X** ^DESCRIPTION:
  72. X**    Indicates whether a usage message was requested by the user
  73. X**    (as opposed to triggerred by a syntax error).  If the message
  74. X**    is requested by the user then it is always printed in verbose
  75. X**    mode and does not return an error-status-code.
  76. X***^^**********************************************************************/
  77. Xstatic  BOOL  Usage_Requested = FALSE;
  78. X
  79. X
  80. X/***************************************************************************
  81. X** ^FUNCTION: amiga_parse - parse Amiga_DOS arg-vectors
  82. X**
  83. X** ^SYNOPSIS:
  84. X*/
  85. X#ifndef __ANSI_C__
  86. X   int amiga_parse( argv, argd )
  87. X/*
  88. X** ^PARAMETERS:
  89. X*/
  90. X   char *argv[];
  91. X/*    -- the vector of string arguments from the command-line
  92. X*/
  93. X   ARGDESC argd[];
  94. X/*    -- the programmer description of the command and its args
  95. X*/
  96. X#endif  /* !__ANSI_C__ */
  97. X
  98. X/* ^DESCRIPTION:
  99. X**    Amiga_parse will parse the arguments in the given vector of strings,
  100. X**    assign the corresponding values to the command-line arguments specified
  101. X**    in argd, and check the syntax of the command-line.
  102. X**
  103. X** ^REQUIREMENTS:
  104. X**    The final element in argv must be a NULL pointer.
  105. X**
  106. X** ^SIDE-EFFECTS:
  107. X**    argd is modified according to the command-line description and parameters
  108. X**
  109. X** ^RETURN-VALUE:
  110. X**    pe_SUCCESS (0) if no errors are encountered
  111. X**    pe_SYSTEM (-1) if a system error is encountered
  112. X**    pe_SYNTAX if a syntax error is encountered
  113. X**
  114. X** ^ALGORITHM:
  115. X**    - for each command-line argument
  116. X**       - attempt to match the argument as a keyword
  117. X**       - if it is a keyword argument
  118. X**          - record and convert its value (if any)
  119. X**         else it is a positional parameter
  120. X**          - record and convert its value (if any)
  121. X**         else there are too many arguments
  122. X**          - return pe_SYNTAX
  123. X**         end-if
  124. X**       end-for
  125. X***^^**********************************************************************/
  126. X#ifdef __ANSI_C__
  127. X   int amiga_parse( char **argv, ARGDESC argd[] )
  128. X#endif
  129. X{
  130. X   register ARGDESC *cmd, *args, *ad = ARGDESCNULL;
  131. X   register char **av;
  132. X   register char *p = CHARNULL;
  133. X   argName_t   keyword;
  134. X   argMask_t   flags;
  135. X   int  parse_error = pe_SUCCESS;
  136. X   BOOL is_match = FALSE;
  137. X
  138. X   if ( !argd )  return  parse_error;
  139. X
  140. X      /* initialize command-structure */
  141. X   if ( !CMD_isINIT(argd) )  init_args( argd );
  142. X   cmd = argd;
  143. X   cmd_prev(cmd) = ARGDESCNULL;
  144. X
  145. X      /* run through the argument vector */
  146. X   for ( av = argv ; *av ; av++ ) {
  147. X      char c = '\0';
  148. X
  149. X         /* If looking for keywords, see if this is one */
  150. X      if( !BTEST(cmd_state(cmd), ps_NOFLAGS) ) {
  151. X         p = strpbrk(*av, s_ARG_SEP);
  152. X         if ( p ) {
  153. X            c = *p;
  154. X            *p++ = '\0';  /* skip past arg-separator character */
  155. X         }
  156. X
  157. X         is_match = FALSE;
  158. X         for ( args = argd ; args  &&  !is_match ; args = cmd_defargs(args) ) {
  159. X            for (ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad)) {
  160. X               if (arg_type(ad) == argDummy)  continue;
  161. X
  162. X               if (!ARG_isPOSONLY(ad)  &&  match(*av, arg_sname(ad)) == 0) {
  163. X                  is_match = TRUE;
  164. X                  break;
  165. X               }/*if*/
  166. X            }
  167. X         }
  168. X
  169. X         if ( !is_match )  ad = ARGDESCNULL;
  170. X      }/*if !NOFLAGS*/
  171. X
  172. X      if (c)  *(p-1) = c;  /* restore the equal sign */
  173. X
  174. X         /* If we have a keyword here */
  175. X      if( !BTEST(cmd_state(cmd), ps_NOFLAGS)  &&  ad) {
  176. X         if ( cmd_prev(cmd) ) { /* a value may have been given but wasnt */
  177. X            if ( ARG_isVALOPTIONAL(cmd_prev(cmd)) ) {
  178. X               BSET( arg_flags(cmd_prev(cmd)), ARGGIVEN );
  179. X            }
  180. X            else {  /* value was required */
  181. X               (VOID)get_kwdname( arg_sname(cmd_prev(cmd)), keyword );
  182. X               usrerr( "value required for %s keyword", keyword );
  183. X               parse_error = pe_SYNTAX;
  184. X            }
  185. X            cmd_prev(cmd) = ARGDESCNULL;
  186. X         }
  187. X
  188. X         if ( cmd_list(cmd) ) { /* end of list */
  189. X            cmd_list(cmd) = ARGDESCNULL;
  190. X         }
  191. X
  192. X         flags = arg_flags(ad);    /* save flags */
  193. X         if ( ARG_isGIVEN(ad) ) {
  194. X            BCLEAR( arg_flags(ad), ARGVALSEP | ARGKEYWORD );
  195. X            if ( !ARG_isMULTIVAL(ad) )  BCLEAR( arg_flags(ad), ARGVALGIVEN );
  196. X         }
  197. X
  198. X         if ( p ) { /* matched NAME=VALUE */
  199. X            if ( ARG_isMULTIVAL(ad) )
  200. X               cmd_list(cmd) = ad;
  201. X            else
  202. X               cmd_list(cmd) = ARGDESCNULL;
  203. X
  204. X               /* try to convert the type */
  205. X            if ( !HANDLE(ad, p, cmd_flags(cmd)) ) {
  206. X               arg_flags(ad) = flags;  /* restore flags */
  207. X               parse_error = pe_SYNTAX;
  208. X            }
  209. X            else
  210. X               BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
  211. X            ad = ARGDESCNULL;
  212. X         }
  213. X         else {
  214. X            if (arg_type(ad) == argUsage) {
  215. X               Usage_Requested = TRUE;
  216. X               usage(argd);
  217. X               exit(exit_USAGE);
  218. X            }
  219. X            else if (arg_type(ad) == argEnd) {
  220. X               BSET( cmd_state(cmd), ps_NOFLAGS );
  221. X               BSET( arg_flags(ad), ARGGIVEN );
  222. X            }
  223. X            else if ( ARG_isVALTAKEN(ad) ) {
  224. X               cmd_prev(cmd) = ad;
  225. X            }
  226. X            else if ( !HANDLE(ad, CHARNULL, cmd_flags(cmd)) ) {
  227. X               arg_flags(ad) = flags;  /* restore flags */
  228. X               parse_error = pe_SYNTAX;
  229. X            }
  230. X            else {
  231. X               BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
  232. X            }
  233. X            ad = ARGDESCNULL;
  234. X         }/*else*/
  235. X      }
  236. X      else if (cmd_prev(cmd)) { /* expecting a vlue from previous arg */
  237. X         /* reset the argument flags - if this arg was already given, some
  238. X         ** of its flags may be set to indicate how it was given before.
  239. X         ** we need to know how it was given now (but save the old ones
  240. X         ** just in case the new one fails).
  241. X         */
  242. X         flags = arg_flags(cmd_prev(cmd));    /* save flags */
  243. X         if ( ARG_isGIVEN(cmd_prev(cmd)) ) {   /* reset flags */
  244. X            BCLEAR( arg_flags(cmd_prev(cmd)), ARGVALSEP );
  245. X            if ( !ARG_isMULTIVAL(ad) )  BCLEAR( arg_flags(ad), ARGVALGIVEN );
  246. X         }
  247. X
  248. X            /* previous value may have required a keyword */
  249. X         BSET( arg_flags(cmd_prev(cmd)), ARGVALSEP );
  250. X
  251. X         if ( ARG_isMULTIVAL(cmd_prev(cmd)) )
  252. X            cmd_list(cmd) = cmd_prev(cmd);
  253. X         else
  254. X            cmd_list(cmd) = ARGDESCNULL;
  255. X
  256. X            /* try to convert the type */
  257. X         if ( !HANDLE(cmd_prev(cmd), *av, cmd_flags(cmd)) ) {
  258. X            arg_flags(cmd_prev(cmd)) = flags;  /* restore flags */
  259. X            parse_error = pe_SYNTAX;
  260. X         }
  261. X         else
  262. X            BSET( arg_flags(cmd_prev(cmd)), ARGGIVEN | ARGVALGIVEN );
  263. X
  264. X         ad = ARGDESCNULL;
  265. X         cmd_prev(cmd) = ARGDESCNULL;
  266. X         continue;
  267. X      }
  268. X      else {  /* it's a positional argument or a list item */
  269. X         if ( cmd_list(cmd) ) { /* its a list item */
  270. X            /* reset the argument flags - if this arg was already given, some
  271. X            ** of its flags may be set to indicate how it was given before.
  272. X            ** we need to know how it was given now (but save the old ones
  273. X            ** just in case the new one fails).
  274. X            */
  275. X            flags = arg_flags(cmd_list(cmd));    /* save flags */
  276. X            if ( ARG_isGIVEN(cmd_list(cmd)) ) {   /* reset flags */
  277. X               BCLEAR( arg_flags(cmd_list(cmd)), ARGVALSEP );
  278. X            }
  279. X            BSET( arg_flags(cmd_list(cmd)), ARGVALSEP );
  280. X
  281. X            if ( !HANDLE(cmd_list(cmd), *av, cmd_flags(cmd)) ) {
  282. X               arg_flags(cmd_list(cmd)) = flags;  /* restore flags */
  283. X               parse_error = pe_SYNTAX;
  284. X            }
  285. X
  286. X            BSET( arg_flags(cmd_list(cmd)), ARGGIVEN | ARGVALGIVEN );
  287. X            continue;
  288. X         }
  289. X         else {  /* its a positional argument */
  290. X
  291. X            /* if FLAGS1ST is set then first positional marks end-of-flags */
  292. X            if ( BTEST(cmd_flags(cmd), pa_FLAGS1ST) )
  293. X               BSET( cmd_state(cmd), ps_NOFLAGS );
  294. X
  295. X            is_match = FALSE;
  296. X            for ( args = argd; args && !is_match; args = cmd_defargs(args) ) {
  297. X               for (ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad)) {
  298. X                  if (arg_type(ad) == argDummy)  continue;
  299. X
  300. X                  if ( ARG_isPOSITIONAL(ad)  &&
  301. X                       (!ARG_isGIVEN(ad) || ARG_isMULTIVAL(ad)) ) {
  302. X                     is_match = TRUE;
  303. X                     break;
  304. X                  }/*if*/
  305. X               }
  306. X            }
  307. X
  308. X            if ( !is_match ) {
  309. X               usrerr("too many arguments");
  310. X               parse_error = pe_SYNTAX;
  311. X               ad = ARGDESCNULL;
  312. X            }
  313. X            else {
  314. X               /* reset the argument flags - if this arg was already given, some
  315. X               ** of its flags may be set to indicate how it was given before.
  316. X               ** we need to know how it was given now (but save the old ones
  317. X               ** just in case the new one fails).
  318. X               */
  319. X               flags = arg_flags(ad);    /* save flags */
  320. X               if ( ARG_isGIVEN(ad) ) {   /* reset flags for this appearance */
  321. X                  BCLEAR( arg_flags(ad), ARGVALSEP );
  322. X                  if (! ARG_isMULTIVAL(ad))  BCLEAR(arg_flags(ad), ARGVALGIVEN);
  323. X               }
  324. X               BSET( arg_flags(ad), ARGVALSEP );
  325. X
  326. X                  /* try to convert */
  327. X               if ( !HANDLE(ad, *av, cmd_flags(cmd)) ) {
  328. X                  arg_flags(ad) = flags;  /* restore flags */
  329. X                  parse_error = pe_SYNTAX;
  330. X               }
  331. X               else
  332. X                  BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
  333. X               ad = ARGDESCNULL;
  334. X            }
  335. X         }/*else positional*/
  336. X      }/*else not keyword*/
  337. X   }/*while*/
  338. X
  339. X   /* If last argument was a keyword and required an option
  340. X   ** then complain about it
  341. X   */
  342. X   if ( cmd_prev(cmd) ) { /* a value may have been given but wasnt */
  343. X      if ( ARG_isVALOPTIONAL(cmd_prev(cmd)) ) {
  344. X         BSET( arg_flags(cmd_prev(cmd)), ARGGIVEN );
  345. X      }
  346. X      else {  /* value was required */
  347. X         (VOID)get_kwdname( arg_sname(cmd_prev(cmd)), keyword );
  348. X         usrerr( "value required for %s keyword", keyword );
  349. X         parse_error = pe_SYNTAX;
  350. X      }
  351. X      cmd_prev(cmd) = ARGDESCNULL;
  352. X   }
  353. X
  354. X   return  parse_error;
  355. X}
  356. X
  357. X
  358. X/***************************************************************************
  359. X** ^FUNCTION: fmtarg - format command-argument syntax
  360. X**
  361. X** ^SYNOPSIS:
  362. X*/
  363. X#ifndef __ANSI_C__
  364. X   static int fmtarg(ad, buf)
  365. X/*  
  366. X** ^PARAMETERS:
  367. X*/
  368. X   ARGDESC *ad;
  369. X/*    -- pointer to the argument to format
  370. X*/
  371. X   char *buf;
  372. X/*    -- character buffer to hold the formatted result
  373. X*/
  374. X#endif  /* !__ANSI_C__ */
  375. X
  376. X/* ^DESCRIPTION:
  377. X**    Fmtarg will determine the proper command-line syntax for the
  378. X**    given argument and write the result to the given buffer.
  379. X**
  380. X** ^REQUIREMENTS:
  381. X**    buf must be large enough to hold the formatted result (100 characters
  382. X**    should do the trick).
  383. X**
  384. X** ^SIDE-EFFECTS:
  385. X**    buf is overwritten.
  386. X**
  387. X** ^RETURN-VALUE:
  388. X**    The number of printable characters in the argument-syntax-string
  389. X**
  390. X** ^ALGORITHM:
  391. X**    Print argument usage based on whether or not the argument is
  392. X**    positional, hidden, multi-valued (list or vector), etc ....
  393. X**    Optional arguments and values are enclosed in square braces.
  394. X***^^**********************************************************************/
  395. X#ifdef __ANSI_C__
  396. X   static int fmtarg( const ARGDESC *ad, char *buf )
  397. X#endif
  398. X{
  399. X      /* buf must already be large enough */
  400. X   char * pos;
  401. X   argName_t  keyword, name;
  402. X
  403. X   (VOID) get_argname(arg_sname(ad), name);
  404. X
  405. X   if ( ARG_isPOSITIONAL(ad) ) {
  406. X      sprintf( buf, "<%s>", name );
  407. X   }
  408. X   else {
  409. X      (VOID) get_kwdname(arg_sname(ad), keyword);
  410. X      (VOID) strcpy( buf, keyword );
  411. X      pos = buf + strlen(buf);
  412. X
  413. X      if ( ARG_isVALTAKEN(ad) && !ARG_isBOOLEAN(ad) && !ARG_isPSEUDOARG(ad) ) {
  414. X         if ( ARG_isVALOPTIONAL(ad) )
  415. X            sprintf( pos, " [<%s>]", name );
  416. X         else
  417. X            sprintf( pos, " <%s>", name );
  418. X      }
  419. X   }/*else*/
  420. X
  421. X   return  strlen(buf);
  422. X}
  423. X
  424. X
  425. X/***************************************************************************
  426. X** ^FUNCTION: amiga_usage - print a usage message
  427. X**
  428. X** ^SYNOPSIS:
  429. X*/
  430. X#ifndef __ANSI_C__
  431. X   VOID amiga_usage( argd, usage_flags )
  432. X/*  
  433. X** ^PARAMETERS:
  434. X*/
  435. X   ARGDESC *argd;
  436. X/*    -- the command-descriptor array
  437. X*/
  438. X   argMask_t usage_flags;
  439. X/*    -- flags set by $USAGECNTL
  440. X*/
  441. X#endif  /* !__ANSI_C__ */
  442. X
  443. X/* ^DESCRIPTION:
  444. X**    Amiga_usage will print the AmigaDOS command-line usage of the given
  445. X**    command on standard diagnostic output (stderr). The content of the
  446. X**    usage message is controlled by the bitmasks in usage_flags which
  447. X**    correspond to the settings in the user's USAGECNTL variable.
  448. X**
  449. X** ^REQUIREMENTS:
  450. X**    argd should be a non-null command-line argument-descriptor array
  451. X**
  452. X** ^SIDE-EFFECTS:
  453. X**    Prints on stderr.
  454. X**
  455. X** ^RETURN-VALUE:
  456. X**    None.
  457. X**
  458. X** ^ALGORITHM:
  459. X**    - if no usage is desired then exit
  460. X**    - if paging is requested print to the pager instead of stderr
  461. X**    - print the command-line syntax
  462. X**    - if the description is requested print it
  463. X**    - if verbose mode is requested, print the description of each argument
  464. X***^^**********************************************************************/
  465. X#ifdef __ANSI_C__
  466. X   void amiga_usage( const ARGDESC *argd, argMask_t usage_flags )
  467. X#endif
  468. X{
  469. X   register CONST ARGDESC  *ad, *args, *cmd;
  470. X   int  max_cols = 80, max_lines  = 24;
  471. X   int  margin, ll, pl, keywords, longest, positionals;
  472. X   BOOL first = TRUE;
  473. X   FILE *fp;
  474. X
  475. X   if ( !argd )  return;
  476. X
  477. X      /* initialize command-structure */
  478. X   if ( !CMD_isINIT(argd) )  init_args( (ARGDESC *)argd );
  479. X   cmd = argd;
  480. X
  481. X      /* force verbose-mode if requested */
  482. X   if ( Usage_Requested )   BSET( usage_flags, usg_VERBOSE );
  483. X
  484. X   if ( BTEST(usage_flags, usg_NONE) )  return;
  485. X
  486. X   fp = ( BTEST(usage_flags, usg_PAGED) )
  487. X      ? pgopen( stderr, getenv("USAGE_PAGER") )
  488. X      : stderr;
  489. X
  490. X      /* get screen size */
  491. X   get_winsize( fileno(stderr), &max_lines, &max_cols );
  492. X   fprintf(fp, "Format: %.*s", ProgNameLen, (ProgName) ? ProgName : "");
  493. X   ll = ProgNameLen + 8;
  494. X   margin = ll + 1;
  495. X   longest = 0;
  496. X
  497. X   for ( positionals = 0 ; positionals < 2 ; positionals++ ) {
  498. X      for ( args = argd ; args ; args = cmd_defargs(args) ) {
  499. X         for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
  500. X            argName_t  buf;
  501. X
  502. X               /* don't display hidden arguments */
  503. X            if ( ARG_isHIDDEN(ad) )  continue;
  504. X            if ( !positionals  &&  ARG_isPOSITIONAL(ad) )  continue;
  505. X            if ( positionals  &&  !ARG_isPOSITIONAL(ad) )  continue;
  506. X
  507. X               /* figure out how wide this parameter is (for printing) */
  508. X            pl = fmtarg(ad, buf);
  509. X
  510. X            if ( pl > longest)  longest = pl;
  511. X
  512. X            if ( !ARG_isREQUIRED(ad) ) {
  513. X               pl += 2;  /* [] */
  514. X            }
  515. X            if ( ARG_isMULTIVAL(ad) ) {
  516. X               strcat( buf, "..." );
  517. X               pl += 3;
  518. X            }
  519. X
  520. X               /* see if this will fit */
  521. X            if ( (ll + pl + 1) > (max_cols - first) ) {
  522. X                  /* no... start a new line */
  523. X               fprintf(fp, "\n%*s", margin, "");
  524. X               ll = margin;
  525. X            }
  526. X            else {
  527. X                  /* yes... just throw in a space */
  528. X               fputc(' ', fp);
  529. X               ++ll;
  530. X            }
  531. X            ll += pl;
  532. X
  533. X               /* show the argument */
  534. X            if ( !ARG_isREQUIRED(ad) )  fputc('[', fp);
  535. X            fprintf(fp, buf);
  536. X            if ( !ARG_isREQUIRED(ad) )  fputc(']', fp);
  537. X
  538. X            first = FALSE;  /* not first line anymore */
  539. X         }/*for each ad */
  540. X      }/* for each argd */
  541. X   }/* for each parm-type */
  542. X
  543. X   fputc('\n', fp);
  544. X
  545. X   if ( BTEST(usage_flags, usg_DESCRIPTION) ) {
  546. X      CONST char *description = cmd_description(cmd);
  547. X
  548. X      if ( description  &&  *description ) {
  549. X         fprintf( fp, "Description:\n" );
  550. X         indent_para(fp, max_cols, 8, "", 0, description, 0);
  551. X         fputc( '\n', fp );
  552. X      }
  553. X   }/*if*/
  554. X
  555. X   if ( !BTEST(usage_flags, usg_VERBOSE) )  {
  556. X      if ( pgactive(fp) )  (VOID) pgclose( fp );
  557. X      return;
  558. X   }
  559. X
  560. X   keywords = 0;
  561. X   for ( positionals = 0 ; positionals < 2 ; positionals++ ) {
  562. X      for ( args = argd ; args ; args = cmd_defargs(args) ) {
  563. X         for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
  564. X            argName_t  buf;
  565. X            char  *desc;
  566. X            int  desclen;
  567. X
  568. X               /* don't display hidden arguments */
  569. X            if ( ARG_isHIDDEN(ad) )  continue;
  570. X            if ( !positionals  &&  ARG_isPOSITIONAL(ad) )  continue;
  571. X            if ( positionals  &&  !ARG_isPOSITIONAL(ad) )  continue;
  572. X
  573. X            if( !(keywords++) )  fprintf(fp, "Keywords/Arguments:\n");
  574. X            (VOID) fmtarg(ad, buf);
  575. X            desc = get_argdesc(arg_description(ad), &desclen);
  576. X            indent_para(fp, max_cols, 8, buf, longest+2, desc, desclen);
  577. X         }/*for each ad */
  578. X      }/* for each argd */
  579. X   }/* for each parm-type */
  580. X
  581. X   if ( pgactive(fp) )  (VOID) pgclose( fp );
  582. X}
  583. END_OF_FILE
  584. if test 18431 -ne `wc -c <'amiga_args.c'`; then
  585.     echo shar: \"'amiga_args.c'\" unpacked with wrong size!
  586. fi
  587. # end of 'amiga_args.c'
  588. fi
  589. if test -f 'argtype.c' -a "${1}" != "-c" ; then 
  590.   echo shar: Will not clobber existing file \"'argtype.c'\"
  591. else
  592. echo shar: Extracting \"'argtype.c'\" \(22859 characters\)
  593. sed "s/^X//" >'argtype.c' <<'END_OF_FILE'
  594. X/*************************************************************************
  595. X** ^FILE: argtype.c - argument type definitions for parseargs(3)
  596. X**
  597. X** ^DESCRIPTION:
  598. X**    This file implements the argument conversion functions for
  599. X**    converting string, character, integer, floating-point,
  600. X**    boolean, and pseudo-arguments, from command-line strings.
  601. X**
  602. X** ^HISTORY:
  603. X**    01/03/91    Brad Appleton    <brad@ssd.csd.harris.com>
  604. X**       - Added structured block comments
  605. X**       - Added argUsage & argDummy dummy-functions
  606. X**       - Added argSBool, argTBool, and argUBool
  607. X**       - Added ARGVEC handling to all necessary functions
  608. X**       - Added argInput & argOutput for VMS
  609. X**       - put floating-point routines (argFloat & argDouble) into
  610. X**         this file (they may be excluded by #defining NOFLOAT)
  611. X**       - changed routines to return negative values (where appropriate)
  612. X**
  613. X**    --/--/--    Peter da Silva    <peter@ferranti.com>
  614. X**
  615. X**    --/--/--    Eric P. Allman    <eric@Berkeley.EDU>     Created
  616. X***^^**********************************************************************/
  617. X
  618. X#include <ctype.h>
  619. X#include <useful.h>
  620. X#include "strfuncs.h"
  621. X
  622. X#define PARSEARGS_NARGTYPES  /* exclude arg-type externs */
  623. X#include "parseargs.h"
  624. X
  625. X#ifdef __ANSI_C__
  626. X# define  PARMS(ad,vp,copyf) \
  627. X    ( register ARGDESC *ad,  register char *vp,  BOOL copyf )
  628. X#else
  629. X# define  PARMS(ad,vp,copyf) \
  630. X    ( ad, vp, copyf )  register ARGDESC *ad;  register char *vp;  BOOL copyf;
  631. X#endif
  632. X
  633. X#define REALLOC(ptr,size)  (( ! ptr ) ? malloc(size) : realloc(ptr, size) )
  634. XEXTERN  VOID    syserr  ARGS((const char *, ...));
  635. XEXTERN  VOID    usrerr  ARGS((const char *, ...));
  636. X
  637. X#ifndef __ANSI_C__
  638. X   EXTERN  long    strtol  ARGS((char *, char **, int));
  639. X   EXTERN  double  strtod  ARGS((const char *, char **));
  640. X#endif
  641. X
  642. X/***************************************************************************
  643. X** ^FUNCTION: argtype -- argument translation routines.
  644. X**
  645. X** ^SYNOPSIS:
  646. X**    BOOL  argUsage( ad, vp, copyf )
  647. X**    BOOL  argEnd( ad, vp, copyf );
  648. X**    BOOL  argDummy( ad, vp, copyf );
  649. X**    BOOL  argBool( ad, vp, copyf );
  650. X**    BOOL  argSBool( ad, vp, copyf );
  651. X**    BOOL  argUBool( ad, vp, copyf );
  652. X**    BOOL  argTBool( ad, vp, copyf );
  653. X**    BOOL  argChar( ad, vp, copyf );
  654. X**    BOOL  argStr( ad, vp, copyf );
  655. X**    BOOL  argInt( ad, vp, copyf );
  656. X**    BOOL  argShort( ad, vp, copyf );
  657. X**    BOOL  argLong( ad, vp, copyf );
  658. X**    BOOL  argFloat( ad, vp, copyf );
  659. X**    BOOL  argDouble( ad, vp, copyf );
  660. X**    BOOL  argInput( ad, vp, copyf );
  661. X**    BOOL  argOutput( ad, vp, copyf );
  662. X**
  663. X** ^PARAMETERS:
  664. X**    ARGDESC *ad;
  665. X**    -- the argument descriptor for this parameter.
  666. X**
  667. X**    char *vp;
  668. X**    -- a pointer to the string input value.
  669. X**
  670. X**    BOOL  copyf;
  671. X**    -- if TRUE, the value will be destroyed later, and so should be copied
  672. X**       if it will be retained (as for a string).
  673. X**
  674. X** ^DESCRIPTION:
  675. X**    Each of these converts a parameter value to the internal form, includ-
  676. X**    ing validity checking.  Their parameters and return values all behave
  677. X**    similarly. One of these routines is called when an argument of that
  678. X**    particular type is matched by one of the argument parsing function in
  679. X**    parseargs(3). When such an argument is matched, its argument transla-
  680. X**    tion routine is invoked and is passed (1) the address of the argument
  681. X**    descriptor for the matched argument, (2) the possible argument string
  682. X**    for that matched argument, and (3) a boolean field that is TRUE only
  683. X**    if the second parameter points to temporary storage (indicating that
  684. X**    some copying may need to be done instead of just pointing to the same
  685. X**    object).
  686. X**
  687. X**    Once the argument translation routine is invoked, it is responsible
  688. X**    for converting the argument string to the desired internal form
  689. X**    (perhaps a number), and assigning the resultant value to the
  690. X**    arg_valp(ad) field of the argument descriptor (this includes handling
  691. X**    any necessary (re)allocation if the matched argument has the ARGVEC
  692. X**    flag enabled). If the argument is an ARGVEC or ARGLIST then the rou-
  693. X**    tine is responsible for allocating any space, copying the arg-flags to
  694. X**    the value-specific flags, and setting the ARGCOPYF flag for the value
  695. X**    if it needs to be allocated as well.
  696. X**
  697. X** ^REQUIREMENTS:
  698. X**    ARGKEYWORD should be set if the argument was matched via its
  699. X**    string name (as opposed to by its character name).
  700. X**
  701. X**    ARGVALSEP should be set is the argument value was in a separate
  702. X**    argv element from the argument string-name (or character name).
  703. X**
  704. X** ^SIDE-EFFECTS:
  705. X**    The value used should be stored in the location indicated by arg_valp(ad).
  706. X**
  707. X** ^RETURN-VALUE:
  708. X**    TRUE : if the conversion was successful and the entire value was used.
  709. X**
  710. X**    FALSE : if the conversion failed.  The reason for failure should be
  711. X**            diagnosed using usrerr().
  712. X**
  713. X**    -N : if the conversion was successful but only N characters of the value
  714. X**         were used, the remaining characters may still match other arguments.
  715. X** 
  716. X** ^ALGORITHM:
  717. X**    Function-specific, but the basic idea is as follows:
  718. X**
  719. X**    - convert the value-string into the desired type
  720. X**    - if the value is invalid call usrerr and return FALSE
  721. X**      end-if
  722. X**    - if this ad is an ARGVEC
  723. X**        - expand the vector and insert the new item at the end
  724. X**        - update the item count
  725. X**    - else 
  726. X**        - set *ad_valp to the converted value
  727. X**      end-if
  728. X**    - return TRUE if we used the whole arg, -N if we only used N-characters
  729. X***^^**********************************************************************/
  730. X
  731. X/* vector types and defines */
  732. X#define BLOCKSIZE  5    /* number of items to allocate at once */
  733. X#define VEC_SIZE(vec,el_typ)  ( sizeof(el_typ *) * (BLOCKSIZE + vec->count) )
  734. Xtypedef ARGVEC_T(char *)  strvec_t;
  735. Xtypedef ARGVEC_T(char)    charvec_t;
  736. Xtypedef ARGVEC_T(int)     intvec_t;
  737. Xtypedef ARGVEC_T(short)   shortvec_t;
  738. Xtypedef ARGVEC_T(long)    longvec_t;
  739. Xtypedef ARGVEC_T(float)   floatvec_t;
  740. Xtypedef ARGVEC_T(double)  doublevec_t;
  741. X
  742. X
  743. X/***************************************************************************
  744. X** ^SECTION: PSEUDO-TYPES -- argUsage, argEnd, argDummy
  745. X**    ArgUsage is used to specify an argument that causes the command
  746. X**    usage to be printed.
  747. X**
  748. X**    ArgDummy is used to force an item to show up in usage-messages but
  749. X**    the item itself is never matched against any arguments from the
  750. X**    command-line.
  751. X**
  752. X**    ArgEnd is used by amiga_args.c and vms_args.c to indicate an argument
  753. X**    that forces all remaining arguments to be considered positional args.
  754. X**
  755. X**    These three are dummy functions. The routines themselves do nothing
  756. X**    of importance, we just need to have their addresses available for
  757. X**    identification in the corresponding <os>_args.c file.
  758. X***^^**********************************************************************/
  759. X
  760. X/*ARGSUSED*/
  761. XBOOL argDummy  PARMS(ad, vp, copyf)
  762. X{
  763. X   return   FALSE;
  764. X}
  765. X
  766. X
  767. X/*ARGSUSED*/
  768. XBOOL argEnd  PARMS(ad, vp, copyf)
  769. X{
  770. X   return (FALSE);
  771. X}
  772. X
  773. X
  774. X/*ARGSUSED*/
  775. XBOOL argUsage  PARMS(ad, vp, copyf)
  776. X{
  777. X   return   FALSE;
  778. X}
  779. X
  780. X
  781. X/***************************************************************************
  782. X** ^SECTION: STRING-TYPES -- argStr
  783. X**    ArgStr is one of the few argument translation routines that actually
  784. X**    uses the <copyf> flag. If <copyf> is true then the string is duplicated.
  785. X**
  786. X**    ArgStr assigns the given string (or a copy of it) to the value referenced
  787. X**    by arg_valp(unless the argument is a vector in which case the given string
  788. X**    is appended to the end).
  789. X**
  790. X**    ArgStr ensures that the very last item in a vector of strings (the one
  791. X**    accessed as vec.array[ vec.count ]) will always be NULL.
  792. X***^^**********************************************************************/
  793. X
  794. X/*ARGSUSED*/
  795. XBOOL argStr  PARMS(ad, vp, copyf)
  796. X{
  797. X   char *cp;
  798. X   argName_t  argname;
  799. X
  800. X   (VOID) get_argname( arg_sname(ad), argname );
  801. X   if (copyf) {
  802. X      register int i;
  803. X
  804. X      i = strlen(vp) + 1;
  805. X      cp = (char *) malloc(i * sizeof(char));
  806. X      if (!cp) {
  807. X         usrerr("out of memory parsing %s", argname);
  808. X         return FALSE;
  809. X      }
  810. X      memcpy(cp, vp, i);
  811. X   }
  812. X   else
  813. X      cp = vp;
  814. X
  815. X   if ( ARG_isVEC(ad) ) {
  816. X      strvec_t  *vec = (strvec_t *)arg_valp(ad);
  817. X
  818. X      if ( (vec->count % BLOCKSIZE) == 0 ) {
  819. X         vec->array = (char **) REALLOC(vec->array, 1+VEC_SIZE(vec, char *));
  820. X         if ( !vec->array ) {
  821. X            if ( copyf )  free(cp);
  822. X            syserr("out of memory saving arg %s", argname);
  823. X         }
  824. X         vec->flags = (argMask_t *) REALLOC(vec->flags, VEC_SIZE(vec, argMask_t));
  825. X         if ( !vec->flags ) {
  826. X            syserr("out of memory saving arg %s", argname);
  827. X         }
  828. X      }
  829. X
  830. X      vec->flags[ vec->count ] = arg_flags(ad);
  831. X      if ( copyf )  BSET( vec->flags[vec->count], ARGCOPYF );
  832. X      vec->array[ (vec->count)++ ] = cp;
  833. X      vec->array[ vec->count ] = (char *)NULL;
  834. X   }
  835. X   else
  836. X      *(char **) arg_valp(ad) = cp;
  837. X
  838. X   return (TRUE);
  839. X}
  840. X
  841. X
  842. X/***************************************************************************
  843. X** ^SECTION: CHARACTER-TYPES -- argChar
  844. X**    ArgChar assigns the given character to the value referenced by ad_valp
  845. X**    (unless the argument is a vector in which case the given character
  846. X**    is appended to the end).
  847. X**
  848. X**    If an argChar argument is matched as a single character option, then
  849. X**    the immediately following character will be considered its argument
  850. X**    (but the characters after it may still be processed as option-letters).
  851. X**
  852. X**    ArgChar ensures that the very last item in a vector of character (the
  853. X**    one accessed as vec.array[ vec.count ]) will always be a NUL byte so
  854. X**    that the resulting vector may also be used as a NULL terminated string.
  855. X**
  856. X**    Unlike argStr, argChar will translate character escape sequences such
  857. X**    as '\n' and '\012'.
  858. X***^^**********************************************************************/
  859. X
  860. X/*ARGSUSED*/
  861. XBOOL argChar  PARMS(ad, vp, copyf)
  862. X{
  863. X   auto char *vpp;
  864. X   argName_t  argname;
  865. X   int status = FALSE;
  866. X   char c;
  867. X
  868. X   (VOID) get_argname( arg_sname(ad), argname );
  869. X   if (!vp || !*vp) {
  870. X      status = FALSE;
  871. X   }
  872. X   if (strlen(vp) == 2 && vp[0]=='^') {
  873. X      c = vp[1] ^ '@';
  874. X      status = TRUE;
  875. X   }
  876. X   else if (strlen(vp) > 1 && vp[0]=='\\') {
  877. X      c = (int) strtol(&vp[1], &vpp, 8);
  878. X      if (*vpp == '\0')
  879. X         status = TRUE;
  880. X   }
  881. X   else if (strlen(vp) == 1) {
  882. X      c = *vp;
  883. X      status = TRUE;
  884. X   }
  885. X   else if ( !BTEST(arg_flags(ad), ARGVALSEP | ARGKEYWORD) ) {
  886. X      c = *vp;
  887. X      status = TRUE;
  888. X   }
  889. X
  890. X   if ( status ) {
  891. X      if ( ARG_isVEC(ad) ) {
  892. X         charvec_t  *vec = (charvec_t *)arg_valp(ad);
  893. X
  894. X         if ( (vec->count % BLOCKSIZE) == 0 ) {
  895. X            vec->array = (char *) REALLOC(vec->array, 1+VEC_SIZE(vec, char));
  896. X            if (!vec->array)  syserr("out of memory saving arg %s", argname);
  897. X         }
  898. X         vec->flags = (argMask_t *) REALLOC(vec->flags, VEC_SIZE(vec, argMask_t));
  899. X         if ( !vec->flags ) {
  900. X            syserr("out of memory saving arg %s", argname);
  901. X         }
  902. X
  903. X         vec->flags[ vec->count ] = arg_flags(ad);
  904. X         vec->array[ (vec->count)++ ] = c;
  905. X         vec->array[ vec->count ] = '\0';
  906. X      }
  907. X      else
  908. X         *(char *) arg_valp(ad) = c;
  909. X   }
  910. X   else {
  911. X      usrerr("invalid character argument '%s' for %s",
  912. X         vp, argname);
  913. X   }
  914. X   return (status) ? (BOOL) -1 : FALSE;
  915. X}
  916. X
  917. X
  918. X/***************************************************************************
  919. X** ^SECTION: INTEGER-TYPES -- argInt, argShort, argLong
  920. X**    Each of these functions converts the given string to the desired
  921. X**    integral type. The value may be specified as an octal number by
  922. X**    specifying the first digit to be 0. Similarly, If the first two 
  923. X**    characters are '0x' then the number is treated as hexadecimal.
  924. X***^^**********************************************************************/
  925. X
  926. X   /*
  927. X   ** macro to define an integral argtype function
  928. X   **
  929. X   ** NOTE : do NOT use a terminating semicolon when invoking this macro!
  930. X   */
  931. X#define  INTEGRAL_ARGTYPE(name,num_t,ls_t) \
  932. XBOOL name  PARMS(ad, vp, copyf) \
  933. X{ \
  934. X   auto char *vpp; \
  935. X   argName_t  argname; \
  936. X   num_t  value; \
  937. X \
  938. X   (VOID) get_argname( arg_sname(ad), argname ); \
  939. X   value = (num_t) strtol(vp, &vpp, 0); \
  940. X   if (*vpp != '\0') { \
  941. X      usrerr("invalid integer argument '%s' for %s", vp, argname); \
  942. X      return (FALSE); \
  943. X   } \
  944. X   else { \
  945. X      if ( ARG_isVEC(ad) ) { \
  946. X         ls_t  *vec = (ls_t *)arg_valp(ad); \
  947. X \
  948. X         if ( (vec->count % BLOCKSIZE) == 0 ) { \
  949. X            vec->array = (num_t *) REALLOC(vec->array, VEC_SIZE(vec, num_t)); \
  950. X            if ( !vec->array ) \
  951. X               syserr("out of memory saving arg %s", argname); \
  952. X \
  953. X            vec->flags = (argMask_t *) REALLOC(vec->flags, VEC_SIZE(vec, argMask_t)); \
  954. X            if ( !vec->flags ) \
  955. X               syserr("out of memory saving arg %s", argname); \
  956. X         } \
  957. X \
  958. X         vec->flags[ vec->count ] = arg_flags(ad); \
  959. X         vec->array[ (vec->count)++ ] = value; \
  960. X      } \
  961. X      else \
  962. X         *(num_t *) arg_valp(ad) = value; \
  963. X \
  964. X      return (TRUE); \
  965. X   } \
  966. X}
  967. X
  968. X
  969. X/* define argInt() */
  970. XINTEGRAL_ARGTYPE( argInt, int, intvec_t )
  971. X
  972. X/* define argShort() */
  973. XINTEGRAL_ARGTYPE( argShort, short, shortvec_t )
  974. X
  975. X/* define argLong() */
  976. XINTEGRAL_ARGTYPE( argLong, long, longvec_t )
  977. X
  978. X
  979. X#ifndef NOFLOAT
  980. X
  981. X/***************************************************************************
  982. X** ^SECTION: FLOATING-POINT-TYPES -- argFloat, argDouble
  983. X**    Each of these functions converts the given string to the desired
  984. X**    floating-point type.
  985. X***^^**********************************************************************/
  986. X
  987. X   /*
  988. X   ** macro to define a decimal argtype function
  989. X   **
  990. X   ** NOTE : do NOT use a terminating semicolon when invoking this macro!
  991. X   */
  992. X#define  DECIMAL_ARGTYPE(name,dec_t,ls_t) \
  993. XBOOL name  PARMS(ad, vp, copyf) \
  994. X{ \
  995. X   auto char *vpp; \
  996. X   argName_t  argname; \
  997. X   dec_t  value; \
  998. X \
  999. X   (VOID) get_argname( arg_sname(ad), argname ); \
  1000. X   value = (dec_t) strtod(vp, &vpp); \
  1001. X   if (*vpp != '\0') { \
  1002. X      usrerr("invalid decimal argument '%s' for %s", vp, argname); \
  1003. X      return (FALSE); \
  1004. X   } \
  1005. X   else { \
  1006. X      if ( ARG_isVEC(ad) ) { \
  1007. X         ls_t  *vec = (ls_t *)arg_valp(ad); \
  1008. X \
  1009. X         if ( (vec->count % BLOCKSIZE) == 0 ) { \
  1010. X            vec->array = (dec_t *) REALLOC(vec->array, VEC_SIZE(vec, dec_t)); \
  1011. X            if (!vec->array) \
  1012. X               syserr("out of memory saving arg %s", argname); \
  1013. X \
  1014. X            vec->flags = (argMask_t *) REALLOC(vec->flags, VEC_SIZE(vec, argMask_t)); \
  1015. X            if (!vec->flags) \
  1016. X               syserr("out of memory saving arg %s", argname); \
  1017. X         } \
  1018. X \
  1019. X         vec->flags[ vec->count ] = arg_flags(ad); \
  1020. X         vec->array[ (vec->count)++ ] = value; \
  1021. X      } \
  1022. X      else \
  1023. X         *(dec_t *) arg_valp(ad) = value; \
  1024. X \
  1025. X      return (TRUE); \
  1026. X   } \
  1027. X}
  1028. X
  1029. X/* define argFloat */
  1030. XDECIMAL_ARGTYPE( argFloat, float, floatvec_t )
  1031. X
  1032. X/* define argLong */
  1033. XDECIMAL_ARGTYPE( argDouble, double, doublevec_t )
  1034. X
  1035. X#endif  /* NOFLOAT */
  1036. X
  1037. X
  1038. X/*************************************************************************
  1039. X** ^SECTION: BOOLEAN-TYPES -- argBool, argSBool, argUBool, argTBool
  1040. X**    ArgBool and argSBool set a boolean value (if no value is given).
  1041. X**    ArgUBool unsets a boolean value (if no value is given). ArgTBool
  1042. X**    toggles a boolean value (if no value is given). If a value is
  1043. X**    supplied to any of these routines, then the string is looked up
  1044. X**    in a table and assigned the corresponding value.
  1045. X**
  1046. X**    If a value is supplied for an argument that was matched via its
  1047. X**    single character name and is part of the same argv element as the
  1048. X**    argument-name (so that both ARGKEYWORD and ARGVALSEP are not set),
  1049. X**    then only the first character of the value is used (unless it is
  1050. X**    not found in our table, in which case the value is ignored and the
  1051. X**    default action is taken).
  1052. X**
  1053. X**    The only possible arguments for single-character options are the
  1054. X**    following:
  1055. X**
  1056. X**       1, +         set the flag
  1057. X**       0, -         unset the flag
  1058. X**       ^, ~         toggle the flag
  1059. X**
  1060. X**    The possible argument strings for long-options (keywords) are as
  1061. X**    follows (case-insensitive):
  1062. X*/
  1063. X
  1064. X   /* define a structure for an item in our boolean-lookup table */
  1065. Xstruct booltab {
  1066. X   char   *bname;      /* string to match against */
  1067. X   char   bneedmatch;  /* number of characters that must match */
  1068. X   BOOL   bval;        /* value to use */
  1069. X};
  1070. X
  1071. X   /* define the boolean-lookup table */
  1072. XSTATIC struct booltab    _BoolTab[] = {
  1073. X   "1",      1,   TRUE,
  1074. X   "0",      1,   FALSE,
  1075. X   "+",      1,   TRUE,
  1076. X   "-",      1,   FALSE,
  1077. X   "yes",    1,   TRUE,
  1078. X   "no",     1,   FALSE,
  1079. X   "true",   1,   TRUE,
  1080. X   "false",  1,   FALSE,
  1081. X   "on",     2,   TRUE,
  1082. X   "off",    3,   FALSE,
  1083. X   CHARNULL
  1084. X};
  1085. X
  1086. X/**^^**********************************************************************/
  1087. X
  1088. X
  1089. X   /*
  1090. X   ** NOTE: Lists and vectors of Boolean types are not supported!!!
  1091. X   **       (same goes for argEnd, argInput, & argOutput)
  1092. X   */
  1093. X
  1094. X/*ARGSUSED*/
  1095. XBOOL argBool  PARMS(ad, vp, copyf)
  1096. X{
  1097. X   register struct booltab *b;
  1098. X   register char *cp;
  1099. X   argName_t  argname;
  1100. X   int len;
  1101. X
  1102. X   (VOID) get_argname( arg_sname(ad), argname );
  1103. X
  1104. X   /* ARGVECs are not supported for this Boolean arg-types */
  1105. X   if ( ARG_isVEC(ad) )
  1106. X      syserr( "Error in '%s' arg-entry! Boolean argvecs are not supported!",
  1107. X            argname );
  1108. X
  1109. X   /* if vp is NULL, just set to TRUE
  1110. X   **    (needed for backward compatibility)
  1111. X   */
  1112. X   if ( !vp || !*vp ) {
  1113. X      *(BOOL *) arg_valp(ad) = TRUE;
  1114. X      return (TRUE);
  1115. X   }
  1116. X
  1117. X      /* allow single character arguments for non-keywords */
  1118. X   if ( !BTEST(arg_flags(ad), ARGKEYWORD | ARGVALSEP) ) {
  1119. X      if ( *vp == '+' || *vp == '1' ) {
  1120. X         *(BOOL *) arg_valp(ad) = TRUE;
  1121. X         return (BOOL) -1;
  1122. X      }
  1123. X      if ( *vp == '-' || *vp == '0' ) {
  1124. X         *(BOOL *) arg_valp(ad) = FALSE;
  1125. X         return (BOOL) -1;
  1126. X      }
  1127. X      if ( *vp == '~' || *vp == '^' ) {
  1128. X         *(BOOL *) arg_valp(ad) = (*(BOOL *) arg_valp(ad)) ? FALSE : TRUE;
  1129. X         return (BOOL) -1;
  1130. X      }
  1131. X
  1132. X         /* unmatched value, return FALSE for non-argBool (so the caller
  1133. X         ** can use whatever default) and return TRUE for argBool.
  1134. X         */
  1135. X      if ( arg_type(ad) == argBool ) {
  1136. X         *(BOOL *) arg_valp(ad) = TRUE;
  1137. X         return  TRUE;
  1138. X      }
  1139. X      return  FALSE;
  1140. X   }/* if single char option */
  1141. X
  1142. X   /* copy input & convert to lower case */
  1143. X   cp = strlwr( strdup(vp) );
  1144. X   len = strlen( cp );
  1145. X
  1146. X   /* search for a match in the table */
  1147. X   for (b = _BoolTab; b->bname ; b++) {
  1148. X      /* if too short, don't even bother trying */
  1149. X      if (len < b->bneedmatch)
  1150. X         continue;
  1151. X
  1152. X      if ( memcmp(cp, b->bname, len) == 0) {
  1153. X         /* got a match */
  1154. X         *(BOOL *) arg_valp(ad) = b->bval;
  1155. X         free( cp );
  1156. X         return (TRUE);
  1157. X      }
  1158. X   }/*if match*/
  1159. X
  1160. X   free( cp );
  1161. X   usrerr("invalid Boolean argument '%s' for %s", vp, argname);
  1162. X   return (FALSE);
  1163. X}
  1164. X
  1165. X
  1166. X/*ARGSUSED*/
  1167. XBOOL argSBool  PARMS(ad, vp, copyf)
  1168. X{
  1169. X   argName_t  argname;
  1170. X   BOOL  retval;
  1171. X
  1172. X   (VOID) get_argname( arg_sname(ad), argname );
  1173. X
  1174. X   /* ARGVECs are not supported for this Boolean arg-types */
  1175. X   if ( ARG_isVEC(ad) )
  1176. X      syserr( "Error in '%s' arg-entry! Boolean argvecs are not supported!",
  1177. X            argname );
  1178. X
  1179. X   /* if vp is NULL, just set to TRUE */
  1180. X   if ( !vp || !*vp || !(retval = argBool(ad, vp, copyf)) ) {
  1181. X      *(BOOL *) arg_valp(ad) = TRUE;
  1182. X      return (TRUE);
  1183. X   }
  1184. X   else
  1185. X      return  retval;
  1186. X}
  1187. X
  1188. X/*ARGSUSED*/
  1189. XBOOL argUBool  PARMS(ad, vp, copyf)
  1190. X{
  1191. X   argName_t  argname;
  1192. X   BOOL  retval;
  1193. X
  1194. X   (VOID) get_argname( arg_sname(ad), argname );
  1195. X
  1196. X   /* ARGVECs are not supported for this Boolean arg-types */
  1197. X   if ( ARG_isVEC(ad) )
  1198. X      syserr( "Error in '%s' arg-entry! Boolean argvecs are not supported!",
  1199. X            argname );
  1200. X
  1201. X   /* if vp is NULL, just set to FALSE */
  1202. X   if ( !vp || !*vp || !(retval = argBool(ad, vp, copyf)) ) {
  1203. X      *(BOOL *) arg_valp(ad) = FALSE;
  1204. X      return (TRUE);
  1205. X   }
  1206. X   else
  1207. X      return retval;
  1208. X}
  1209. X
  1210. X/*ARGSUSED*/
  1211. XBOOL argTBool  PARMS(ad, vp, copyf)
  1212. X{
  1213. X   argName_t  argname;
  1214. X   BOOL  retval;
  1215. X
  1216. X   (VOID) get_argname( arg_sname(ad), argname );
  1217. X
  1218. X   /* ARGVECs are not supported for this Boolean arg-types */
  1219. X   if ( ARG_isVEC(ad) )
  1220. X      syserr( "Error in '%s' arg-entry! Boolean argvecs are not supported!",
  1221. X            argname );
  1222. X
  1223. X   /* if vp is NULL, just toggle value */
  1224. X   if ( !vp || !*vp || !(retval = argBool(ad, vp, copyf)) ) {
  1225. X      *(BOOL *) arg_valp(ad) = (*(BOOL *) arg_valp(ad)) ? FALSE : TRUE ;
  1226. X      return (TRUE);
  1227. X   }
  1228. X   else
  1229. X      return retval;
  1230. X}
  1231. X
  1232. X
  1233. X#ifdef vms_style
  1234. X
  1235. X/***************************************************************************
  1236. X** ^SECTION: I/O-REDIRECTION-TYPES -- argInput, argOutput
  1237. X**    ArgInput attempts to redirect the file-pointer addressed by ad_valp
  1238. X**    to the file named by the given value. The file is opened for reading.
  1239. X**
  1240. X**    ArgOutput attempts to redirect the file-pointer addressed by ad_valp
  1241. X**    to the file named by the given value. The file is opened for writing.
  1242. X**
  1243. X**    In either case, ad_valp should be of type (FILE **) (a pointer to a
  1244. X**    file pointer) and not a mere file pointer as in (FILE *)!!!
  1245. X**
  1246. X**    If the given files cannot be opened, then an error message is printed
  1247. X**    and the associated input/output streams are closed.
  1248. X***^^**********************************************************************/
  1249. X
  1250. X   /*
  1251. X   ** slight problem here - on VMS, as_valp should be of type FILE **
  1252. X   ** but on Unix (emulating VMS) it needs to be of type FILE *.
  1253. X   ** we get around this using the following:
  1254. X   */
  1255. X# ifdef vms
  1256. X#  define FP *fp
  1257. X# else
  1258. X#  define FP fp
  1259. X# endif
  1260. X
  1261. X/*ARGSUSED*/
  1262. XBOOL argInput  PARMS(ad, vp, copyf)
  1263. X{
  1264. X#ifdef vms
  1265. X   FILE **fp = (FILE **)arg_valp(ad);
  1266. X#else
  1267. X   FILE *fp = (FILE *)arg_valp(ad);
  1268. X#endif
  1269. X   BOOL error = FALSE;
  1270. X
  1271. X   /* redirect file pointer to read from file */
  1272. X   if ( !vp ) {
  1273. X      usrerr( "Error: no file name given" );
  1274. X      error = TRUE;
  1275. X   }
  1276. X
  1277. X   if ( !error  &&  !FP )
  1278. X      error = TRUE;
  1279. X   else if ( !error  &&  !freopen(vp, "r", FP) )
  1280. X      error = TRUE;
  1281. X
  1282. X   if ( error )  {
  1283. X      usrerr( "Error: unable to redirect input to file \"%s.\"", vp );
  1284. X      return  (FALSE);
  1285. X   }
  1286. X   return (TRUE);
  1287. X}
  1288. X
  1289. X
  1290. X/*ARGSUSED*/
  1291. XBOOL argOutput  PARMS(ad, vp, copyf)
  1292. X{
  1293. X#ifdef vms
  1294. X   FILE **fp = (FILE **)arg_valp(ad);
  1295. X#else
  1296. X   FILE *fp = (FILE *)arg_valp(ad);
  1297. X#endif
  1298. X   BOOL error = FALSE;
  1299. X
  1300. X   /* redirect file pointer to write to file */
  1301. X   if ( !vp ) {
  1302. X      usrerr( "Error: no file name given" );
  1303. X      error = TRUE;
  1304. X   }
  1305. X
  1306. X   if ( !error  &&  !FP )
  1307. X      error = TRUE;
  1308. X   else if ( !error  &&  !freopen(vp, "a", FP) )
  1309. X      error = TRUE;
  1310. X
  1311. X   if ( error )  {
  1312. X      usrerr( "Error: unable to redirect output to file \"%s.\"", vp );
  1313. X      return  (FALSE);
  1314. X   }
  1315. X   return (TRUE);
  1316. X}
  1317. X
  1318. X# undef FP
  1319. X#endif  /* vms_style */
  1320. END_OF_FILE
  1321. if test 22859 -ne `wc -c <'argtype.c'`; then
  1322.     echo shar: \"'argtype.c'\" unpacked with wrong size!
  1323. fi
  1324. # end of 'argtype.c'
  1325. fi
  1326. if test -f 'unix_args.c' -a "${1}" != "-c" ; then 
  1327.   echo shar: Will not clobber existing file \"'unix_args.c'\"
  1328. else
  1329. echo shar: Extracting \"'unix_args.c'\" \(23539 characters\)
  1330. sed "s/^X//" >'unix_args.c' <<'END_OF_FILE'
  1331. X/*************************************************************************
  1332. X** ^FILE: unix_args.c - parse Unix argument vectors
  1333. X**
  1334. X** ^DESCRIPTION:
  1335. X**    This file contains the routines used to parse Unix argument
  1336. X**    vectors and to print Unix usage messages.
  1337. X**
  1338. X** ^HISTORY:
  1339. X**    12/05/91     Brad Appleton     <brad@ssd.csd.harris.com>
  1340. X**    - added #ifdef POSIX_SOURCE to use "--" instead of "+" as
  1341. X**      GNU conformant prefix for long options.
  1342. X**
  1343. X**    08/27/91     Earl Chew     <cechew@bruce.cs.monash.edu.au>
  1344. X**    - Use ProgNameLen when accessing ProgName
  1345. X**    - Use get_argdesc() to access description
  1346. X**
  1347. X**    01/02/91     Brad Appleton     <brad@ssd.csd.harris.com>
  1348. X**    - Added structured block comments
  1349. X**    - Added optional arguments to keywords and options
  1350. X**
  1351. X**    --/--/--    Peter da Silva    <peter@ferranti.com>    
  1352. X**
  1353. X**    --/--/--    Eric P. Allman    <eric@Berkeley.EDU>     Created
  1354. X***^^**********************************************************************/
  1355. X
  1356. X#include <ctype.h>
  1357. X#include <useful.h>
  1358. X#include "strfuncs.h"
  1359. X#include "pgopen.h"
  1360. X#include "exit_codes.h"
  1361. X
  1362. X#define PARSEARGS_PRIVATE   /* include private definitions */
  1363. X#include "parseargs.h"
  1364. X
  1365. XEXTERN  VOID  syserr       ARGS((const char *, ...));
  1366. XEXTERN  VOID  usrerr       ARGS((const char *, ...));
  1367. XEXTERN  char *getenv       ARGS((const char *));
  1368. XEXTERN  VOID  get_winsize  ARGS((int, int *, int *));
  1369. X
  1370. XVERSIONID("$Header: parseargs.c,v 2.1 89/12/30 20:59:48 eric Exp $");
  1371. X
  1372. X
  1373. X/***************************************************************************
  1374. X** ^GLOBAL-VARIABLE: Usage_Requested
  1375. X**
  1376. X** ^VISIBILITY:
  1377. X**    static-global (visible to all functions in this file).
  1378. X**
  1379. X** ^DESCRIPTION:
  1380. X**    Indicates whether a usage message was requested by the user
  1381. X**    (as opposed to triggered by a syntax error).  If the message
  1382. X**    is requested by the user then it is always printed in verbose
  1383. X**    mode and does not return an error-status-code.
  1384. X***^^**********************************************************************/
  1385. Xstatic  BOOL  Usage_Requested = (BOOL) FALSE;
  1386. X
  1387. X
  1388. X   /* macros to detect an option/keyword -- watch out for side effects!! */
  1389. X#define isOPT(s)  \
  1390. X   ( !BTEST(cmd_flags(cmd), pa_KWDSONLY)  && \
  1391. X     !BTEST(cmd_state(cmd), ps_NOFLAGS)  && \
  1392. X     (*s == c_OPT_PFX)  &&  *(s+1) \
  1393. X   )
  1394. X
  1395. X#ifndef POSIX_SOURCE
  1396. X#define isKWD(s)  \
  1397. X   ( !BTEST(cmd_flags(cmd), pa_OPTSONLY)  && \
  1398. X     !BTEST(cmd_state(cmd), ps_NOFLAGS)  && \
  1399. X     (*s == c_KWD_PFX)  &&  *(s+1) \
  1400. X   )
  1401. X#else
  1402. X#define isKWD(s)  \
  1403. X   ( !BTEST(cmd_flags(cmd), pa_OPTSONLY)  && \
  1404. X     !BTEST(cmd_state(cmd), ps_NOFLAGS)  && \
  1405. X     (*s == c_OPT_PFX)  &&  (*(s+1) == c_OPT_PFX)  &&  *(s+2) \
  1406. X   )
  1407. X#endif
  1408. X
  1409. X
  1410. X/***************************************************************************
  1411. X** ^FUNCTION: unix_parse - parse Unix arg-vectors
  1412. X**
  1413. X** ^SYNOPSIS:
  1414. X*/
  1415. X#ifndef __ANSI_C__
  1416. X   int unix_parse( argv, argd )
  1417. X/*  
  1418. X** ^PARAMETERS:
  1419. X*/
  1420. X   char *argv[];
  1421. X/*    -- the vector of string arguments from the command-line
  1422. X*/
  1423. X   ARGDESC argd[];
  1424. X/*    -- the programmer description of the command and its args
  1425. X*/
  1426. X#endif  /* !__ANSI_C__ */
  1427. X
  1428. X/* ^DESCRIPTION:
  1429. X**    Unix_parse will parse the arguments in the given vector of strings,
  1430. X**    assign the corresponding values to the command-line arguments specified
  1431. X**    in argd, and check the syntax of the command-line.
  1432. X**
  1433. X** ^REQUIREMENTS:
  1434. X**    The final element in argv must be a NULL pointer.
  1435. X**
  1436. X** ^SIDE-EFFECTS:
  1437. X**    argd is modified according to the command-line description and parameters
  1438. X**
  1439. X** ^RETURN-VALUE:
  1440. X**    pe_SUCCESS (0) if no errors are encountered
  1441. X**    pe_SYSTEM (-1) if a system error is encountered
  1442. X**    pe_SYNTAX if a syntax error is encountered
  1443. X**
  1444. X** ^ALGORITHM:
  1445. X**    - for each command-line argument
  1446. X**       - attempt to match the argument as a keyword
  1447. X**       - if it is a keyword argument
  1448. X**          - record and convert its value (if any)
  1449. X**         else attempt to match the argument as an option
  1450. X**         if it is an option
  1451. X**          - record and convert its value (if any)
  1452. X**         else it is a positional parameter
  1453. X**          - record and convert its value (if any)
  1454. X**         else there are too many arguments
  1455. X**          - return pe_SYNTAX
  1456. X**         end-if
  1457. X**       end-for
  1458. X***^^**********************************************************************/
  1459. X#ifdef __ANSI_C__
  1460. X   int unix_parse( char *argv[], ARGDESC argd[] )
  1461. X#endif
  1462. X{
  1463. X   register ARGDESC *ad, *args, *cmd;
  1464. X   register char **av = argv;
  1465. X   register char *p;
  1466. X   argName_t  name;
  1467. X   argMask_t  flags;
  1468. X   int  parse_error = pe_SUCCESS;
  1469. X   BOOL  ad_okay, is_match = FALSE;
  1470. X
  1471. X   if ( !argd )  return  parse_error;
  1472. X
  1473. X      /* initialize command-structure */
  1474. X   if ( !CMD_isINIT(argd) )  init_args( argd );
  1475. X   cmd = argd;
  1476. X
  1477. X   while ( av  &&  (p = *av++) ) {
  1478. X      if ( isKWD(p) ) {  /* we have a keyword here */
  1479. X         char *s, c = '\0';
  1480. X
  1481. X#ifndef POSIX_SOURCE
  1482. X         /* check for `++' to end flags */
  1483. X         if ( *(p+1) == c_KWD_PFX  &&  !*(p+2) ) {
  1484. X            BSET( cmd_state(cmd), ps_NOFLAGS );
  1485. X            cmd_list(cmd) = ARGDESCNULL;
  1486. X            continue;
  1487. X         }
  1488. X#endif
  1489. X
  1490. X            /* get past prefix and look for possible argument */
  1491. X#ifdef POSIX_SOURCE
  1492. X         ++p;
  1493. X#endif
  1494. X         s = strpbrk(++p, s_ARG_SEP);
  1495. X         if(s) {
  1496. X            c = *s;
  1497. X            *s++ = '\0';
  1498. X         }
  1499. X
  1500. X         is_match = FALSE;
  1501. X         for ( args = argd ; args  &&  !is_match ; args = cmd_defargs(args) ) {
  1502. X            for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
  1503. X               if ( arg_type(ad) == argDummy )  continue;
  1504. X
  1505. X               if ( !ARG_isPOSONLY(ad)  &&  match(p, arg_sname(ad)) == 0 ) {
  1506. X                  is_match = TRUE;
  1507. X                  break;
  1508. X               }/*if*/
  1509. X            }
  1510. X         }
  1511. X
  1512. X         if ( c )  *(s-1) = c;  /* restore the equal sign */
  1513. X
  1514. X         if ( !is_match ) {
  1515. X#ifndef POSIX_SOURCE
  1516. X            usrerr("option %c%s unknown", c_KWD_PFX, p);
  1517. X#else
  1518. X            usrerr("option %c%c%s unknown", c_OPT_PFX, c_OPT_PFX, p);
  1519. X#endif
  1520. X            parse_error = pe_SYNTAX;
  1521. X            cmd_list(cmd) = ARGDESCNULL;
  1522. X            continue;
  1523. X         }
  1524. X
  1525. X         /* reset the argument flags - if this arg was already given, some
  1526. X         ** of its flags may be set to indicate how it was given before. 
  1527. X         ** we need to know how it was given now (but save the old ones
  1528. X         ** just in case the new one fails).
  1529. X         */
  1530. X         flags = arg_flags(ad);
  1531. X         if ( ARG_isGIVEN(ad) ) {
  1532. X            BCLEAR( arg_flags(ad), ARGVALSEP | ARGKEYWORD );
  1533. X            if ( !ARG_isMULTIVAL(ad) )  BCLEAR( arg_flags(ad), ARGVALGIVEN );
  1534. X         }
  1535. X
  1536. X         BSET( arg_flags(ad), ARGKEYWORD );
  1537. X
  1538. X         if( ARG_isMULTIVAL(ad) ) { /* we matched a list (or a vector) */
  1539. X            cmd_list(cmd) = ad;
  1540. X         }
  1541. X         else {
  1542. X            cmd_list(cmd) = ARGDESCNULL;
  1543. X         }
  1544. X
  1545. X            /* if usage - just print usage and exit */
  1546. X         if ( arg_type(ad) == argUsage ) {
  1547. X            Usage_Requested = TRUE;
  1548. X            usage(argd);
  1549. X            exit(exit_USAGE);
  1550. X         }
  1551. X
  1552. X            /* ARGNOVALs are special, having no value */
  1553. X         if ( ! ARG_isVALTAKEN(ad) ) {
  1554. X            ad_okay = HANDLE(ad, s, cmd_flags(cmd));
  1555. X            if ( !ad_okay ) {
  1556. X               arg_flags(ad) = flags;
  1557. X               parse_error = pe_SYNTAX;
  1558. X            }
  1559. X            else {
  1560. X               BSET( arg_flags(ad), ARGGIVEN );
  1561. X               ad = ARGDESCNULL;
  1562. X            }
  1563. X            continue;
  1564. X         }/*if ARGNOVAL*/
  1565. X
  1566. X            /* now get the real value */
  1567. X         if (!s) {
  1568. X            s = *av++;
  1569. X            if ( !s  ||  isOPT(s)  ||  isKWD(s) ) {
  1570. X               if ( ARG_isVALOPTIONAL(ad) ) {
  1571. X                  BSET( arg_flags(ad), ARGGIVEN );
  1572. X               }
  1573. X               else {
  1574. X                  (VOID) get_kwdname( arg_sname(ad), name );
  1575. X                  usrerr("option %c%s requires an argument", c_KWD_PFX, name);
  1576. X                  arg_flags(ad) = flags;
  1577. X                  parse_error = pe_SYNTAX;
  1578. X               }
  1579. X
  1580. X               av--;
  1581. X               continue;
  1582. X            }/*if arg*/
  1583. X            BSET( arg_flags(ad), ARGVALSEP );
  1584. X         }/*if empty*/
  1585. X
  1586. X            /* try to convert the type */
  1587. X         ad_okay = HANDLE(ad, s, cmd_flags(cmd));
  1588. X         if ( !ad_okay ) {
  1589. X            arg_flags(ad) = flags;
  1590. X            parse_error = pe_SYNTAX;
  1591. X         }
  1592. X         else {
  1593. X            BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
  1594. X         }
  1595. X
  1596. X         continue;
  1597. X      }/*if keyword*/
  1598. X
  1599. X      else if ( isOPT(p) ) {
  1600. X         p++;  /* skip over option prefix */
  1601. X
  1602. X            /* check for `--' to end flags */
  1603. X         if ( *p == c_OPT_PFX  &&  !*(p+1) ) {
  1604. X            BSET( cmd_state(cmd), ps_NOFLAGS );
  1605. X            cmd_list(cmd) = ARGDESCNULL;
  1606. X            continue;
  1607. X         }
  1608. X
  1609. X         /* We have a flag argument;
  1610. X         ** remember that in the case of single character keywords,
  1611. X         ** the conversion function (ad_type) tells us how many characters
  1612. X         ** were used. We need that information to decide how many 
  1613. X         ** characters to skip before the next iteration of the while loop.
  1614. X         */
  1615. X         while (*p) {
  1616. X
  1617. X               /* find the flag in the list */
  1618. X            is_match = FALSE;
  1619. X            for (args = argd; args  &&  !is_match ; args = cmd_defargs(args)) {
  1620. X               for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
  1621. X                  register char c1 = arg_cname(ad);
  1622. X                  register char c2 = *p;
  1623. X
  1624. X                  if ( arg_type(ad) == argDummy )   continue;
  1625. X                  if ( ARG_isPOSONLY(ad) )   continue;
  1626. X
  1627. X                  if ( BTEST(cmd_flags(cmd), pa_ANYCASE) ) {
  1628. X                     c1 = TOUPPER( c1 );
  1629. X                     c2 = TOUPPER( c2 );
  1630. X                  }/*if*/
  1631. X
  1632. X                  if ( c1 == c2 ) {
  1633. X                     is_match = TRUE;
  1634. X                     break;
  1635. X                  }/*if*/
  1636. X               }
  1637. X            }
  1638. X            if ( !is_match ) {
  1639. X                  usrerr("option %c%c unknown", c_OPT_PFX, *p++);
  1640. X                  parse_error = pe_SYNTAX;
  1641. X                  cmd_list(cmd) = ARGDESCNULL;
  1642. X                  continue;
  1643. X            }/* if unknown-option */
  1644. X
  1645. X            /* reset the argument flags - if this arg was already given, some
  1646. X            ** of its flags may be set to indicate how it was given before.
  1647. X            ** we need to know how it was given now (but save the old ones
  1648. X            ** just in case the new one fails).
  1649. X            */
  1650. X            flags = arg_flags(ad);
  1651. X            if ( ARG_isGIVEN(ad) ) {
  1652. X               BCLEAR( arg_flags(ad), ARGVALSEP | ARGKEYWORD );
  1653. X               if ( !ARG_isMULTIVAL(ad) )  BCLEAR( arg_flags(ad), ARGVALGIVEN );
  1654. X            }
  1655. X
  1656. X            if( ARG_isMULTIVAL(ad) ) {
  1657. X               cmd_list(cmd) = ad;  /* we matched a list (or a vector) */
  1658. X            }
  1659. X            else {
  1660. X               cmd_list(cmd) = ARGDESCNULL;
  1661. X            }
  1662. X
  1663. X               /* move p up to point to the (possible) value */
  1664. X            p++;
  1665. X
  1666. X            /* if usage - just print usage and exit */
  1667. X            if (arg_type(ad) == argUsage) {
  1668. X               Usage_Requested = TRUE;
  1669. X               usage(argd);
  1670. X               exit(exit_USAGE);
  1671. X            }
  1672. X
  1673. X               /* ARGNOVALs are special, having no value */
  1674. X            if (! ARG_isVALTAKEN(ad)) {
  1675. X               ad_okay = HANDLE(ad, p, cmd_flags(cmd));
  1676. X
  1677. X               if ( !ad_okay ) {
  1678. X                  arg_flags(ad) = flags;
  1679. X                  parse_error = pe_SYNTAX;
  1680. X               }/*if*/
  1681. X               else {
  1682. X                  BSET( arg_flags(ad), ARGGIVEN );
  1683. X                  ad = ARGDESCNULL;
  1684. X                  if ( ad_okay < 0 )  p -= ad_okay;
  1685. X               }/*else*/
  1686. X
  1687. X               continue;
  1688. X            }/*if*/
  1689. X
  1690. X               /* now get the real value */
  1691. X            if ( !(*p) ) {
  1692. X               p = *av++;
  1693. X               if ( !p  ||  isOPT(p)  ||  isKWD(p) ) {
  1694. X                  if ( ARG_isVALOPTIONAL(ad) ) {
  1695. X                     BSET( arg_flags(ad), ARGGIVEN );
  1696. X                  }
  1697. X                  else {
  1698. X                     (VOID) get_argname(arg_sname(ad), name);
  1699. X                     usrerr( "%s required for %c%c flag",
  1700. X                             name, c_OPT_PFX, arg_cname(ad) );
  1701. X                     arg_flags(ad) = flags;
  1702. X                     parse_error = pe_SYNTAX;
  1703. X                  }/*else*/
  1704. X
  1705. X                  av--;
  1706. X                  break;
  1707. X               }/*if arg*/
  1708. X               BSET( arg_flags(ad), ARGVALSEP );
  1709. X            }/*if empty*/
  1710. X
  1711. X               /* try to convert the type */
  1712. X            ad_okay = HANDLE(ad, p, cmd_flags(cmd));
  1713. X            if ( !ad_okay ) {
  1714. X               arg_flags(ad) = flags;
  1715. X               parse_error = pe_SYNTAX;
  1716. X               p += strlen(p);
  1717. X            }/*if*/
  1718. X            else {
  1719. X               BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
  1720. X               if ( ad_okay < 0  &&  !ARG_isVALSEPARATE(ad) ) {
  1721. X                  p -= ad_okay;
  1722. X               }
  1723. X               else {
  1724. X                  p += strlen(p);
  1725. X               }
  1726. X            }/*else*/
  1727. X
  1728. X         }/*while*/
  1729. X      }/*elif option*/
  1730. X      else {
  1731. X            /* parsing a list of arguments */
  1732. X         if ( cmd_list(cmd) ) {  /* we're in the middle of a list */
  1733. X            ad = cmd_list(cmd);
  1734. X
  1735. X            /* reset the argument flags - if this arg was already given, some
  1736. X            ** of its flags may be set to indicate how it was given before.
  1737. X            ** we need to know how it was given now (but save the old ones
  1738. X            ** just in case the new one fails).
  1739. X            */
  1740. X            flags = arg_flags(ad);
  1741. X            if ( ARG_isGIVEN(ad) ) {
  1742. X               BCLEAR( arg_flags(ad), ARGVALSEP | ARGKEYWORD );
  1743. X            }
  1744. X
  1745. X            BSET( arg_flags(ad), ARGVALSEP );
  1746. X
  1747. X            ad_okay = HANDLE(ad, p, cmd_flags(cmd));
  1748. X            if ( !ad_okay ) {
  1749. X               arg_flags(ad) = flags;
  1750. X               parse_error = pe_SYNTAX;
  1751. X            }
  1752. X
  1753. X            continue;
  1754. X         }
  1755. X            /* positional argument */
  1756. X         is_match = FALSE;
  1757. X         for (args = argd; args  &&  !is_match ; args = cmd_defargs(args)) {
  1758. X            for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
  1759. X               if (arg_type(ad) == argDummy)  continue;
  1760. X
  1761. X               if ( ARG_isPOSITIONAL(ad)  &&
  1762. X                    (!ARG_isGIVEN(ad) ||  ARG_isMULTIVAL(ad)) ) {
  1763. X                  is_match = TRUE;
  1764. X                  break;
  1765. X               }/*if*/
  1766. X            }
  1767. X         }
  1768. X
  1769. X         if ( !is_match ) {
  1770. X            usrerr("too many arguments");
  1771. X            parse_error = pe_SYNTAX;
  1772. X            continue;
  1773. X         }
  1774. X
  1775. X         /* reset the argument flags - if this arg was already given, some
  1776. X         ** of its flags may be set to indicate how it was given before.
  1777. X         ** we need to know how it was given now (but save the old ones
  1778. X         ** just in case the new one fails).
  1779. X         */
  1780. X         flags = arg_flags(ad);
  1781. X         if ( ARG_isGIVEN(ad) ) {
  1782. X            BCLEAR( arg_flags(ad), ARGVALSEP | ARGKEYWORD );
  1783. X            if ( !ARG_isMULTIVAL(ad) )  BCLEAR( arg_flags(ad), ARGVALGIVEN );
  1784. X         }
  1785. X
  1786. X         if ( ARG_isMULTIVAL(ad) ) {  /* we positionally matched a list */
  1787. X            cmd_list(cmd) = ad;
  1788. X         }
  1789. X
  1790. X         /* if FLAGS1ST is set then first positional marks end-of-flags */
  1791. X         if ( BTEST(cmd_flags(cmd), pa_FLAGS1ST) ) {
  1792. X            BSET( cmd_state(cmd), ps_NOFLAGS );
  1793. X         }
  1794. X
  1795. X         BSET( arg_flags(ad), ARGVALSEP );
  1796. X
  1797. X            /* try to convert */
  1798. X         ad_okay = HANDLE(ad, p, cmd_flags(cmd));
  1799. X         if ( !ad_okay ) {
  1800. X            arg_flags(ad) = flags;
  1801. X            parse_error = pe_SYNTAX;
  1802. X         }
  1803. X         else {
  1804. X            BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
  1805. X         }
  1806. X      }/*else*/
  1807. X   }/*while*/
  1808. X
  1809. X   return  parse_error;
  1810. X}
  1811. X
  1812. X
  1813. X/***************************************************************************
  1814. X** ^FUNCTION: fmtarg - format command-argument syntax
  1815. X**
  1816. X** ^SYNOPSIS:
  1817. X*/
  1818. X#ifndef __ANSI_C__
  1819. X   static int fmtarg( ad, buf, usgflags )
  1820. X/*
  1821. X** ^PARAMETERS:
  1822. X*/
  1823. X   ARGDESC *ad;
  1824. X/*    -- pointer to the argument to format
  1825. X*/
  1826. X   char *buf;
  1827. X/*    -- character buffer to hold the formatted result
  1828. X*/
  1829. X   argMask_t usgflags;
  1830. X/*    -- set of bitmasks corresponding to the value of the user's USAGECNTL
  1831. X**       environment variable
  1832. X*/
  1833. X#endif  /* !__ANSI_C__ */
  1834. X
  1835. X/* ^DESCRIPTION:
  1836. X**    Fmtarg will determine the proper command-line syntax for the
  1837. X**    given argument and write the result to the given buffer.
  1838. X**
  1839. X** ^REQUIREMENTS:
  1840. X**    buf must be large enough to hold the formatted result (100 characters
  1841. X**    should do the trick).
  1842. X**
  1843. X** ^SIDE-EFFECTS:
  1844. X**    buf is overwritten.
  1845. X**
  1846. X** ^RETURN-VALUE:
  1847. X**    The number of printable characters in the argument-syntax-string
  1848. X**
  1849. X** ^ALGORITHM:
  1850. X**    Print argument usage based on whether or not the argument is
  1851. X**    positional, hidden, multi-valued (list or vector), etc ....
  1852. X**    Optional arguments and values are enclosed in square braces.
  1853. X**
  1854. X**    Any syntax biases reflected in usgflags will be used.
  1855. X***^^**********************************************************************/
  1856. X#ifdef __ANSI_C__
  1857. X   static int fmtarg ( const ARGDESC *ad, char *buf, argMask_t usgflags )
  1858. X#endif
  1859. X{
  1860. X   /* buf must already be large enough */
  1861. X   char *pos;
  1862. X   argName_t   name, keyword;
  1863. X
  1864. X   (VOID) get_argname( arg_sname(ad), name );
  1865. X
  1866. X   if (ARG_isPOSITIONAL(ad)) {
  1867. X      sprintf( buf, "<%s>", name );
  1868. X   }
  1869. X   else {
  1870. X      (VOID) get_kwdname( arg_sname(ad), keyword );
  1871. X
  1872. X      if ( isupper(arg_cname(ad))  &&  toupper(*keyword) == arg_cname(ad) ) {
  1873. X         *keyword = toupper(*keyword);
  1874. X      }
  1875. X
  1876. X      if ( !(usgflags & usg_LONGOPTS) ) {
  1877. X         sprintf( buf, "%c%c", c_OPT_PFX, arg_cname(ad) );
  1878. X      }
  1879. X      else if ( !(usgflags & usg_OPTS) ) {
  1880. X#ifndef POSIX_SOURCE
  1881. X         sprintf( buf, "%c%s", c_KWD_PFX, keyword );
  1882. X#else
  1883. X         sprintf( buf, "%c%c%s", c_OPT_PFX, c_OPT_PFX, keyword );
  1884. X#endif
  1885. X      }
  1886. X      else  {  /* use both */
  1887. X#ifndef POSIX_SOURCE
  1888. X         sprintf( buf, "%c%c|%c%s", c_OPT_PFX, arg_cname(ad),
  1889. X                                    c_KWD_PFX, keyword );
  1890. X#else
  1891. X         sprintf( buf, "%c%c|%c%c%s", c_OPT_PFX, arg_cname(ad),
  1892. X                                      c_OPT_PFX, c_OPT_PFX, keyword );
  1893. X#endif
  1894. X      }
  1895. X
  1896. X      pos = buf + strlen(buf);
  1897. X
  1898. X      if ( ARG_isVALTAKEN(ad)  &&  !ARG_isBOOLEAN(ad) &&  !ARG_isPSEUDOARG(ad) )
  1899. X      {
  1900. X         *(pos++) = ' ';
  1901. X
  1902. X         if  (ARG_isVALOPTIONAL(ad)) {
  1903. X            sprintf( pos, "[<%s>]", name);
  1904. X         }
  1905. X         else {
  1906. X            sprintf( pos, "<%s>", name );
  1907. X         }
  1908. X      }/*if*/
  1909. X   }/*else*/
  1910. X
  1911. X   return  strlen(buf);
  1912. X}
  1913. X
  1914. X
  1915. X/***************************************************************************
  1916. X** ^FUNCTION: unix_usage - print a usage message
  1917. X**
  1918. X** ^SYNOPSIS:
  1919. X*/
  1920. X#ifndef __ANSI_C__
  1921. X   VOID unix_usage( argd, usage_flags )
  1922. X/*
  1923. X** ^PARAMETERS:
  1924. X*/
  1925. X   ARGDESC *argd;
  1926. X/*    -- the command-descriptor array
  1927. X*/
  1928. X   argMask_t usage_flags;
  1929. X/*    -- flags set by $USAGECNTL
  1930. X*/
  1931. X#endif  /* !__ANSI_C__ */
  1932. X
  1933. X/* ^DESCRIPTION:
  1934. X**    Unix_usage will print the Unix command-line usage of the given
  1935. X**    command on standard diagnostic output (stderr). The content of the
  1936. X**    usage message is controlled by the bitmasks in usage_flags which
  1937. X**    correspond to the settings in the user's USAGECNTL variable.
  1938. X**
  1939. X** ^REQUIREMENTS:
  1940. X**    argd should be a non-null command-line argument-descriptor array
  1941. X**
  1942. X** ^SIDE-EFFECTS:
  1943. X**    Prints on stderr.
  1944. X**
  1945. X** ^RETURN-VALUE:
  1946. X**    None.
  1947. X**
  1948. X** ^ALGORITHM:
  1949. X**    - if no usage is desired then exit
  1950. X**    - if paging is requested print to the pager instead of stderr
  1951. X**    - print the command-line syntax
  1952. X**    - if the description is requested print it
  1953. X**    - if verbose mode is requested, print the description of each argument
  1954. X***^^**********************************************************************/
  1955. X#ifdef __ANSI_C__
  1956. X   void unix_usage ( const ARGDESC *argd, argMask_t usage_flags )
  1957. X#endif
  1958. X{
  1959. X   register CONST ARGDESC *ad, *args, *cmd;
  1960. X   int  max_cols = 80, max_lines  = 24;
  1961. X   int  ll, margin, options, longest, positionals;
  1962. X   BOOL first = TRUE;
  1963. X   FILE *fp;
  1964. X
  1965. X   if ( !argd )  return;
  1966. X
  1967. X      /* initialize command-structure */
  1968. X   if ( !CMD_isINIT(argd) )  init_args( (ARGDESC *)argd );
  1969. X   cmd = argd;
  1970. X
  1971. X      /* force verbose-mode if requested */
  1972. X   if ( Usage_Requested )   BSET( usage_flags, usg_VERBOSE );
  1973. X
  1974. X   if ( BTEST(usage_flags, usg_NONE) )  return;
  1975. X
  1976. X   fp = ( BTEST(usage_flags, usg_PAGED) )
  1977. X      ? pgopen( stderr, getenv("USAGE_PAGER") )
  1978. X      : stderr;
  1979. X
  1980. X      /* get screen size */
  1981. X   get_winsize( fileno(fp), &max_lines, &max_cols );
  1982. X
  1983. X   fprintf(fp, "Usage: %.*s", ProgNameLen, (ProgName) ? ProgName : "");
  1984. X
  1985. X   ll = ProgNameLen + 7;
  1986. X   margin = ll + 1;
  1987. X   longest = 0;
  1988. X
  1989. X      /* print Synopsis */
  1990. X   for ( positionals = 0 ; positionals < 2 ; positionals++ ) {
  1991. X      for ( args = argd ; args ; args = cmd_defargs(args) ) {
  1992. X         for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
  1993. X            argName_t  buf;
  1994. X            int pl;
  1995. X
  1996. X               /* don't display hidden arguments */
  1997. X            if ( ARG_isHIDDEN(ad) )  continue;
  1998. X            if ( !positionals  &&  ARG_isPOSITIONAL(ad) )  continue;
  1999. X            if ( positionals  &&  !ARG_isPOSITIONAL(ad) )  continue;
  2000. X
  2001. X               /* figure out how wide this parameter is (for printing) */
  2002. X            pl = fmtarg(ad, buf, usage_flags);
  2003. X
  2004. X            if ( pl > longest)  longest = pl;
  2005. X
  2006. X            if  ( ARG_isMULTIVAL(ad) ) {
  2007. X               strcat( buf, "..." );
  2008. X               pl += 3;
  2009. X            }
  2010. X            if ( !ARG_isREQUIRED(ad) ) {
  2011. X               pl += 2;
  2012. X            }
  2013. X
  2014. X            /* see if this will fit */
  2015. X            if ( (ll + pl + 1) > (max_cols - first) ) {
  2016. X                  /* no... start a new line */
  2017. X               fprintf(fp, "\n%*s", margin, "");
  2018. X               ll = margin;
  2019. X            }
  2020. X            else {
  2021. X                  /* yes... just throw in a space */
  2022. X               fputc(' ', fp);
  2023. X               ++ll;
  2024. X            }
  2025. X            ll += pl;
  2026. X
  2027. X               /* show the argument */
  2028. X            if ( !ARG_isREQUIRED(ad) )  fputc('[', fp);
  2029. X            fprintf(fp, buf);
  2030. X            if ( !ARG_isREQUIRED(ad) )  fputc(']', fp);
  2031. X
  2032. X            first = FALSE;  /* not first line anymore */
  2033. X         }/*for each ad */
  2034. X      }/* for each argd */
  2035. X   }/* for each parm-type */
  2036. X
  2037. X   fputc('\n', fp);
  2038. X
  2039. X   if ( BTEST(usage_flags, usg_DESCRIPTION) ) {
  2040. X      CONST char *description = cmd_description(cmd);
  2041. X
  2042. X      if ( description  &&  *description ) {
  2043. X         fprintf( fp, "Description:\n" );
  2044. X         indent_para(fp, max_cols, 8, "", 0, description, 0);
  2045. X         fputc( '\n', fp );
  2046. X      }
  2047. X   }/*if*/
  2048. X
  2049. X   if ( !BTEST(usage_flags, usg_VERBOSE) )  {
  2050. X      if ( pgactive(fp) )  (VOID) pgclose( fp );
  2051. X      return;
  2052. X   }
  2053. X
  2054. X   options = 0;
  2055. X
  2056. X      /* print Argument descriptions */
  2057. X   for ( positionals = 0 ; positionals < 2 ; positionals++ ) {
  2058. X      for ( args = argd ; args ; args = cmd_defargs(args) ) {
  2059. X         for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
  2060. X            argName_t  buf;
  2061. X            char  *desc;
  2062. X            int  desclen;
  2063. X
  2064. X               /* don't display hidden arguments */
  2065. X            if ( ARG_isHIDDEN(ad) )  continue;
  2066. X            if ( !positionals  &&  ARG_isPOSITIONAL(ad) )  continue;
  2067. X            if ( positionals  &&  !ARG_isPOSITIONAL(ad) )  continue;
  2068. X
  2069. X            if ( !options++ )   fprintf(fp, "Options/Arguments:\n");
  2070. X            fmtarg(ad, buf, usage_flags);
  2071. X            desc = get_argdesc(arg_description(ad), &desclen);
  2072. X            indent_para( fp, max_cols, 8, buf, longest+2, desc, desclen );
  2073. X         }/*for each ad */
  2074. X      }/* for each argd */
  2075. X   }/* for each parm-type */
  2076. X
  2077. X   if ( pgactive(fp) )  (VOID) pgclose( fp );
  2078. X}
  2079. X
  2080. END_OF_FILE
  2081. if test 23539 -ne `wc -c <'unix_args.c'`; then
  2082.     echo shar: \"'unix_args.c'\" unpacked with wrong size!
  2083. fi
  2084. # end of 'unix_args.c'
  2085. fi
  2086. echo shar: End of archive 5 \(of 10\).
  2087. cp /dev/null ark5isdone
  2088. MISSING=""
  2089. for I in 1 2 3 4 5 6 7 8 9 10 ; do
  2090.     if test ! -f ark${I}isdone ; then
  2091.     MISSING="${MISSING} ${I}"
  2092.     fi
  2093. done
  2094. if test "${MISSING}" = "" ; then
  2095.     echo You have unpacked all 10 archives.
  2096.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2097. else
  2098.     echo You still need to unpack the following archives:
  2099.     echo "        " ${MISSING}
  2100. fi
  2101. ##  End of shell archive.
  2102. exit 0
  2103.  
  2104. exit 0 # Just in case...
  2105.