home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume17 / parseargs / part05 < prev    next >
Encoding:
Internet Message Format  |  1991-03-18  |  61.3 KB

  1. From: brad@hcx1.ssd.csd.harris.com (Brad Appleton)
  2. Newsgroups: comp.sources.misc
  3. Subject: v17i050:  parseargs - functions to parse command line arguments, Part05/12
  4. Message-ID: <1991Mar17.200712.17928@sparky.IMD.Sterling.COM>
  5. Date: 17 Mar 91 20:07:12 GMT
  6. Approved: kent@sparky.imd.sterling.com
  7. X-Checksum-Snefru: 05f305bf 9dbcc514 b4c32c2f 672882ff
  8.  
  9. Submitted-by: Brad Appleton <brad@hcx1.ssd.csd.harris.com>
  10. Posting-number: Volume 17, Issue 50
  11. Archive-name: parseargs/part05
  12.  
  13. This is part 5 of parseargs
  14.  
  15. #!/bin/sh
  16. # this is Part.05 (part 5 of a multipart archive)
  17. # do not concatenate these parts, unpack them in order with /bin/sh
  18. # file parseargs/ibm_args.c continued
  19. #
  20. if test ! -r _shar_seq_.tmp; then
  21.     echo 'Please unpack part 1 first!'
  22.     exit 1
  23. fi
  24. (read Scheck
  25.  if test "$Scheck" != 5; then
  26.     echo Please unpack part "$Scheck" next!
  27.     exit 1
  28.  else
  29.     exit 0
  30.  fi
  31. ) < _shar_seq_.tmp || exit 1
  32. if test ! -f _shar_wnt_.tmp; then
  33.     echo 'x - still skipping parseargs/ibm_args.c'
  34. else
  35. echo 'x - continuing file parseargs/ibm_args.c'
  36. sed 's/^X//' << 'SHAR_EOF' >> 'parseargs/ibm_args.c' &&
  37. **    an option switch on the command-line.
  38. **
  39. **    KwdPrefix contains the single character prefix used to precede
  40. **    a keyword switch on the command-line.
  41. ***^^**********************************************************************/
  42. static  char  OptPrefix='/';
  43. static  char  KwdPrefix='/';
  44. X
  45. #define  isUNIXISH  ( OptPrefix == '-' )
  46. X
  47. X
  48. /***************************************************************************
  49. ** ^GLOBAL-VARIABLE: Usage_Requested
  50. **
  51. ** ^VISIBILITY:
  52. **    static-global (visible to all functions in this file).
  53. **
  54. ** ^DESCRIPTION:
  55. **    Indicates whether a usage message was requested by the user
  56. **    (as opposed to triggerred by a syntax error).  If the message
  57. **    is requested by the user then it is always printed in verbose
  58. **    mode and does not return an error-status-code.
  59. ***^^**********************************************************************/
  60. static  BOOL  Usage_Requested = FALSE;
  61. X
  62. X
  63. X   /* macros to detect an option/keyword -- watch out for side effects!! */
  64. #define isOPT(s)  \
  65. X   ( !BTEST(cmd_flags(cmd), pa_KWDSONLY)  && \
  66. X     !BTEST(cmd_state(cmd), ps_NOFLAGS)  && \
  67. X     *s == OptPrefix  &&  *(s+1) \
  68. X   )
  69. X
  70. #define isKWD(s)  \
  71. X   ( !BTEST(cmd_flags(cmd), pa_OPTSONLY)  && \
  72. X     !BTEST(cmd_state(cmd), ps_NOFLAGS)  && \
  73. X     *s == KwdPrefix  &&  *(s+1) \
  74. X   )
  75. X
  76. X
  77. /***************************************************************************
  78. ** ^FUNCTION: get_prefixes - determine short and long keyword prefixes
  79. **
  80. ** ^SYNOPSIS:
  81. */
  82. #ifndef __ANSI_C__
  83. X   static VOID get_prefixes()
  84. #endif
  85. /*  
  86. ** ^PARAMETERS:
  87. **    None.
  88. **
  89. ** ^DESCRIPTION:
  90. **    Get_prefixes will determine the prefixes to used to denote option
  91. **    switches and keyword switches on the command-line.  The prefixes
  92. **    are determined by the $SWITCHAR environment varaible. The first
  93. **    character of the variable is the option-switch prefix and the second
  94. **    character is the keyword-switch prefix.
  95. **
  96. **    If The option-switch prefix is '-' then Unix-style command-line parsing
  97. **    is performed, otherwise MS-DOS style command-line parsing is used.
  98. **
  99. ** ^REQUIREMENTS:
  100. **    None.
  101. **
  102. ** ^SIDE-EFECTS:
  103. **    Sets the global variables "OptPrefix" and "KwdPrefix'.
  104. **
  105. ** ^RETURN-VALUE:
  106. **    None.
  107. **
  108. ** ^ALGORITHM:
  109. **    - If $SWITCHAR is NULL or empty
  110. **      - use the defaults ('/' and '/').
  111. **    - Else
  112. **      - set the OptPrefix to the first character in SWITCHAR
  113. **      End-if
  114. **
  115. **    - If there is a second character in SWITCHAR
  116. **      - assign it to KwdPrefix
  117. **    - Else if OptPrefix is '-'
  118. **      - then use '+' as the default KwdPrefix
  119. **    - Else
  120. **      - use '/' as the default KwdPrefix
  121. **      End-if
  122. ***^^**********************************************************************/
  123. #ifdef __ANSI_C__
  124. X   static VOID  get_prefixes( void )
  125. #endif
  126. {
  127. X   char *prefixes = getenv( "SWITCHAR" );
  128. X
  129. X   if ( prefixes &&  *prefixes ) {
  130. X      OptPrefix = *prefixes;
  131. X      KwdPrefix = *(prefixes + 1);
  132. X      if ( !KwdPrefix )  KwdPrefix = (( OptPrefix == '-' ) ? '+' : '/');
  133. X   }
  134. X   else {
  135. X      OptPrefix = '/';
  136. X      KwdPrefix = '/';
  137. X   }
  138. }
  139. X
  140. X
  141. /***************************************************************************
  142. ** ^FUNCTION: ibm_parse - parse MS-DOS and OS/2 arg-vectors
  143. **
  144. ** ^SYNOPSIS:
  145. */
  146. #ifndef __ANSI_C__
  147. X   int ibm_parse( argv, argd )
  148. /*
  149. ** ^PARAMETERS:
  150. */
  151. X   char *argv[];
  152. /*    -- the vector of string arguments from the command-line
  153. */
  154. X   ARGDESC argd[];
  155. /*    -- the programmer description of the command and its args
  156. */
  157. #endif  /* !__ANSI_C__ */
  158. X  
  159. /* ^DESCRIPTION:
  160. **    Ibm_parse will parse the arguments in the given vector of strings,
  161. **    assign the corresponding values to the command-line arguments specified
  162. **    in argd, and check the syntax of the command-line.
  163. **
  164. ** ^REQUIREMENTS:
  165. **    The final element in argv must be a NULL pointer.
  166. **
  167. ** ^SIDE-EFECTS:
  168. **    argd is modified according to the command-line description and parameters
  169. **
  170. ** ^RETURN-VALUE:
  171. **    pe_SUCCESS (0) if no errors are encountered
  172. **    pe_SYSTEM (-1) if a system error is encountered
  173. **    pe_SYNTAX if a syntax error is encountered
  174. **
  175. ** ^ALGORITHM:
  176. **    - get the active option and keyword prefixes
  177. **    - determine whether to use Unix style or not (based on the prefixes)
  178. **    - for each command-line argument
  179. **       - attempt to match the argument as a keyword
  180. **       - if it is a keyword argument
  181. **          - record and convert its value (if any)
  182. **         else attempt to match the argument as an option
  183. **         if it is an option
  184. **          - record and convert its value (if any)
  185. **         else it is a positional parameter
  186. **          - record and convert its value (if any)
  187. **         else there are too many arguments
  188. **          - return pe_SYNTAX
  189. **         end-if
  190. **       end-for
  191. ***^^**********************************************************************/
  192. #ifdef __ANSI_C__
  193. X   int ibm_parse( char *argv[], ARGDESC argd[] )
  194. #endif
  195. {
  196. X   register ARGDESC *ad, *args, *cmd;
  197. X   register char **av = argv;
  198. X   register char *p;
  199. X   argName_t  name;
  200. X   argMask_t  flags;
  201. X   int  parse_error = pe_SUCCESS;
  202. X   BOOL  ad_okay, is_match = FALSE;
  203. X
  204. X   if ( !argd )  return  parse_error;
  205. X
  206. X      /* initialize command-structure */
  207. X   if ( !CMD_isINIT(argd) )  init_args( argd );
  208. X   cmd = argd;
  209. X
  210. X   get_prefixes();
  211. X
  212. X   while ( av  &&  (p = *av++) ) {
  213. X      if ( isKWD(p) &&
  214. X          ( (OptPrefix != KwdPrefix) || *(p+2) && !strchr(s_ARG_SEP, *(p+2)) )
  215. X         ) {
  216. X         char *s, c = '\0';
  217. X
  218. X         /* check for `++' to end flags */
  219. X         if ( *(p+1) == KwdPrefix  &&  !*(p+2) ) {
  220. X            BSET( cmd_state(cmd), ps_NOFLAGS );
  221. X            cmd_list(cmd) = ARGDESCNULL;
  222. X            continue;
  223. X         }
  224. X
  225. X            /* get past prefix and look for possible argument */
  226. X         s = strpbrk(++p, s_ARG_SEP);
  227. X         if(s) {
  228. X            c = *s;
  229. X            *s++ = '\0';
  230. X         }
  231. X
  232. X         is_match = FALSE;
  233. X         for ( args = argd ; args  &&  !is_match ; args = cmd_defargs(args) ) {
  234. X            for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
  235. X               if ( arg_type(ad) == argDummy )  continue;
  236. X
  237. X               if ( !ARG_isPOSONLY(ad)  &&  match(p, arg_sname(ad)) == 0 ) {
  238. X                  is_match = TRUE;
  239. X                  break;
  240. X               }/*if*/
  241. X            }
  242. X         }
  243. X
  244. X         if ( c )  *(s-1) = c;  /* restore the equal sign */
  245. X
  246. X         if ( !is_match ) {
  247. X            if ( OptPrefix == KwdPrefix ) {
  248. X               goto  MATCHOPT;  /* maybe its an option (and NOT a keyword) */
  249. X            }
  250. X            usrerr("%c%s switch unknown", KwdPrefix, p);
  251. X            parse_error = pe_SYNTAX;
  252. X            cmd_list(cmd) = ARGDESCNULL;
  253. X            continue;
  254. X         }
  255. X
  256. X         flags = arg_flags(ad);
  257. X         if ( ARG_isGIVEN(ad) )
  258. X            BCLEAR( arg_flags(ad), ARGVALSEP | ARGVALGIVEN | ARGKEYWORD );
  259. X
  260. X         BSET( arg_flags(ad), ARGKEYWORD );
  261. X
  262. X         if( ARG_isMULTIVAL(ad) ) {
  263. X            cmd_list(cmd) = ad;
  264. X         }
  265. X         else {
  266. X            cmd_list(cmd) = ARGDESCNULL;
  267. X         }
  268. X
  269. X            /* if usage - just print usage and exit */
  270. X         if ( arg_type(ad) == argUsage ) {
  271. X            Usage_Requested = TRUE;
  272. X            usage(argd);
  273. X            exit(1);
  274. X         }
  275. X
  276. X            /* ARGNOVALs are special, having no value */
  277. X         if ( ! ARG_isVALTAKEN(ad) ) {
  278. X            ad_okay = HANDLE(ad, s, cmd_flags(cmd));
  279. X            if ( !ad_okay ) {
  280. X               arg_flags(ad) = flags;
  281. X               parse_error = pe_SYNTAX;
  282. X            }
  283. X            else {
  284. X               BSET( arg_flags(ad), ARGGIVEN );
  285. X               ad = ARGDESCNULL;
  286. X            }
  287. X            continue;
  288. X         }/*if ARGNOVAL*/
  289. X
  290. X            /* now get the real value */
  291. X         if (!s) {
  292. X            if ( isUNIXISH )  s = *av++;
  293. X            if ( !isUNIXISH  ||  !s  ||  isOPT(s)  ||  isKWD(s) ) {
  294. X               if ( ARG_isVALOPTIONAL(ad) ) {
  295. X                  BSET( arg_flags(ad), ARGGIVEN );
  296. X               }
  297. X               else {
  298. X                  (VOID) get_keyword( arg_sname(ad), name );
  299. X                  usrerr("%c%s switch requires an argument", KwdPrefix, name);
  300. X                  arg_flags(ad) = flags;
  301. X                  parse_error = pe_SYNTAX;
  302. X               }
  303. X
  304. X               if ( isUNIXISH )  av--;
  305. X               continue;
  306. X            }/*if arg*/
  307. X            if ( isUNIXISH )  BSET( arg_flags(ad), ARGVALSEP );
  308. X         }/*if empty*/
  309. X
  310. X            /* try to convert the type */
  311. X         ad_okay = HANDLE(ad, s, cmd_flags(cmd));
  312. X         if ( !ad_okay ) {
  313. X            arg_flags(ad) = flags;
  314. X            parse_error = pe_SYNTAX;
  315. X         }
  316. X         else {
  317. X            BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
  318. X         }
  319. X
  320. X         continue;
  321. X      }/*if keyword*/
  322. X      else if ( isOPT(p) ) {
  323. X         p++;  /* skip over option prefix */
  324. X
  325. MATCHOPT:
  326. X            /* check for `--' to end flags */
  327. X         if ( *p == OptPrefix  &&  !*(p+1) ) {
  328. X            BSET( cmd_state(cmd), ps_NOFLAGS );
  329. X            cmd_list(cmd) = ARGDESCNULL;
  330. X            continue;
  331. X         }
  332. X
  333. X            /* flag argument */
  334. X         while (*p) {
  335. X
  336. X               /* find the flag in the list */
  337. X            is_match = FALSE;
  338. X            for (args = argd; args  &&  !is_match ; args = cmd_defargs(args)) {
  339. X               for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
  340. X                  register char c1 = arg_cname(ad);
  341. X                  register char c2 = *p;
  342. X
  343. X                  if ( arg_type(ad) == argDummy )   continue;
  344. X                  if ( ARG_isPOSONLY(ad) )   continue;
  345. X
  346. X                  if ( BTEST(cmd_flags(cmd), pa_ANYCASE) ) {
  347. X                     c1 = TOUPPER( c1 );
  348. X                     c2 = TOUPPER( c2 );
  349. X                  }/*if*/
  350. X
  351. X                  if ( c1 == c2 ) {
  352. X                     is_match = TRUE;
  353. X                     break;
  354. X                  }/*if*/
  355. X               }
  356. X            }
  357. X            if ( !is_match ) {
  358. X                  usrerr("%c%c switch unknown", OptPrefix, *p++);
  359. X                  parse_error = pe_SYNTAX;
  360. X                  cmd_list(cmd) = ARGDESCNULL;
  361. X                  if ( !isUNIXISH  &&  *p == *s_ARG_SEP )  p += strlen(p);
  362. X                  if ( !isUNIXISH  &&  *p == OptPrefix )  ++p;
  363. X                  continue;
  364. X            }/* if unknown-option */
  365. X
  366. X            flags = arg_flags(ad);
  367. X            if ( ARG_isGIVEN(ad) )
  368. X               BCLEAR( arg_flags(ad), ARGVALSEP | ARGVALGIVEN | ARGKEYWORD );
  369. X
  370. X            if ( ARG_isMULTIVAL(ad) ) {
  371. X               cmd_list(cmd) = ad;
  372. X            }
  373. X            else {
  374. X               cmd_list(cmd) = ARGDESCNULL;
  375. X            }
  376. X
  377. X               /* move p up to point to the (possible) value */
  378. X            p++;
  379. X            if ( !isUNIXISH  &&  *p  &&  strchr(s_ARG_SEP, *p) )  ++p;
  380. X
  381. X            /* if usage - just print usage and exit */
  382. X            if (arg_type(ad) == argUsage) {
  383. X               Usage_Requested = TRUE;
  384. X               usage(argd);
  385. X               exit(1);
  386. X            }
  387. X
  388. X               /* ARGNOVALs are special, having no value */
  389. X            if (! ARG_isVALTAKEN(ad)) {
  390. X               ad_okay = HANDLE(ad, p, cmd_flags(cmd));
  391. X
  392. X               if ( !ad_okay ) {
  393. X                  arg_flags(ad) = flags;
  394. X                  parse_error = pe_SYNTAX;
  395. X               }/*if*/
  396. X               else {
  397. X                  BSET( arg_flags(ad), ARGGIVEN );
  398. X                  ad = ARGDESCNULL;
  399. X                  if ( ad_okay < 0 )  p -= ad_okay;
  400. X               }/*else*/
  401. X
  402. X               if ( !isUNIXISH  &&  *p == OptPrefix )  ++p;
  403. X               continue;
  404. X            }/*if*/
  405. X
  406. X               /* now get the real value */
  407. X            if ( !(*p) ) {
  408. X               if ( isUNIXISH )  p = *av++;
  409. X               if ( !isUNIXISH  ||  !p  ||  isOPT(p)  ||  isKWD(p) ) {
  410. X                  if ( ARG_isVALOPTIONAL(ad) ) {
  411. X                     BSET( arg_flags(ad), ARGGIVEN );
  412. X                  }
  413. X                  else {
  414. X                     (VOID) get_name(arg_sname(ad), name);
  415. X                     usrerr( "%s required for %c%c flag",
  416. X                             name, OptPrefix, arg_cname(ad) );
  417. X                     arg_flags(ad) = flags;
  418. X                     parse_error = pe_SYNTAX;
  419. X                  }/*else*/
  420. X
  421. X                  if ( isUNIXISH )  av--;
  422. X                  break;
  423. X               }/*if arg*/
  424. X               if ( isUNIXISH )  BSET( arg_flags(ad), ARGVALSEP );
  425. X            }/*if empty*/
  426. X
  427. X               /* try to convert the type */
  428. X            ad_okay = HANDLE(ad, p, cmd_flags(cmd));
  429. X            if ( !ad_okay ) {
  430. X               arg_flags(ad) = flags;
  431. X               parse_error = pe_SYNTAX;
  432. X               p += strlen(p);
  433. X            }/*if*/
  434. X            else {
  435. X               BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
  436. X               if ( isUNIXISH  &&  ad_okay < 0  &&  !ARG_isVALSEPARATE(ad) ) {
  437. X                  p -= ad_okay;
  438. X               }
  439. X               else {
  440. X                  p += strlen(p);
  441. X               }
  442. X            }/*else*/
  443. X
  444. X            if ( !isUNIXISH  &&  *p == OptPrefix )  ++p;
  445. X         }/*while*/
  446. X      }/*elif option*/
  447. X      else {
  448. X            /* parsing a list of arguments */
  449. X         if( cmd_list(cmd) ) {
  450. X            ad = cmd_list(cmd);
  451. X            flags = arg_flags(ad);
  452. X            if ( ARG_isGIVEN(ad) )
  453. X               BCLEAR( arg_flags(ad), ARGVALSEP | ARGVALGIVEN | ARGKEYWORD );
  454. X
  455. X            BSET( arg_flags(ad), ARGVALSEP );
  456. X
  457. X            ad_okay = HANDLE(ad, p, cmd_flags(cmd));
  458. X            if ( !ad_okay ) {
  459. X               arg_flags(ad) = flags;
  460. X               parse_error = pe_SYNTAX;
  461. X            }
  462. X
  463. X            continue;
  464. X         }
  465. X            /* positional argument */
  466. X         is_match = FALSE;
  467. X         for (args = argd; args  &&  !is_match ; args = cmd_defargs(args)) {
  468. X            for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
  469. X               if (arg_type(ad) == argDummy)  continue;
  470. X
  471. X               if ( ARG_isPOSITIONAL(ad)  &&
  472. X                    (!ARG_isGIVEN(ad) ||  ARG_isMULTIVAL(ad)) ) {
  473. X                  is_match = TRUE;
  474. X                  break;
  475. X               }/*if*/
  476. X            }
  477. X         }
  478. X
  479. X         if ( !is_match ) {
  480. X            usrerr("too any arguments");
  481. X            parse_error = pe_SYNTAX;
  482. X            continue;
  483. X         }
  484. X
  485. X         flags = arg_flags(ad);
  486. X         if ( ARG_isGIVEN(ad) )
  487. X            BCLEAR( arg_flags(ad), ARGVALSEP | ARGVALGIVEN | ARGKEYWORD );
  488. X
  489. X         if ( ARG_isMULTIVAL(ad) ) {
  490. X            cmd_list(cmd) = ad;
  491. X         }
  492. X
  493. X         if ( BTEST(cmd_flags(cmd), pa_FLAGS1ST) ) {
  494. X            BSET( cmd_state(cmd), ps_NOFLAGS );
  495. X         }
  496. X
  497. X         BSET( arg_flags(ad), ARGVALSEP );
  498. X
  499. X            /* try to convert */
  500. X         ad_okay = HANDLE(ad, p, cmd_flags(cmd));
  501. X         if ( !ad_okay ) {
  502. X            arg_flags(ad) = flags;
  503. X            parse_error = pe_SYNTAX;
  504. X         }
  505. X         else {
  506. X            BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
  507. X         }
  508. X      }/*else*/
  509. X   }/*while*/
  510. X
  511. X   return  parse_error;
  512. }
  513. X
  514. X
  515. /***************************************************************************
  516. ** ^FUNCTION: fmtarg - format command-argument syntax
  517. **
  518. ** ^SYNOPSIS:
  519. */
  520. #ifndef __ANSI_C__
  521. X   static int fmtarg( ad, buf, usgflags )
  522. /*
  523. ** ^PARAMETERS:
  524. */
  525. X   ARGDESC *ad;
  526. /*    -- pointer to the argument to format
  527. */
  528. X   char *buf;
  529. /*    -- character buffer to hold the formatted result
  530. */
  531. X   argMask_t usgflags;
  532. /*    -- set of bitmasks corresponding to the value of the user's USAGECNTL
  533. **       environment variable
  534. */
  535. #endif  /* !__ANSI_C__ */
  536. X
  537. /* ^DESCRIPTION:
  538. **    Fmtarg will determine the proper command-line syntax for the
  539. **    given argument and write the result to the given buffer.
  540. **
  541. ** ^REQUIREMENTS:
  542. **    buf must be large enough to hold the formatted result (100 characters
  543. **    should do the trick).
  544. **
  545. ** ^SIDE-EFECTS:
  546. **    buf is overwritten.
  547. **
  548. ** ^RETURN-VALUE:
  549. **    The number of printable characters in the argument-syntax-string
  550. **
  551. ** ^ALGORITHM:
  552. **    Print argument usage based on whether or not the argument is
  553. **    positional, hidden, multi-valued (list or vector), etc ....
  554. **    Optional arguments and values are enclosed in square braces.
  555. **
  556. **    Any syntax biases reflected in usgflags will be used.
  557. ***^^**********************************************************************/
  558. #ifdef __ANSI_C__
  559. X   static int fmtarg( const ARGDESC *ad, char *buf, argMask_t usgflags )
  560. #endif
  561. {
  562. X   /* buf must already be large enough */
  563. X   char *pos;
  564. X   argName_t   name, keyword;
  565. X
  566. X   (VOID) get_name( arg_sname(ad), name );
  567. X
  568. X   if (ARG_isPOSITIONAL(ad)) {
  569. X      sprintf( buf, "<%s>", name );
  570. X   }
  571. X   else {
  572. X      (VOID) get_keyword( arg_sname(ad), keyword );
  573. X
  574. X      if ( isupper(arg_cname(ad))  &&  toupper(*keyword) == arg_cname(ad) ) {
  575. X         *keyword = toupper(*keyword);
  576. X      }
  577. X
  578. X      if ( !(usgflags & usg_LONGOPTS) ) {
  579. X         sprintf( buf, "%c%c", OptPrefix, arg_cname(ad) );
  580. X      }
  581. X      else if ( !(usgflags & usg_OPTS) ) {
  582. X         sprintf( buf, "%c%s", KwdPrefix, keyword );
  583. X      }
  584. X      else  {  /* use both */
  585. X         if ( OptPrefix == KwdPrefix  &&  *keyword == arg_cname(ad) ) {
  586. X            if ( !*(keyword+1) )
  587. X               sprintf( buf, "%c%c", OptPrefix, arg_cname(ad) );
  588. X            else
  589. X               sprintf( buf, "%c%c[%s]", OptPrefix, arg_cname(ad), keyword+1 );
  590. X         }
  591. X         else {
  592. X            sprintf( buf, "%c%c|%c%s", OptPrefix, arg_cname(ad),
  593. X                                       KwdPrefix, keyword );
  594. X         }
  595. X      }
  596. X
  597. X      pos = buf + strlen(buf);
  598. X
  599. X      if ( ARG_isVALTAKEN(ad)  &&  !ARG_isBOOLEAN(ad)  &&  !ARG_isPSEUDOARG(ad) ) {
  600. X         if ( isUNIXISH )  *(pos++) = ' ';
  601. X         if ( ARG_isVALOPTIONAL(ad) )  *(pos++) = '[';
  602. X         if ( !isUNIXISH )  *(pos++) = *s_ARG_SEP;
  603. X         sprintf( pos, "<%s>", name );
  604. X         if ( ARG_isVALOPTIONAL(ad) )  strcat(pos, "]");
  605. X      }/*if*/
  606. X   }/*else*/
  607. X
  608. X   return  strlen(buf);
  609. }
  610. X
  611. X
  612. /***************************************************************************
  613. ** ^FUNCTION: ibm_usage - print a usage message
  614. **
  615. ** ^SYNOPSIS:
  616. */
  617. #ifndef __ANSI_C__
  618. X   VOID ibm_usage( argd, usage_flags )
  619. /*
  620. ** ^PARAMETERS:
  621. */
  622. X   ARGDESC *argd;
  623. /*    -- the command-descriptor array
  624. */
  625. X   argMask_t usage_flags;
  626. /*    -- flags set by $USAGECNTL
  627. */
  628. #endif  /* !__ANSI_C__ */
  629. X
  630. /* ^DESCRIPTION:
  631. **    Ibm_usage will print the Unix command-line usage of the given
  632. **    command on standard diagnostic output (stderr). The content of the
  633. **    usage message is controlled by the bitmasks in usage_flags which
  634. **    correspond to the settings in the user's USAGECNTL variable.
  635. **
  636. ** ^REQUIREMENTS:
  637. **    argd should be a non-null command-line argument-descriptor array
  638. **
  639. ** ^SIDE-EFECTS:
  640. **    Prints on stderr.
  641. **
  642. ** ^RETURN-VALUE:
  643. **    None.
  644. **
  645. ** ^ALGORITHM:
  646. **    - if no usage is desired then exit
  647. **    - if paging is requested print to the pager instead of stderr
  648. **    - print the command-line syntax
  649. **    - if the description is requested print it
  650. **    - if verbose mode is requested, print the description of each argument
  651. ***^^**********************************************************************/
  652. #ifdef __ANSI_C__
  653. X   void ibm_usage( const ARGDESC *argd, argMask_t usage_flags )
  654. #endif
  655. {
  656. X   register CONST ARGDESC  *ad, *args, *cmd;
  657. X   int  max_cols = 80, max_lines  = 24;
  658. X   int  ll, margin, options, longest, positionals;
  659. X   BOOL first = TRUE;
  660. X   FILE *fp;
  661. X
  662. X   if ( !argd )  return;
  663. X
  664. X      /* initialize command-structure */
  665. X   if ( !CMD_isINIT(argd) )  init_args( (ARGDESC *)argd );
  666. X   cmd = argd;
  667. X
  668. X      /* force verbose-mode if requested */
  669. X   if ( Usage_Requested )   BSET( usage_flags, usg_VERBOSE );
  670. X
  671. X   if ( BTEST(usage_flags, usg_NONE) )  return;
  672. X
  673. X   fp = ( BTEST(usage_flags, usg_PAGED) )
  674. X      ? pgopen( stderr, getenv("USAGE_PAGER") )
  675. X      : stderr;
  676. X
  677. X      /* get screen size */
  678. X   get_winsize( fileno(fp), &max_lines, &max_cols );
  679. X
  680. X   fprintf(fp, "Usage: %s", ProgName);
  681. X
  682. X   ll = strlen( ProgName ) + 7;
  683. X   margin = ll + 1;
  684. X   longest = 0;
  685. X
  686. X      /* print Synopsis */
  687. X   for ( positionals = 0 ; positionals < 2 ; positionals++ ) {
  688. X      for ( args = argd ; args ; args = cmd_defargs(args) ) {
  689. X         for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
  690. X            argName_t  buf;
  691. X            int pl;
  692. X
  693. X               /* don't display hidden arguments */
  694. X            if ( ARG_isHIDDEN(ad) )  continue;
  695. X            if ( !positionals  &&  ARG_isPOSITIONAL(ad) )  continue;
  696. X            if ( positionals  &&  !ARG_isPOSITIONAL(ad) )  continue;
  697. X
  698. X               /* figure out how wide this parameter is (for printing) */
  699. X            pl = fmtarg(ad, buf, usage_flags);
  700. X
  701. X            if ( pl > longest)  longest = pl;
  702. X
  703. X            if  ( ARG_isMULTIVAL(ad) ) {
  704. X               strcat( buf, "..." );
  705. X               pl += 3;
  706. X            }
  707. X            if ( !ARG_isREQUIRED(ad) ) {
  708. X               pl += 2;
  709. X            }
  710. X
  711. X            /* see if this will fit */
  712. X            if ( (ll + pl + 1) > (max_cols - first) ) {
  713. X                  /* no... start a new line */
  714. X               fprintf(fp, "\n%*s", margin, "");
  715. X               ll = margin;
  716. X            }
  717. X            else {
  718. X                  /* yes... just throw in a space */
  719. X               fputc(' ', fp);
  720. X               ++ll;
  721. X            }
  722. X            ll += pl;
  723. X
  724. X               /* show the argument */
  725. X            if ( !ARG_isREQUIRED(ad) )  fputc('[', fp);
  726. X            fprintf(fp, buf);
  727. X            if ( !ARG_isREQUIRED(ad) )  fputc(']', fp);
  728. X
  729. X            first = FALSE;  /* not first line anymore */
  730. X         }/*for each ad */
  731. X      }/* for each argd */
  732. X   }/* for each parm-type */
  733. X
  734. X   fputc('\n', fp);
  735. X
  736. X   if ( BTEST(usage_flags, usg_DESCRIPTION) ) {
  737. X      CONST char *description = cmd_description(cmd);
  738. X
  739. X      if ( description  &&  *description ) {
  740. X         fprintf( fp, "Description:\n" );
  741. X         indent_para(fp, max_cols, 8, "", 0, description);
  742. X         fputc( '\n', fp );
  743. X      }
  744. X   }/*if*/
  745. X
  746. X   if ( !BTEST(usage_flags, usg_VERBOSE) )  {
  747. X      if ( pgactive(fp) )  (VOID) pgclose( fp );
  748. X      return;
  749. X   }
  750. X
  751. X   options = 0;
  752. X
  753. X      /* print Argument descriptions */
  754. X   for ( positionals = 0 ; positionals < 2 ; positionals++ ) {
  755. X      for ( args = argd ; args ; args = cmd_defargs(args) ) {
  756. X         for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
  757. X            argName_t  buf;
  758. X
  759. X               /* don't display hidden arguments */
  760. X            if ( ARG_isHIDDEN(ad) )  continue;
  761. X            if ( !positionals  &&  ARG_isPOSITIONAL(ad) )  continue;
  762. X            if ( positionals  &&  !ARG_isPOSITIONAL(ad) )  continue;
  763. X
  764. X            if ( !options++ )   fprintf(fp, "Options/Arguments:\n");
  765. X            fmtarg(ad, buf, usage_flags);
  766. X            indent_para( fp, max_cols, 8, buf, longest+2, arg_description(ad) );
  767. X         }/*for each ad */
  768. X      }/* for each argd */
  769. X   }/* for each parm-type */
  770. X
  771. X   if ( pgactive(fp) )  (VOID) pgclose( fp );
  772. }
  773. X
  774. SHAR_EOF
  775. echo 'File parseargs/ibm_args.c is complete' &&
  776. chmod 0664 parseargs/ibm_args.c ||
  777. echo 'restore of parseargs/ibm_args.c failed'
  778. Wc_c="`wc -c < 'parseargs/ibm_args.c'`"
  779. test 23858 -eq "$Wc_c" ||
  780.     echo 'parseargs/ibm_args.c: original size 23858, current size' "$Wc_c"
  781. rm -f _shar_wnt_.tmp
  782. fi
  783. # ============= parseargs/parseargs.awk ==============
  784. if test -f 'parseargs/parseargs.awk' -a X"$1" != X"-c"; then
  785.     echo 'x - skipping parseargs/parseargs.awk (File already exists)'
  786.     rm -f _shar_wnt_.tmp
  787. else
  788. > _shar_wnt_.tmp
  789. echo 'x - extracting parseargs/parseargs.awk (Text)'
  790. sed 's/^X//' << 'SHAR_EOF' > 'parseargs/parseargs.awk' &&
  791. #!/usr/bin/awk -f
  792. X
  793. ##########################################################################
  794. ## ^FILE: parseargs.awk - parseargs for awk programs
  795. ##
  796. ## ^DESCRIPTION:
  797. ##    This file defines an awk function named parseargs to parse
  798. ##    command-line arguments for awk scripts. It also contains a
  799. ##    bare-bones template of what such an awk-script might contain.
  800. ##
  801. ## ^HISTORY:
  802. ##    02/21/91    Brad Appleton    <brad@ssd.csd.harris.com>    Created
  803. ###^^#####################################################################
  804. X
  805. X
  806. #########
  807. ## ^FUNCTION: parseargs - parse command-line argument vectors
  808. ##
  809. ## ^SYNOPSIS:
  810. ##    parseargs( argc, argv, argd, arr )
  811. ##
  812. ## ^PARAMETERS:
  813. ##    argc -- the number of elements in argv (usually ARGC-1).
  814. ##    argv -- the vector of command-line arguments (usually ARGV).
  815. ##    argd -- the argument-description string
  816. ##    arr  -- the associative array to assign command-line values from
  817. ##
  818. ## ^DESCRIPTION:
  819. ##    Parseargs will invoke parseargs(1) to parse the command-line given
  820. ##    in <argv> for the command defined by <argd>.  The resulting values
  821. ##    will be assigned to elements of the associative array given by <arr>.
  822. ##    Values are assigned using using the syntax: arr [ "argname" ] = value;
  823. ##    The exception to this is that if the <argname> is "ARGV" then the global
  824. ##    array ARGV is reset to the given array (using tab separated fields).
  825. ##
  826. ## ^REQUIREMENTS:
  827. ##    Any desired initial values for items in <arr> should be assigned BEFORE
  828. ##    calling this function (using the syntax: arr[ "argname" ] = initial-val).
  829. ##
  830. ##    The following global variables may be assigned before calling parseargs:
  831. ##
  832. ##       PROGNAME -- name of the current awk script (default= ARGV[0])
  833. ##       PARSEOPTS -- any extra options to pass toi parseargs() (default="-ul")
  834. ##       PARSEINPUT -- input file for parseargs(1) (default=unique-name)
  835. ##       PARSEOUTPUT -- output file for parseargs(1) (default=unique-name)
  836. ##
  837. ## ^SIDE-EFFECTS:
  838. ##    The files PARSEINPUT and PARSEOUTPUT are created and then deleted.
  839. ##
  840. ##    The return value from parseargs(1) will be stored in the global-variable
  841. ##    named PARSESTATUS.
  842. ##
  843. ##    The global variable PARSEARGS will contain the command-line used to
  844. ##    invoke parseargs(1).
  845. ##
  846. ##    ARGV and ARGC may be reset, all other values are (re)set in <arr>.
  847. ##
  848. ## ^RETURN-VALUE:
  849. ##    The exit code returned by parseargs(1).
  850. ##
  851. ## ^BUGS:
  852. ##    Due to the limited ability of awk, scripts using parseargs(1) cannot
  853. ##    use short-options (with a  dash '-') because awk will attempt to interpret
  854. ##    any such arguments as options to awk and remove them from ARGV (regardless
  855. ##    of whether or not they are valid awk-options). Keyword options (with a
  856. ##    plus sign '+') may still be used without this difficulty. Dash-options
  857. ##    may be successfully processed if they did not first appear on the command
  858. ##    to the awk-script, so the full syntax of unix-style options could be 
  859. ##    provided in an array other than ARGV.
  860. ##
  861. ## ^ALGORITHM:
  862. ##    - set defaults for PROGNAME, PARSEOPTS, PARSEINPUT, and PARSEOUTPUT.
  863. ##    - build the parseargs command (dont forget to quote arguments).
  864. ##    - redirect input and output of the parseargs command.
  865. ##    - run parseargs(1)
  866. ##    - assign the exit-code from parseargs(1) to PARSESTATUS
  867. ##    - remove PARSEINPUT
  868. ##    - if PARSESTATUS != 0
  869. ##      - save RS and FS and reset RS = "" and FS = "\n"
  870. ##      - for each record in PARSEOUTPUT
  871. ##        - $1 is the argname and $2 is the value
  872. ##        - if $1 is "ARGV" reset ARGV and ARGC ($2 is a tab separated array)
  873. ##        - else assign arr[ $1 ] = $2
  874. ##      end-for
  875. ##      - restore RS and FS to previous values
  876. ##      - remove PARSEOUTPUT
  877. ##      - return PARSESTATUS
  878. ###^^####
  879. X
  880. function parseargs(argc, argv, argd, arr) {
  881. X      ## set defaults -- use $$ to get a unique suffix string
  882. X   if ( ! PROGNAME )     PROGNAME = ARGV[0];
  883. X   if ( ! PARSEOPTS )    PARSEOPTS = "-u -l";
  884. X
  885. X   "echo  ${TMP:-/tmp}/parseargs.${$}_"  |  getline TMPFILE;
  886. X   if ( ! PARSEINPUT )   PARSEINPUT = TMPFILE "in";
  887. X   if ( ! PARSEOUTPUT )  PARSEOUTPUT = TMPFILE "out";
  888. X
  889. X      ## build the options and required arguments for parseargs(1)
  890. X   PARSEARGS = sprintf( "parseargs -s awk %s -- '%s'", PARSEOPTS, PROGNAME );
  891. X
  892. X      ## quote each elemnt in argv and append it to the parseargs-command
  893. X   for ( i = 1 ; i <= argc ; i++ ) {
  894. X      arg = argv[i];
  895. X      gsub( /'/, "'\\''", arg );
  896. X      PARSEARGS = PARSEARGS " '" arg "'";
  897. X   }
  898. X
  899. X      ## set up i/o redirection
  900. X   PARSEARGS = PARSEARGS  " <" PARSEINPUT  " >" PARSEOUTPUT;
  901. X   print  argd > PARSEINPUT;
  902. X
  903. X      ## invoke parseargs(1) and save the status
  904. X   PARSESTATUS = system( PARSEARGS );
  905. X   system( "/bin/rm -f " PARSEINPUT );  ## dont need input anymore
  906. X
  907. X      ## if successful status, read the result
  908. X   if ( PARSESTATUS == 0 ) {
  909. X      save_RS = RS; save_FS = FS;
  910. X      RS = ""; FS = "\n";
  911. X      while ( getline  < PARSEOUTPUT  > 0 ) {
  912. X         gsub( /\034/, "\n" );
  913. X         if ( $1 == "ARGV" ) {
  914. X            ARGC = 1 + split( $2, ARGV, "\t" );
  915. X            ARGV[0] = PROGNAME;
  916. X         }
  917. X         else  arr[ $1 ] = $2;
  918. X      }
  919. X      RS = save_RS; FS = save_FS;
  920. X   }
  921. X   system( "/bin/rm -f " PARSEOUTPUT );
  922. X
  923. X   return  PARSESTATUS;
  924. }
  925. X
  926. X
  927. BEGIN {
  928. X  PROGNAME = "test.awk";
  929. X  ARGD = sprintf( "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s",
  930. X    "'?', ARGHIDDEN, argUsage, NULL,    'Help : print usage and exit'" ,
  931. X    "'S', ARGVALOPT, argStr,   string,  'STRing : optional string arg'" ,
  932. X    "'g', ARGLIST,   argStr,   groups,  'newsGROUPS : groups to test'" ,
  933. X    "'r', ARGOPT,    argInt,   count,   'REPcount : group repeat count'" ,
  934. X    "'d', ARGOPT,    argStr,   dirname, 'DIRectory : working directory'" ,
  935. X    "'x', ARGOPT,    argBool,  xflag,   'Xflag : turn on X-mode'" ,
  936. X    "'y', ARGOPT,    argUBool, yflag,   'Yflag : turn off Y-mode'" ,
  937. X    "'s', ARGOPT,    argChar,  sepch,   'SEPchar : field separator'" ,
  938. X    "'f', ARGLIST,   argStr,   files,   'files : files to process'" ,
  939. X    "' ', ARGREQ,    argStr,   name,    'name : name to use'" ,
  940. X    "' ', ARGLIST,   argStr,   argv,    'argv : any remaining arguments'" ,
  941. X    "ENDOFARGS" );
  942. X
  943. X  Args[ "count" ] = 1;
  944. X  Args[ "dirname" ] = ".";
  945. X  Args[ "sepch" ] = ",";
  946. X  Args[ "yflag" ] = "TRUE";
  947. X
  948. X  rc = parseargs( ARGC-1, ARGV, ARGD, Args );
  949. X  if ( rc != 0 )  exit( rc );
  950. X
  951. X  ## print  the parsed arguments (use defaults if not defined)
  952. X  print "ARGUMENTS:";
  953. X  print "==========";
  954. X
  955. X  for ( i in Args )
  956. X    printf( "Args[\"%s\"] = \"%s\"\n", i, Args[i] );
  957. X
  958. X  argc = split( Args[ "argv" ], argv, "\t" );
  959. X  for ( i = 1 ; i <= argc ; i++ )
  960. X    printf( "argv[%d] = \"%s\"\n", i, argv[i] );
  961. X    
  962. }
  963. SHAR_EOF
  964. chmod 0664 parseargs/parseargs.awk ||
  965. echo 'restore of parseargs/parseargs.awk failed'
  966. Wc_c="`wc -c < 'parseargs/parseargs.awk'`"
  967. test 6648 -eq "$Wc_c" ||
  968.     echo 'parseargs/parseargs.awk: original size 6648, current size' "$Wc_c"
  969. rm -f _shar_wnt_.tmp
  970. fi
  971. # ============= parseargs/parseargs.c ==============
  972. if test -f 'parseargs/parseargs.c' -a X"$1" != X"-c"; then
  973.     echo 'x - skipping parseargs/parseargs.c (File already exists)'
  974.     rm -f _shar_wnt_.tmp
  975. else
  976. > _shar_wnt_.tmp
  977. echo 'x - extracting parseargs/parseargs.c (Text)'
  978. sed 's/^X//' << 'SHAR_EOF' > 'parseargs/parseargs.c' &&
  979. /*************************************************************************
  980. ** ^FILE: parseargs.c - command line interface to parseargs()
  981. **
  982. ** ^DESCRIPTION:
  983. **    This file implements the command-line interface to the parseargs
  984. **    library. Under Unix, the user may use parseargs(1) (this program)
  985. **    to parse command-line arguments for shell scripts.  At the present,
  986. **    time, VMS/DCL is not yet supported (nor are MS-DOS Batch-files).
  987. **
  988. **    Given a command name, a vector of string-valued arguments such as that
  989. **    passed to a shell script, and a specification string describing the
  990. **    possible arguments, parseargs matches actual arguments to possible
  991. **    arguments, converts values to the desired type, and diagnoses problems
  992. **    such as missing arguments, extra arguments, and argument values that
  993. **    are syntactically incorrect.  Other behavior such as prompting the
  994. **    user for missing arguments and ignoring as command-line syntax may be
  995. **    specified on the command-line through the use of various options, or
  996. **    through the use of the "PARSECNTL" environment variable.
  997. **
  998. **    Given the command name and the argument specification string,
  999. **       parsearg -U
  1000. **    prints a reasonably friendly version of the usage of the
  1001. **    calling program on standard diagnostic output. The "verbosity" of
  1002. **    the usage message may be controlled through the use of the
  1003. **    "USAGECNTL" environment variable.
  1004. **
  1005. **    Given the command name and the argument specification string,
  1006. **       parsearg -M
  1007. **    prints a template of the command-syntax on standard output that is
  1008. **    suitable for input to nroff or troff using the -man macro package.
  1009. **
  1010. ** ^SEE_ALSO:
  1011. **    argtype(3), parseargs(1), parseargs(3), parsecntl(3),
  1012. **    parseargs.pl, parseargs.awk
  1013. **    test.sh, test.csh, test.ksh, test.rc, test.awk, test.pl
  1014. **
  1015. ** ^BUGS:
  1016. **    It does not make sense to use any arguments of type argTBool since
  1017. **    parseargs currently has no way of knowing what the initial value of
  1018. **    the variable is. For this reason, argTBool is not recognized as a
  1019. **    valid argument type (even though it is used by parseargs(3)). By the
  1020. **    same token, since the user cannot create their own arguments types on
  1021. **    the fly from a shell-script, ARGNOVAL is not recognized as a valid
  1022. **    argument flag.
  1023. **
  1024. **    Commas will not be interpreted properly if any field in the argument
  1025. **    specification string contains double quotes that are nested inside of
  1026. **    double quotes, or single quotes that are nested inside of single quotes.
  1027. **
  1028. **    Inside the argument specification string, any repeated string of
  1029. **    commas that does not appear inside of double or single quotes will
  1030. **    be treated as a single comma.
  1031. **
  1032. **    Text descriptions for argument entries are automatically formatted in
  1033. **    usage messages. Any attempt by the user to include tabs and/or newlines
  1034. **    in the description will cause it to be formatted improperly.
  1035. **
  1036. **    Parseargs cannot properly preserve any newlines in shell variables if
  1037. **    the eval command is used to read its output (this is a shortcoming of
  1038. **    the eval command, not of parseargs). If the user is concerned about
  1039. **    this particular case, then the user should redirect the output from
  1040. **    parseargs to a temporary file and use the source command in csh or the
  1041. **    dot command (`.') in sh and ksh, to interpret the results; otherwise,
  1042. **    newlines will be translated into spaces, or characters following a
  1043. **    newline may be lost, in any variables that are set by parseargs.
  1044. **
  1045. **    Parseargs(1) is subject to the same caveats as parseargs(3).
  1046. **    Refer to the CAVEATS section of the parseargs(3) for more information.
  1047. **
  1048. ** ^HISTORY:
  1049. **    07/18/90     Brad Appleton     <brad@ssd.csd.harris.com>     Created
  1050. ***^^**********************************************************************/
  1051. X
  1052. #include <fcntl.h>
  1053. #include <stdio.h>
  1054. #include <useful.h>
  1055. #include "strfuncs.h"
  1056. X
  1057. #define PARSEARGS_PRIVATE   /* include private definitions */
  1058. #include "parseargs.h"
  1059. X
  1060. /*************************************************************************
  1061. ** ^SECTION: RETURN-CODES
  1062. **
  1063. ** Parseargs may return any of the following status-codes:
  1064. */
  1065. #define  e_SYSTEM   -1
  1066. /*    -- A system error occurred
  1067. */
  1068. #define  e_SUCCESS   0
  1069. /*    -- No errors, success!!
  1070. */
  1071. #define  e_USAGE     1
  1072. /*    -- No errors were encountered. A usage-message (or manual-page-template)
  1073. **       was explicitly requested (and printed) by the user.
  1074. */
  1075. #define  e_SYNTAX    2
  1076. /*    -- A syntax error was encountered on the command-line. The error may
  1077. **       be in the argument(s) intended for parseargs(1) or in the argument(s)
  1078. **       for the invoking shell-script.
  1079. */
  1080. #define  e_NOENV     3
  1081. /*    -- The user specified that the argument description was to be found in
  1082. **       an environment variable, however the environment variable in question
  1083. **       is unset or empty.
  1084. */
  1085. #define  e_ARGD      4
  1086. /*    -- An error was encountered in the string that describes the arguments
  1087. **       for the given command.
  1088. */
  1089. /**^^**********************************************************************/
  1090. X
  1091. X   /* default shell variable values for a boolean argument */
  1092. static CONST char  Default_StrTrue[]  = "TRUE";
  1093. static CONST char  Default_StrFalse[] = "";
  1094. X
  1095. X      /* define character sets */
  1096. static CONST char  WhiteSpace[] = " \t\n\v\r\f\"'";
  1097. static CONST char  ArgTableDelims[] = ",";
  1098. static CONST char  ArgFlagsDelims[] = "|+ \t\n\v\r\f";
  1099. X
  1100. X   /* macros to improve readability of string tests */
  1101. #define strEQ(s1,s2)     !strcmp(s1, s2)
  1102. #define strnEQ(s1,s2,n)  !strncmp(s1, s2, n)
  1103. X
  1104. #define  BUFFER_SIZE  1024       /* start off with 1k buffer & resize it */
  1105. #define  ESCAPED_COMMA  '\001'   /* character to replace commas with */
  1106. X
  1107. X      /* determine the beginning and end of a struct */
  1108. #define  c_BEGIN_STRUCT  '{'
  1109. #define  c_END_STRUCT    '}'
  1110. X
  1111. X      /* determine beginning-of-arg-table string */
  1112. #define  s_START_ARGS    "STARTOFARGS"
  1113. #define  isSTART_ARGS(s)  strnEQ(s, s_START_ARGS, 5)
  1114. X
  1115. X      /* determine end-of-arg-table string */
  1116. #define  s_END_ARGS    "ENDOFARGS"
  1117. #define  isEND_ARGS(s)  strnEQ(s, s_END_ARGS, 3)
  1118. X
  1119. X      /* define #of entries per arg-descriptor */
  1120. #define  NFIELDS  5
  1121. X
  1122. X
  1123. /**************************************************************************
  1124. ** ^SECTION: SHELLS
  1125. **    After the command line has been parsed, parseargs will print on stan-
  1126. **    dard output, a script to set the shell variables which correspond to
  1127. **    arguments that were present on the command-line.  This script may be
  1128. **    evaluated by redirecting it to a file and then executing the file,
  1129. **    or by directly evaluating the output from parseargs (under most UNIX
  1130. **    shells, this could be done using eval).  If any arguments on the com-
  1131. **    mand line contained any special characters that needed to be escaped
  1132. **    from the shell, these characters will remain intact (not be evaluated
  1133. **    by the shell) in the corresponding shell variable.
  1134. **
  1135. **    The -s shell option may be used to tell parseargs which shell syntax
  1136. **    to use. At present, parseargs only recognizes "sh", "csh", "ksh",
  1137. **    "tcsh", "bash", "rc", "awk", and "perl" as valid command interpreters.
  1138. **    Awk output is slightly different from that of the other shells in that
  1139. **    the actual variable setting are not printed but each line of an
  1140. **    associative array is printed (the first field is the array index, the
  1141. **    second is the value for that index).  If no shell is specified, then
  1142. **    the Bourne shell ("sh") will be assumed.
  1143. **
  1144. **    If the user wishes to use a value other than "TRUE" for a boolean
  1145. **    flag that is true, this may be done using the "-T string" option.
  1146. **    The same may also be done for a boolean flag that is false using the
  1147. **    "-F string" option.
  1148. **
  1149. **    Parseargs will only set the values of variables that correspond to
  1150. **    arguments that were given on the command line. If a particular argu-
  1151. **    ment was not supplied on the command line, then no assignment is made
  1152. **    for the corresponding shell variable and it will have the same value
  1153. **    that it had before parseargs was invoked. The only exception to this
  1154. **    is that if the -u option is specified, then the positional parameters
  1155. **    are unset before any shell variable assignments (which may reset the
  1156. **    positional parameters) are made.
  1157. ***^^*********************************************************************/
  1158. X
  1159. X      /* #defines for possible shell names and corresponding types */
  1160. typedef short  shell_t;
  1161. #define  BASH  ((shell_t) 0)
  1162. #define  TCSH  ((shell_t) 1)
  1163. #define  CSH   ((shell_t) 2)
  1164. #define  KSH   ((shell_t) 3)
  1165. #define  SH    ((shell_t) 4)
  1166. #define  RC    ((shell_t) 5)
  1167. #define  AWK   ((shell_t) 6)
  1168. #define  PERL  ((shell_t) 7)
  1169. X
  1170. #define  BOURNE_AGAIN_SHELL  "bash"
  1171. #define  BOURNE_SHELL        "sh"
  1172. #define  KORN_SHELL          "ksh"
  1173. #define  C_SHELL             "csh"
  1174. #define  RC_SHELL            "rc"
  1175. #define  TC_SHELL            "tcsh"
  1176. #define  AWK_LANG            "awk"
  1177. #define  PERL_LANG           "perl"
  1178. X
  1179. X   /* structure for shell-specific info */
  1180. typedef struct {
  1181. X   char  *varname;   /* name of variable containing the positional parameters */
  1182. X   char  *setcmd;    /* formatted string (%s is replaced with variable name) */
  1183. X   char  *prefix;    /* beginning for variable setting */
  1184. X   char  *suffix;    /* ending for variable setting */
  1185. X   char  *escape;    /* format to escape chars (%c is the char to escape) */
  1186. X   char  *metachars; /* special characters that need to be escaped */
  1187. } shell_info;
  1188. X
  1189. X   /* array of shell info - indexed by the #define for the shell type */
  1190. static CONST shell_info  Shell[] = {
  1191. X
  1192. X   /* BASH : Positional parms in -- ; Assignment Syntax: name="value"; */
  1193. X   { "--", "%s=",   "'",   "';\n",   "'\\%c'",   "'" },
  1194. X
  1195. X   /* TCSH : Positional parms in argv ; Assignment Syntax: set name="value"; */
  1196. X   { "argv", "set %s=", "'",   "';\n",  "'\\%c'",   "'" },
  1197. X
  1198. X   /* CSH : Positional parms in argv ; Assignment Syntax: set name="value"; */
  1199. X   { "argv", "set %s=", "'",   "';\n",  "'\\%c'",   "'" },
  1200. X
  1201. X   /* KSH : Positional parms in -- ; Assignment Syntax: name="value"; */
  1202. X   { "--", "%s=",       "'",   "';\n",  "'\\%c'",   "'" },
  1203. X
  1204. X   /* SH : Positional parms in -- ; Assignment Syntax: name="value"; */
  1205. X   { "--", "%s=",       "'",   "';\n",  "'\\%c'",   "'" },
  1206. X
  1207. X   /* RC : Positional parms in -- ; Assignment Syntax: name="value"; */
  1208. X   { "*", "%s=",       "'",   "';\n",  "''",   "'" },
  1209. X
  1210. X   /* AWK : Positional parms in ARGV; Assignment Syntax: name\nvalue\n\n; */
  1211. X   { "ARGV", "%s\n",    "",   "\n\n",  "'\034'",   "\n" },
  1212. X
  1213. X   /* PERL : Positional parms in ARGV; Assignment Syntax: $name=value\n; */
  1214. X   { "ARGV", "$%s = ",  "",   ";\n",  "'.\"%c\".'",   "'" }
  1215. };
  1216. /*************************************************************************/
  1217. X
  1218. X   /* define all current arg-vector types */
  1219. typedef ARGVEC_T(char *)  strvec_t;
  1220. typedef ARGVEC_T(char)    charvec_t;
  1221. typedef ARGVEC_T(int)     intvec_t;
  1222. typedef ARGVEC_T(short)   shortvec_t;
  1223. typedef ARGVEC_T(long)    longvec_t;
  1224. typedef ARGVEC_T(float)   floatvec_t;
  1225. typedef ARGVEC_T(double)  doublevec_t;
  1226. typedef ARGVEC_T(VOID)    genericvec_t;  /* generic vector */
  1227. X
  1228. X      /* union to hold all possibles values of an argument */
  1229. typedef union {
  1230. X   BOOL    Bool_val;
  1231. X   short   Short_val;
  1232. X   int     Int_val;
  1233. X   long    Long_val;
  1234. X   float   Float_val;
  1235. X   double  Double_val;
  1236. X   char    Char_val;
  1237. X   char   *Str_val;
  1238. X   strvec_t      Str_vec;
  1239. X   charvec_t     Char_vec;
  1240. X   intvec_t      Int_vec;
  1241. X   shortvec_t    Short_vec;
  1242. X   longvec_t     Long_vec;
  1243. X   floatvec_t    Float_vec;
  1244. X   doublevec_t   Double_vec;
  1245. X   genericvec_t  Vector;
  1246. } storage_t;
  1247. X
  1248. X   /* structure to hold a command-line argument name, value, and fmt-string */
  1249. typedef struct {
  1250. X   CONST char *name;   /* name of shell variable to use */
  1251. X   storage_t   value;  /* storage for value of argument */
  1252. } cmdarg_t;
  1253. #define CMDARGNULL (cmdarg_t *)NULL
  1254. X
  1255. EXTERN  int   eprintf   ARGS((const char *, ...));
  1256. EXTERN  VOID  syserr    ARGS((const char *, ...));
  1257. EXTERN  VOID  usrerr    ARGS((const char *, ...));
  1258. EXTERN  char *getenv    ARGS((const char *));
  1259. EXTERN  VOID  manpage   ARGS((const ARGDESC *));
  1260. EXTERN  VOID  perror    ARGS((const char *));
  1261. X
  1262. extern  int  errno;  /* system wide error level */
  1263. X
  1264. /*************************************************************************/
  1265. X   /*
  1266. X   ** variables that are set via command-line arguments
  1267. X   */
  1268. static  char   *Cmd_Name;  /* name of this program */
  1269. X
  1270. static  ARGDESC   *UsrArgd = ARGDESCNULL;       /* users arg-table */
  1271. static  cmdarg_t  *UsrVals = CMDARGNULL;        /* variable names & values */
  1272. static  int        UsrArgc = 0;                 /* # of arg-table entries */
  1273. static  shell_t    UsrSh;                       /* shell indicator */
  1274. static  BOOL       UseStdin = TRUE;             /* read argd from stdin */
  1275. X
  1276. static  char   *ShellName  = CHARNULL;  /* name of user's shell */
  1277. static  char   *UsrName    = CHARNULL;  /* name of users program */
  1278. static  char   *FieldSep   = " ";       /* field-separators for arrays */
  1279. static  strvec_t UsrArgv   = ARGVEC_EMPTY(char *);   /* users args */
  1280. static  char   *ArgdString = CHARNULL;  /* argd string (with WhiteSpace) */
  1281. static  char   *ArgdEnv    = CHARNULL;  /* environment variable for argd */
  1282. static  char   *ArgdFname  = CHARNULL;  /* argd input file */
  1283. static  BOOL    Unset      = FALSE;     /* ?unset positional parms? */
  1284. static  char   *StrTrue    = CHARNULL;  /* string for TRUE values */
  1285. static  char   *StrFalse   = CHARNULL;  /* string for FALSE values */
  1286. static  char    OptsOnly   = FALSE;     /* parse options only? */
  1287. static  char    KwdsOnly   = FALSE;     /* parse keywords only? */
  1288. static  BOOL    ModArr     = FALSE;     /* modify array behavior */
  1289. static  BOOL    PrUsage    = FALSE;     /* ?just print usage? */
  1290. static  BOOL    PrManual   = FALSE;     /* ?just print manual page(s)? */
  1291. static  BOOL    Prompt     = FALSE;     /* ?prompt for missing args? */
  1292. static  BOOL    Ignore     = FALSE;     /* ?ignore bad syntax and continue? */
  1293. X
  1294. /*************************************************************************/
  1295. X   /* now we are ready to define the command-line */
  1296. static
  1297. CMD_OBJECT
  1298. X   Args
  1299. X
  1300. CMD_NAME
  1301. X   "parseargs  --  parse command-line arguments in shell scripts"
  1302. X
  1303. CMD_DESCRIPTION
  1304. X   "Given a description of the command-line and the command-line arguments, \
  1305. parseargs will parse all command-line arguments, convert them to their \
  1306. desired type, and print on standard output, a script of all the resulting \
  1307. shell assignment statements."
  1308. X
  1309. CMD_ARGUMENTS
  1310. X   'U', ARGOPT,  argBool,  __ &PrUsage,
  1311. X   "usage : just print program usage, dont parse command-line",
  1312. X
  1313. X   'M', ARGOPT,  argBool,  __ &PrManual,
  1314. X   "man1 : just print man1 template, dont parse command-line",
  1315. X
  1316. X   'T', ARGOPT,  argStr,  __ &StrTrue,
  1317. X   "TRUEstr : string to use for TRUE Booleans   (default=\"TRUE\")",
  1318. X
  1319. X   'F', ARGOPT,  argStr,  __ &StrFalse,
  1320. X   "FALSEstr : string to use for FALSE Booleans  (default=\"\")",
  1321. X
  1322. X   'A', ARGOPT,  argBool,  __ &ModArr,
  1323. X   "array : modify the behavior of arrays",
  1324. X
  1325. X   'S', ARGOPT,  argStr,  __ &FieldSep,
  1326. X   "SEParator : field-separator-string used to delimit array elements \
  1327. (default=\" \")",
  1328. X
  1329. X   'a', ARGOPT,  argStr,  __ &ArgdString,
  1330. X   "ARGSpec : argument specification string",
  1331. X
  1332. X   'e', ARGOPT,  argStr,  __ &ArgdEnv,
  1333. X   "ENVarname : environment variable containing arg-spec",
  1334. X
  1335. X   'f', ARGOPT,  argStr,  __ &ArgdFname,
  1336. X   "FILEname : read the arg-spec from <filename> (default=stdin)",
  1337. X
  1338. X   'l', ARGOPT,  argBool,  __ &KwdsOnly,
  1339. X   "Long-OPTionS : long-options only - do not parse options",
  1340. X
  1341. X   'o', ARGOPT,  argBool,  __ &OptsOnly,
  1342. X   "OPTionS : options only - do not parse long-options",
  1343. X
  1344. X   's', ARGOPT,  argStr,  __ &ShellName,
  1345. X   "SHell : use <shell> command syntax        (default=\"sh\")",
  1346. X
  1347. X   'u', ARGOPT,  argBool,  __ &Unset,
  1348. X   "unset : unset positional parameters before parsing",
  1349. X
  1350. X   'p', ARGOPT,  argBool,  __ &Prompt,
  1351. X   "prompt : prompt the user for missing required arguments",
  1352. X
  1353. X   'i', ARGOPT,  argBool,  __ &Ignore,
  1354. X   "ignore : ignore bad command-line syntax and continue processing \
  1355. (instead of aborting)",
  1356. X
  1357. X   '-', ARGOPT,  argDummy, __ NULL,
  1358. X   "+ : end of options - all remaining arguments are interpreted as \
  1359. positional parameters (even if one begins with '-' or '+')",
  1360. X
  1361. X   ' ', ARGREQ,  argStr, __ &UsrName,
  1362. X   "name : name of calling program",
  1363. X
  1364. X   ' ', ARGOPT|ARGVEC,  argStr,  __ &UsrArgv,
  1365. X   "arguments : arguments to calling program",
  1366. X
  1367. X   END_ARGUMENTS
  1368. X
  1369. CMD_END
  1370. X
  1371. X
  1372. /***************************************************************************
  1373. ** ^FUNCTION: cleanup - deallocate all global storage
  1374. **
  1375. ** ^SYNOPSIS:
  1376. */
  1377. #ifndef __ANSI_C__
  1378. X   static  VOID cleanup()
  1379. #endif  /* !__ANSI_C__ */
  1380. /*
  1381. ** ^PARAMETERS:
  1382. **    None.
  1383. **
  1384. ** ^DESCRIPTION:
  1385. **    Cleanup is used to deallocate any global storage. It is called
  1386. **    before exiting.
  1387. **
  1388. ** ^REQUIREMENTS:
  1389. **    None.
  1390. **
  1391. ** ^SIDE-EFECTS:
  1392. **    Storage associated with all dynamically allocated global-variables
  1393. **    is released and set to NULL.
  1394. **
  1395. ** ^RETURN-VALUE:
  1396. **    None.
  1397. **
  1398. ** ^ALGORITHM:
  1399. **    Trivial.
  1400. ***^^**********************************************************************/
  1401. #ifdef __ANSI_C__
  1402. X   static void cleanup( void )
  1403. #endif
  1404. {
  1405. X   register ARGDESC *ad;
  1406. X   register storage_t val;
  1407. X   
  1408. X   /* free up any vectors from the command-line */
  1409. X   for ( ad = ARG_FIRST(UsrArgd) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
  1410. X      if ( ! BTEST(arg_flags(ad), ARGVEC) )  continue;
  1411. X
  1412. X      val = *((storage_t *) arg_valp(ad));
  1413. X
  1414. X      if      ( arg_type(ad) == argStr )     vecFree( val.Str_vec, char * );
  1415. X      else if ( arg_type(ad) == argChar )    vecFree( val.Char_vec, char );
  1416. X      else if ( arg_type(ad) == argInt )     vecFree( val.Int_vec, int );
  1417. X      else if ( arg_type(ad) == argShort )   vecFree( val.Short_vec, short );
  1418. X      else if ( arg_type(ad) == argLong )    vecFree( val.Long_vec, long );
  1419. X      else if ( arg_type(ad) == argFloat )   vecFree( val.Float_vec, float );
  1420. X      else if ( arg_type(ad) == argDouble )  vecFree( val.Double_vec, double );
  1421. X   }
  1422. X
  1423. X   /* free up tables */
  1424. X   vecFree( UsrArgv, char * );
  1425. X   if ( UsrArgd ) {
  1426. X      free( UsrArgd );
  1427. X      UsrArgd = ARGDESCNULL;
  1428. X   }
  1429. X   if ( UsrVals ) {
  1430. X      free( UsrVals );
  1431. X      UsrVals = CMDARGNULL;
  1432. X   }
  1433. X   if ( ArgdFname   &&   !ArgdEnv ) {
  1434. X      free( ArgdString );
  1435. X      ArgdString = CHARNULL;
  1436. X   }
  1437. }
  1438. X
  1439. X
  1440. /***************************************************************************
  1441. ** ^FUNCTION: ckalloc - allocate space, check for success
  1442. **
  1443. ** ^SYNOPSIS:
  1444. */
  1445. #ifndef __ANSI_C__
  1446. X   static ARBPTR ckalloc( size )
  1447. /*
  1448. ** ^PARAMETERS:
  1449. */
  1450. X   size_t  size;
  1451. /*    -- the number of bytes to allocate
  1452. */
  1453. #endif  /* !__ANSI_C__ */
  1454. X
  1455. /* ^DESCRIPTION:
  1456. **    Ckalloc will use malloc to attempt to fill the given request 
  1457. **    for memory. If The request cannot be met than a message is
  1458. **    printed and execution is terminated.
  1459. **
  1460. ** ^REQUIREMENTS:
  1461. **    size should be > 0
  1462. **
  1463. ** ^SIDE-EFECTS:
  1464. **    Memory is allocated that should later be deallocated using free().
  1465. **
  1466. ** ^RETURN-VALUE:
  1467. **    The address of the allocated region.
  1468. **
  1469. ** ^ALGORITHM:
  1470. **    - Allocate space, check for success
  1471. ***^^**********************************************************************/
  1472. #ifdef __ANSI_C__
  1473. X   static ARBPTR ckalloc( size_t size )
  1474. #endif
  1475. {
  1476. X   ARBPTR  ptr;
  1477. X
  1478. X   ptr = malloc( size );
  1479. X   if ( !ptr ) {
  1480. X      eprintf( "%s: Fatal Error: out of memory!!", Cmd_Name );
  1481. X      cleanup();
  1482. X      if ( errno )  perror( Cmd_Name );
  1483. X      exit( e_SYSTEM );
  1484. X   }
  1485. X
  1486. X   return  ptr;
  1487. }
  1488. X
  1489. X
  1490. /***************************************************************************
  1491. ** ^FUNCTION: ckrealloc - reallocate space, check for success
  1492. **
  1493. ** ^SYNOPSIS:
  1494. */
  1495. #ifndef __ANSI_C__
  1496. X   static ARBPTR ckrealloc( ptr, size )
  1497. /*
  1498. ** ^PARAMETERS:
  1499. */
  1500. X   ARBPTR  ptr;
  1501. /*    -- address of the region to be expanded/shrunk
  1502. */
  1503. X   size_t  size;
  1504. /*    -- the number of bytes to allocate
  1505. */
  1506. #endif  /* !__ANSI_C__ */
  1507. X
  1508. /* ^DESCRIPTION:
  1509. **    Ckrealloc will use realloc to attempt to fill the given request 
  1510. **    for memory. If The request cannot be met than a message is
  1511. **    printed and execution is terminated.
  1512. **
  1513. ** ^REQUIREMENTS:
  1514. **    size should be > 0
  1515. **
  1516. ** ^SIDE-EFECTS:
  1517. **    Memory is allocated that should later be deallocated using free().
  1518. **
  1519. ** ^RETURN-VALUE:
  1520. **    The address of the (re)allocated region (which may have been moved).
  1521. **
  1522. ** ^ALGORITHM:
  1523. **    - Reallocate space, check for success
  1524. ***^^**********************************************************************/
  1525. #ifdef __ANSI_C__
  1526. X   static ARBPTR ckrealloc( ARBPTR ptr, size_t size )
  1527. #endif
  1528. {
  1529. X   ptr = realloc( ptr, (unsigned int)size );
  1530. X   if ( !ptr ) {
  1531. X      eprintf( "%s: Fatal Error: out of memory!!", Cmd_Name );
  1532. X      cleanup();
  1533. X      if ( errno )  perror( Cmd_Name );
  1534. X      exit( e_SYSTEM );
  1535. X   }
  1536. X
  1537. X   return  ptr;
  1538. }
  1539. X
  1540. X
  1541. /***************************************************************************
  1542. ** ^FUNCTION: escape_char - (re)map a character
  1543. **
  1544. ** ^SYNOPSIS:
  1545. */
  1546. #ifndef __ANSI_C__
  1547. X   static VOID escape_char( str, ch, esc )
  1548. /*
  1549. ** ^PARAMETERS:
  1550. */
  1551. X   char *str;
  1552. /*    -- the string to be translated
  1553. */
  1554. X   int ch;
  1555. /*    --  the character to be replaced/translated
  1556. */
  1557. X   int esc;
  1558. /*    -- the replacement character to use
  1559. */
  1560. #endif  /* !__ANSI_C__ */
  1561. X
  1562. /* ^DESCRIPTION:
  1563. **    Escape_char will escape all occurences of a character by replacing
  1564. **    it with <esc> if the character appears in double or single quotes.
  1565. **
  1566. ** ^REQUIREMENTS:
  1567. **    Both <ch> and <esc> should be non-zero.
  1568. **    <str> should be non-null and non-empty.
  1569. **
  1570. ** ^SIDE-EFECTS:
  1571. **    Each occurrence in <str> of <ch> within single or double quotes is
  1572. **    replaced with <esc>.
  1573. **
  1574. ** ^RETURN-VALUE:
  1575. **    None.
  1576. **
  1577. ** ^ALGORITHM:
  1578. **    Trivial.
  1579. ***^^**********************************************************************/
  1580. #ifdef __ANSI_C__
  1581. X   static void escape_char( char *str, int ch, int esc )
  1582. #endif
  1583. {
  1584. X   int   squoted = 0, dquoted = 0;
  1585. X
  1586. X   for ( ; *str ; str++ ) {
  1587. X      if ( *str == '\''  &&  !dquoted )
  1588. X         squoted = ~squoted;
  1589. X      else if ( *str == '"'  &&  !squoted )
  1590. X         dquoted = ~dquoted;
  1591. X      else if ( (squoted || dquoted)  &&  *str == ch )
  1592. X         *str = esc;
  1593. X   }
  1594. }
  1595. X
  1596. X
  1597. /***************************************************************************
  1598. ** ^FUNCTION: restore_char - restore any chars escaped by escape_char()
  1599. **
  1600. ** ^SYNOPSIS:
  1601. */
  1602. #ifndef __ANSI_C__
  1603. X   static VOID restore_char( str, ch, esc )
  1604. /*
  1605. ** ^PARAMETERS:
  1606. */
  1607. X   char *str;
  1608. /*    -- the string to be translated
  1609. */
  1610. X   int ch;
  1611. /*    --  the character to be restored
  1612. */
  1613. X   int esc;
  1614. /*    -- the replacement character to use to escape the above character.
  1615. */
  1616. #endif  /* !__ANSI_C__ */
  1617. X
  1618. /* ^DESCRIPTION:
  1619. **    Restore_char will attempt to undo the results of a previous call
  1620. **    to escape_char by replacing each occurence of <esc> in <str> with <ch>.
  1621. **
  1622. ** ^REQUIREMENTS:
  1623. **    <str> should be the victim of a previous escape_char(str, ch, esc) call.
  1624. **    Furthermore, <esc> should be a character that occurs only as a result
  1625. **    of this call (it should be VERY uncommon).
  1626. **
  1627. **    It should be noted that escape_char() only replaces characters in quotes
  1628. **    whereas this routine replaces all occurrences.
  1629. **
  1630. ** ^SIDE-EFECTS:
  1631. **    Each occurrence of <esc> in <str> is replaced with <ch>.
  1632. **
  1633. ** ^RETURN-VALUE:
  1634. **    None.
  1635. **
  1636. ** ^ALGORITHM:
  1637. **    Trivial.
  1638. ***^^**********************************************************************/
  1639. #ifdef __ANSI_C__
  1640. X   void restore_char( char *str, int ch, int esc )
  1641. #endif
  1642. {
  1643. X   for ( ; *str ; str++ )
  1644. X      if ( *str == esc )   *str = ch;
  1645. }
  1646. X
  1647. X
  1648. /***************************************************************************
  1649. ** ^FUNCTION: get_arg_type - return function corresponding to given string
  1650. **
  1651. ** ^SYNOPSIS:
  1652. */
  1653. #ifndef __ANSI_C__
  1654. X   static argTypePtr_t  get_arg_type( type_str )
  1655. /*
  1656. ** ^PARAMETERS:
  1657. */
  1658. X   char *type_str;
  1659. /*    -- string corresponding to the name of an existing argXxxx type function.
  1660. */
  1661. #endif  /* !__ANSI_C__ */
  1662. X
  1663. /* ^DESCRIPTION:
  1664. **    Get_arg_type will attempt to match <type_name> against the name of all
  1665. **    known argXxxx argumnent translation routines and routine the address of
  1666. **    the corresponding function. If no match is found, then an error message
  1667. **    is printed and execution is terminated.
  1668. **
  1669. ** ^REQUIREMENTS:
  1670. **    type_str should be non-NULL and non-empty
  1671. **
  1672. ** ^SIDE-EFECTS:
  1673. **    None.
  1674. **
  1675. ** ^RETURN-VALUE:
  1676. **    Address of the corresponding function
  1677. **
  1678. ** ^ALGORITHM:
  1679. **    Trivial.
  1680. ***^^**********************************************************************/
  1681. #ifdef __ANSI_C__
  1682. X   static  argTypePtr_t  get_arg_type( const char *type_str )
  1683. #endif
  1684. {
  1685. X   register  CONST char *str = type_str;
  1686. X
  1687. X   /* translate all listXxx into argXxx */
  1688. X   if ( strnEQ( str, "list", 4 ) )
  1689. X      str += 4;
  1690. X
  1691. X   if ( strnEQ( str, "arg", 3 ) )
  1692. X      str += 3;
  1693. X
  1694. X   if      ( strEQ( str, "Usage" ) )
  1695. X      return   argUsage;
  1696. X   else if ( strEQ( str, "Dummy" ) )
  1697. X      return   argDummy;
  1698. X   else if ( strEQ( str, "Bool" ) )
  1699. X      return   argBool;
  1700. X   else if ( strEQ( str, "SBool" ) )
  1701. X      return   argSBool;
  1702. X   else if ( strEQ( str, "UBool" ) )
  1703. X      return   argUBool;
  1704. X   else if ( strEQ( str, "Int" ) )
  1705. X      return   argInt;
  1706. X   else if ( strEQ( str, "Short" ) )
  1707. X      return   argShort;
  1708. X   else if ( strEQ( str, "Long" ) )
  1709. X      return   argLong;
  1710. X   else if ( strEQ( str, "Float" ) )
  1711. X      return   argFloat;
  1712. X   else if ( strEQ( str, "Double" ) )
  1713. X      return   argDouble;
  1714. X   else if ( strEQ( str, "Char" ) )
  1715. X      return   argChar;
  1716. X   else if ( strEQ( str, "Str" ) )
  1717. X      return   argStr;
  1718. X   else {
  1719. X      eprintf( "%s: Fatal Error: invalid argument type '%s'\n",
  1720. X               Cmd_Name, type_str );
  1721. X      cleanup();
  1722. X      exit( e_ARGD );
  1723. X   }
  1724. }
  1725. X
  1726. X
  1727. /***************************************************************************
  1728. ** ^FUNCTION: get_arg_flag - return BITMASK corresponding to string
  1729. **
  1730. ** ^SYNOPSIS:
  1731. */
  1732. #ifndef __ANSI_C__
  1733. X   static argMask_t get_arg_flag( flag_str )
  1734. /*
  1735. ** ^PARAMETERS:
  1736. */
  1737. X   char flag_str[];
  1738. /*    -- name of an ARGXXXXX argument-flag
  1739. */
  1740. #endif  /* !__ANSI_C__ */
  1741. X
  1742. /* ^DESCRIPTION:
  1743. **    Get_arg_flag will attempt to match the given string against the name of
  1744. **    all valid argument-flags and return its associated bitmask.  If no match
  1745. **    is found, then an error message is printed and execution is terminated.
  1746. **
  1747. ** ^REQUIREMENTS:
  1748. **    flag_str should be non-NULL and non-empty
  1749. **
  1750. ** ^SIDE-EFECTS:
  1751. **    None.
  1752. **
  1753. ** ^RETURN-VALUE:
  1754. **    The bitmask corresponding to named ARGXXXX flag.
  1755. **
  1756. ** ^ALGORITHM:
  1757. **    Trivial.
  1758. ***^^**********************************************************************/
  1759. #ifdef __ANSI_C__
  1760. X   static argMask_t get_arg_flag( const char flag_str[] )
  1761. #endif
  1762. {
  1763. X   if ( strnEQ( flag_str, "ARG", 3 ) )   {
  1764. X      if      ( strEQ( flag_str+3, "OPT" ) )     return   ARGOPT;
  1765. X      else if ( strEQ( flag_str+3, "REQ" ) )     return   ARGREQ;
  1766. X      else if ( strEQ( flag_str+3, "POS" ) )     return   ARGPOS;
  1767. X      else if ( strEQ( flag_str+3, "VALREQ" ) )  return   ARGVALREQ;
  1768. X      else if ( strEQ( flag_str+3, "VALOPT" ) )  return   ARGVALOPT;
  1769. X      else if ( strEQ( flag_str+3, "HIDDEN" ) )  return   ARGHIDDEN;
  1770. X      else if ( strEQ( flag_str+3, "LIST" ) )    return   ARGVEC;
  1771. X      else if ( strEQ( flag_str+3, "VEC" ) )     return   ARGVEC;
  1772. X      else {
  1773. X         eprintf( "%s: Fatal Error: invalid argument flag '%s'\n",
  1774. X                  Cmd_Name, flag_str );
  1775. X         cleanup();
  1776. X         exit( e_ARGD );
  1777. X      }
  1778. X   }
  1779. X   else {
  1780. X      eprintf( "%s: Fatal Error: invalid argument flag '%s'\n",
  1781. X               Cmd_Name, flag_str );
  1782. X      cleanup();
  1783. X      exit( e_ARGD );
  1784. X   }
  1785. }
  1786. X
  1787. /***************************************************************************
  1788. ** ^FUNCTION: get_argtable_string - read in the argument-table
  1789. **
  1790. ** ^SYNOPSIS:
  1791. */
  1792. #ifndef __ANSI_C__
  1793. X   static char *get_argtable_string()
  1794. #endif
  1795. /*
  1796. ** ^PARAMETERS:
  1797. **    None.
  1798. **
  1799. ** ^DESCRIPTION:
  1800. **    Get_argtable_string will read (from standard input if UseStdin is set)
  1801. **    the entire argument descriptor table into a string and return its address.
  1802. **
  1803. **    Execution is terminated if there is an error reading STDIN or if the
  1804. **    string is too big to fit into memory.
  1805. **
  1806. ** ^REQUIREMENTS:
  1807. **    Standard input should be open for reading and be non-interactive.
  1808. **
  1809. ** ^SIDE-EFECTS:
  1810. **    Memory is allocated that should later be deallocated using free.
  1811. **
  1812. ** ^RETURN-VALUE:
  1813. **    NULL if STDIN is connected to a terminal (after all,
  1814. **    this program is for Non-interactive input)
  1815. **
  1816. ** ^ALGORITHM:
  1817. **    - start off with a 1k buffer
  1818. **    - open the file (if necessary)
  1819. **    - while (not eof)
  1820. **      - read 1k bytes (or whatever is left).
  1821. **      - increase the buffer size by 1k bytes.
  1822. **      end-while
  1823. **    - shrink the buffer down to the number of bytes used.
  1824. **    - close the file (if we had to open it).
  1825. **    - return the buffer address
  1826. ***^^**********************************************************************/
  1827. #ifdef __ANSI_C__
  1828. X   static char *get_argtable_string( void )
  1829. #endif
  1830. {
  1831. X   int  isatty  ARGS((int));
  1832. X   int  fread   ARGS((char *, int, int, FILE *));
  1833. X   FILE *fp;
  1834. X   char *buf;
  1835. X   register int  nchars = 0;   /* # bytes read */
  1836. X   register int  bufsiz = 0;   /* actual buffer-size needed */
  1837. X
  1838. X   /* open file if necessary */
  1839. X   if ( UseStdin )  {
  1840. X      if ( isatty(STDIN) ) {
  1841. X            /* we wont read the arg-table from a terminal */
  1842. X         eprintf( "\
  1843. %s: Fatal Error:\n\
  1844. \tcannot read arg-descriptor table from stdin\n\
  1845. \tif stdin is connected to a terminal\n!",
  1846. X                  Cmd_Name );
  1847. X         cleanup();
  1848. X         exit( e_ARGD );
  1849. X      }
  1850. X      errno = 0;   /* reset errno if isatty() was not a terminal */
  1851. X      fp = stdin;
  1852. X   }
  1853. X   else {
  1854. X      if ( (fp = fopen( ArgdFname, "r")) == FILENULL )   {
  1855. X         eprintf( "%s: Fatal error: Unable to open %s for reading\n",
  1856. SHAR_EOF
  1857. true || echo 'restore of parseargs/parseargs.c failed'
  1858. fi
  1859. echo 'End of  part 5'
  1860. echo 'File parseargs/parseargs.c is continued in part 6'
  1861. echo 6 > _shar_seq_.tmp
  1862. exit 0
  1863. exit 0 # Just in case...
  1864. -- 
  1865. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1866. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1867. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1868. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1869.