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

  1. Newsgroups: comp.sources.misc
  2. From: brad@hcx1.ssd.csd.harris.com (Brad Appleton)
  3. Subject:  v29i121:  parseargs - functions to parse command line arguments, Part06/10
  4. Message-ID: <1992May17.182429.28867@sparky.imd.sterling.com>
  5. X-Md4-Signature: 3d12912bfa1164d531d8ad836e6725ce
  6. Date: Sun, 17 May 1992 18:24:29 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 121
  11. Archive-name: parseargs/part06
  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 6 (of 10)."
  22. # Contents:  ibm_args.c vms_args.c
  23. # Wrapped by brad@hcx1 on Thu May  7 12:12:25 1992
  24. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  25. if test -f 'ibm_args.c' -a "${1}" != "-c" ; then 
  26.   echo shar: Will not clobber existing file \"'ibm_args.c'\"
  27. else
  28. echo shar: Extracting \"'ibm_args.c'\" \(25618 characters\)
  29. sed "s/^X//" >'ibm_args.c' <<'END_OF_FILE'
  30. X/*************************************************************************
  31. X** ^FILE: ibm_args.c - parse MS-DOS and OS/2 argument vectors
  32. X**
  33. X** ^DESCRIPTION:
  34. X**    This file contains the routines used to parse MS-DOS and OS/2
  35. X**    argument vectors and to print MS-DOS and OS/2 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>    Created
  43. X***^^**********************************************************************/
  44. X
  45. X#include <ctype.h>
  46. X#include <useful.h>
  47. X#include "strfuncs.h"
  48. X#include "pgopen.h"
  49. X#include "exit_codes.h"
  50. X
  51. X#define PARSEARGS_PRIVATE   /* include private definitions */
  52. X#include "parseargs.h"
  53. X
  54. XEXTERN  VOID  syserr       ARGS((const char *, ...));
  55. XEXTERN  VOID  usrerr       ARGS((const char *, ...));
  56. XEXTERN  char *getenv       ARGS((const char *));
  57. XEXTERN  VOID  get_winsize  ARGS((int, int *, int *));
  58. X
  59. XVERSIONID("$Header: parseargs.c,v 2.1 89/12/30 20:59:48 eric Exp $");
  60. X
  61. X/***************************************************************************
  62. X** ^GLOBAL-VARIABLE: OptPrefix, KwdPrefix
  63. X**
  64. X** ^VISIBILITY:
  65. X**    static-global (visible to all functions in this file).
  66. X**
  67. X** ^DESCRIPTION:
  68. X**    OptPrefix contains the single character prefix used to precede
  69. X**    an option switch on the command-line.
  70. X**
  71. X**    KwdPrefix contains the single character prefix used to precede
  72. X**    a keyword switch on the command-line.
  73. X***^^**********************************************************************/
  74. Xstatic  char  OptPrefix='/';
  75. Xstatic  char  KwdPrefix='/';
  76. X
  77. X#define  isUNIXISH  ( OptPrefix == '-' )
  78. X
  79. X
  80. X/***************************************************************************
  81. X** ^GLOBAL-VARIABLE: Usage_Requested
  82. X**
  83. X** ^VISIBILITY:
  84. X**    static-global (visible to all functions in this file).
  85. X**
  86. X** ^DESCRIPTION:
  87. X**    Indicates whether a usage message was requested by the user
  88. X**    (as opposed to triggerred by a syntax error).  If the message
  89. X**    is requested by the user then it is always printed in verbose
  90. X**    mode and does not return an error-status-code.
  91. X***^^**********************************************************************/
  92. Xstatic  BOOL  Usage_Requested = FALSE;
  93. X
  94. X
  95. X   /* macros to detect an option/keyword -- watch out for side effects!! */
  96. X#define isOPT(s)  \
  97. X   ( !BTEST(cmd_flags(cmd), pa_KWDSONLY)  && \
  98. X     !BTEST(cmd_state(cmd), ps_NOFLAGS)  && \
  99. X     *s == OptPrefix  &&  *(s+1) \
  100. X   )
  101. X
  102. X#define isKWD(s)  \
  103. X   ( !BTEST(cmd_flags(cmd), pa_OPTSONLY)  && \
  104. X     !BTEST(cmd_state(cmd), ps_NOFLAGS)  && \
  105. X     *s == KwdPrefix  &&  *(s+1) \
  106. X   )
  107. X
  108. X
  109. X/***************************************************************************
  110. X** ^FUNCTION: get_prefixes - determine short and long keyword prefixes
  111. X**
  112. X** ^SYNOPSIS:
  113. X*/
  114. X#ifndef __ANSI_C__
  115. X   static VOID get_prefixes()
  116. X#endif
  117. X/*  
  118. X** ^PARAMETERS:
  119. X**    None.
  120. X**
  121. X** ^DESCRIPTION:
  122. X**    Get_prefixes will determine the prefixes to used to denote option
  123. X**    switches and keyword switches on the command-line.  The prefixes
  124. X**    are determined by the $SWITCHAR environment varaible. The first
  125. X**    character of the variable is the option-switch prefix and the second
  126. X**    character is the keyword-switch prefix.
  127. X**
  128. X**    If The option-switch prefix is '-' then Unix-style command-line parsing
  129. X**    is performed, otherwise MS-DOS style command-line parsing is used.
  130. X**
  131. X** ^REQUIREMENTS:
  132. X**    None.
  133. X**
  134. X** ^SIDE-EFFECTS:
  135. X**    Sets the global variables "OptPrefix" and "KwdPrefix'.
  136. X**
  137. X** ^RETURN-VALUE:
  138. X**    None.
  139. X**
  140. X** ^ALGORITHM:
  141. X**    - If $SWITCHAR is NULL or empty
  142. X**      - use the defaults ('/' and '/').
  143. X**    - Else
  144. X**      - set the OptPrefix to the first character in SWITCHAR
  145. X**      End-if
  146. X**
  147. X**    - If there is a second character in SWITCHAR
  148. X**      - assign it to KwdPrefix
  149. X**    - Else if OptPrefix is '-'
  150. X**      - then use '+' as the default KwdPrefix
  151. X**    - Else
  152. X**      - use '/' as the default KwdPrefix
  153. X**      End-if
  154. X***^^**********************************************************************/
  155. X#ifdef __ANSI_C__
  156. X   static VOID  get_prefixes( void )
  157. X#endif
  158. X{
  159. X   char *prefixes = getenv( "SWITCHAR" );
  160. X
  161. X   if ( prefixes &&  *prefixes ) {
  162. X      OptPrefix = *prefixes;
  163. X      KwdPrefix = *(prefixes + 1);
  164. X      if ( !KwdPrefix )  KwdPrefix = (( OptPrefix == '-' ) ? '+' : '/');
  165. X   }
  166. X   else {
  167. X      OptPrefix = '/';
  168. X      KwdPrefix = '/';
  169. X   }
  170. X}
  171. X
  172. X
  173. X/***************************************************************************
  174. X** ^FUNCTION: ibm_parse - parse MS-DOS and OS/2 arg-vectors
  175. X**
  176. X** ^SYNOPSIS:
  177. X*/
  178. X#ifndef __ANSI_C__
  179. X   int ibm_parse( argv, argd )
  180. X/*
  181. X** ^PARAMETERS:
  182. X*/
  183. X   char *argv[];
  184. X/*    -- the vector of string arguments from the command-line
  185. X*/
  186. X   ARGDESC argd[];
  187. X/*    -- the programmer description of the command and its args
  188. X*/
  189. X#endif  /* !__ANSI_C__ */
  190. X  
  191. X/* ^DESCRIPTION:
  192. X**    Ibm_parse will parse the arguments in the given vector of strings,
  193. X**    assign the corresponding values to the command-line arguments specified
  194. X**    in argd, and check the syntax of the command-line.
  195. X**
  196. X** ^REQUIREMENTS:
  197. X**    The final element in argv must be a NULL pointer.
  198. X**
  199. X** ^SIDE-EFFECTS:
  200. X**    argd is modified according to the command-line description and parameters
  201. X**
  202. X** ^RETURN-VALUE:
  203. X**    pe_SUCCESS (0) if no errors are encountered
  204. X**    pe_SYSTEM (-1) if a system error is encountered
  205. X**    pe_SYNTAX if a syntax error is encountered
  206. X**
  207. X** ^ALGORITHM:
  208. X**    - get the active option and keyword prefixes
  209. X**    - determine whether to use Unix style or not (based on the prefixes)
  210. X**    - for each command-line argument
  211. X**       - attempt to match the argument as a keyword
  212. X**       - if it is a keyword argument
  213. X**          - record and convert its value (if any)
  214. X**         else attempt to match the argument as an option
  215. X**         if it is an option
  216. X**          - record and convert its value (if any)
  217. X**         else it is a positional parameter
  218. X**          - record and convert its value (if any)
  219. X**         else there are too many arguments
  220. X**          - return pe_SYNTAX
  221. X**         end-if
  222. X**       end-for
  223. X***^^**********************************************************************/
  224. X#ifdef __ANSI_C__
  225. X   int ibm_parse( char *argv[], ARGDESC argd[] )
  226. X#endif
  227. X{
  228. X   register ARGDESC *ad, *args, *cmd;
  229. X   register char **av = argv;
  230. X   register char *p;
  231. X   argName_t  name;
  232. X   argMask_t  flags;
  233. X   int  parse_error = pe_SUCCESS;
  234. X   BOOL  ad_okay, is_match = FALSE;
  235. X
  236. X   if ( !argd )  return  parse_error;
  237. X
  238. X      /* initialize command-structure */
  239. X   if ( !CMD_isINIT(argd) )  init_args( argd );
  240. X   cmd = argd;
  241. X
  242. X   get_prefixes();
  243. X
  244. X   while ( av  &&  (p = *av++) ) {
  245. X      /* is this a keyword */
  246. X      if ( isKWD(p) &&
  247. X          ( (OptPrefix != KwdPrefix) || *(p+2) && !strchr(s_ARG_SEP, *(p+2)) )
  248. X         ) {
  249. X         char *s, c = '\0';
  250. X
  251. X         /* check for `++' to end flags */
  252. X         if ( *(p+1) == KwdPrefix  &&  !*(p+2) ) {
  253. X            BSET( cmd_state(cmd), ps_NOFLAGS );
  254. X            cmd_list(cmd) = ARGDESCNULL;
  255. X            continue;
  256. X         }
  257. X
  258. X            /* get past prefix and look for possible argument */
  259. X         s = strpbrk(++p, s_ARG_SEP);
  260. X         if(s) {
  261. X            c = *s;
  262. X            *s++ = '\0';
  263. X         }
  264. X
  265. X         is_match = FALSE;
  266. X         for ( args = argd ; args  &&  !is_match ; args = cmd_defargs(args) ) {
  267. X            for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
  268. X               if ( arg_type(ad) == argDummy )  continue;
  269. X
  270. X               if ( !ARG_isPOSONLY(ad)  &&  match(p, arg_sname(ad)) == 0 ) {
  271. X                  is_match = TRUE;
  272. X                  break;
  273. X               }/*if*/
  274. X            }
  275. X         }
  276. X
  277. X         if ( c )  *(s-1) = c;  /* restore the equal sign */
  278. X
  279. X         if ( !is_match ) {
  280. X            if ( OptPrefix == KwdPrefix ) {
  281. X               goto  MATCHOPT;  /* maybe its an option (and NOT a keyword) */
  282. X            }
  283. X            usrerr("%c%s switch unknown", KwdPrefix, p);
  284. X            parse_error = pe_SYNTAX;
  285. X            cmd_list(cmd) = ARGDESCNULL;
  286. X            continue;
  287. X         }
  288. X
  289. X         /* reset the argument flags - if this arg was already given, some
  290. X         ** of its flags may be set to indicate how it was given before.
  291. X         ** we need to know how it was given now (but save the old ones
  292. X         ** just in case the new one fails).
  293. X         */
  294. X         flags = arg_flags(ad);
  295. X         if ( ARG_isGIVEN(ad) ) {
  296. X            BCLEAR( arg_flags(ad), ARGVALSEP | ARGKEYWORD );
  297. X            if ( !ARG_isMULTIVAL(ad) )  BCLEAR( arg_flags(ad), ARGVALGIVEN );
  298. X         }
  299. X
  300. X         BSET( arg_flags(ad), ARGKEYWORD );
  301. X
  302. X         if( ARG_isMULTIVAL(ad) ) {
  303. X            cmd_list(cmd) = ad;  /* we matched a lst or a vector */
  304. X         }
  305. X         else {
  306. X            cmd_list(cmd) = ARGDESCNULL;
  307. X         }
  308. X
  309. X            /* if usage - just print usage and exit */
  310. X         if ( arg_type(ad) == argUsage ) {
  311. X            Usage_Requested = TRUE;
  312. X            usage(argd);
  313. X            exit(exit_USAGE);
  314. X         }
  315. X
  316. X            /* ARGNOVALs are special, having no value */
  317. X         if ( ! ARG_isVALTAKEN(ad) ) {
  318. X            ad_okay = HANDLE(ad, s, cmd_flags(cmd));
  319. X            if ( !ad_okay ) {
  320. X               arg_flags(ad) = flags;
  321. X               parse_error = pe_SYNTAX;
  322. X            }
  323. X            else {
  324. X               BSET( arg_flags(ad), ARGGIVEN );
  325. X               ad = ARGDESCNULL;
  326. X            }
  327. X            continue;
  328. X         }/*if ARGNOVAL*/
  329. X
  330. X            /* now get the real value */
  331. X         if (!s) {
  332. X            if ( isUNIXISH )  s = *av++;
  333. X            if ( !isUNIXISH  ||  !s  ||  isOPT(s)  ||  isKWD(s) ) {
  334. X               if ( ARG_isVALOPTIONAL(ad) ) {
  335. X                  BSET( arg_flags(ad), ARGGIVEN );
  336. X               }
  337. X               else {
  338. X                  (VOID) get_kwdname( arg_sname(ad), name );
  339. X                  usrerr("%c%s switch requires an argument", KwdPrefix, name);
  340. X                  arg_flags(ad) = flags;
  341. X                  parse_error = pe_SYNTAX;
  342. X               }
  343. X
  344. X               if ( isUNIXISH )  av--;
  345. X               continue;
  346. X            }/*if arg*/
  347. X            if ( isUNIXISH )  BSET( arg_flags(ad), ARGVALSEP );
  348. X         }/*if empty*/
  349. X
  350. X            /* try to convert the type */
  351. X         ad_okay = HANDLE(ad, s, cmd_flags(cmd));
  352. X         if ( !ad_okay ) {
  353. X            arg_flags(ad) = flags;
  354. X            parse_error = pe_SYNTAX;
  355. X         }
  356. X         else {
  357. X            BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
  358. X         }
  359. X
  360. X         continue;
  361. X      }/*if keyword*/
  362. X      else if ( isOPT(p) ) {
  363. X         p++;  /* skip over option prefix */
  364. X
  365. XMATCHOPT:
  366. X            /* check for `--' to end flags */
  367. X         if ( *p == OptPrefix  &&  !*(p+1) ) {
  368. X            BSET( cmd_state(cmd), ps_NOFLAGS );
  369. X            cmd_list(cmd) = ARGDESCNULL;
  370. X            continue;
  371. X         }
  372. X
  373. X         /* We have a flag argument;
  374. X         ** remember that in the case of single character keywords,
  375. X         ** the conversion function (ad_type) tells us how many characters
  376. X         ** were used. We need that information to decide how many 
  377. X         ** characters to skip before the next iteration of the while loop.
  378. X         */
  379. X         while (*p) {  /* while not end of switch-chars */
  380. X
  381. X               /* find the flag in the list */
  382. X            is_match = FALSE;
  383. X            for (args = argd; args  &&  !is_match ; args = cmd_defargs(args)) {
  384. X               for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
  385. X                  register char c1 = arg_cname(ad);
  386. X                  register char c2 = *p;
  387. X
  388. X                  if ( arg_type(ad) == argDummy )   continue;
  389. X                  if ( ARG_isPOSONLY(ad) )   continue;
  390. X
  391. X                  if ( BTEST(cmd_flags(cmd), pa_ANYCASE) ) {
  392. X                     c1 = TOUPPER( c1 );
  393. X                     c2 = TOUPPER( c2 );
  394. X                  }/*if*/
  395. X
  396. X                  if ( c1 == c2 ) {
  397. X                     is_match = TRUE;
  398. X                     break;
  399. X                  }/*if*/
  400. X               }
  401. X            }
  402. X            if ( !is_match ) {
  403. X                  usrerr("%c%c switch unknown", OptPrefix, *p++);
  404. X                  parse_error = pe_SYNTAX;
  405. X                  cmd_list(cmd) = ARGDESCNULL;
  406. X                  if ( !isUNIXISH  &&  *p == *s_ARG_SEP )  p += strlen(p);
  407. X                  if ( !isUNIXISH  &&  *p == OptPrefix )  ++p;
  408. X                  continue;
  409. X            }/* if unknown-option */
  410. X
  411. X            /* reset the argument flags - if this arg was already given, some
  412. X            ** of its flags may be set to indicate how it was given before.
  413. X            ** we need to know how it was given now (but save the old ones
  414. X            ** just in case the new one fails).
  415. X            */
  416. X            flags = arg_flags(ad);
  417. X            if ( ARG_isGIVEN(ad) ) {
  418. X               BCLEAR( arg_flags(ad), ARGVALSEP | ARGKEYWORD );
  419. X               if ( !ARG_isMULTIVAL(ad) )  BCLEAR( arg_flags(ad), ARGVALGIVEN );
  420. X            }
  421. X
  422. X            if ( ARG_isMULTIVAL(ad) ) {
  423. X               cmd_list(cmd) = ad;  /* we matched a list (or a vector) */
  424. X            }
  425. X            else {
  426. X               cmd_list(cmd) = ARGDESCNULL;
  427. X            }
  428. X
  429. X               /* move p up to point to the (possible) value */
  430. X            p++;
  431. X            if ( !isUNIXISH  &&  *p  &&  strchr(s_ARG_SEP, *p) )  ++p;
  432. X
  433. X            /* if usage - just print usage and exit */
  434. X            if (arg_type(ad) == argUsage) {
  435. X               Usage_Requested = TRUE;
  436. X               usage(argd);
  437. X               exit(exit_USAGE);
  438. X            }
  439. X
  440. X               /* ARGNOVALs are special, having no value */
  441. X            if (! ARG_isVALTAKEN(ad)) {
  442. X               ad_okay = HANDLE(ad, p, cmd_flags(cmd));
  443. X
  444. X               if ( !ad_okay ) {
  445. X                  arg_flags(ad) = flags;
  446. X                  parse_error = pe_SYNTAX;
  447. X               }/*if*/
  448. X               else {
  449. X                  BSET( arg_flags(ad), ARGGIVEN );
  450. X                  ad = ARGDESCNULL;
  451. X                  if ( ad_okay < 0 )  p -= ad_okay;
  452. X               }/*else*/
  453. X
  454. X               if ( !isUNIXISH  &&  *p == OptPrefix )  ++p;
  455. X               continue;
  456. X            }/*if*/
  457. X
  458. X               /* now get the real value */
  459. X            if ( !(*p) ) {
  460. X               if ( isUNIXISH )  p = *av++;
  461. X               if ( !isUNIXISH  ||  !p  ||  isOPT(p)  ||  isKWD(p) ) {
  462. X                  if ( ARG_isVALOPTIONAL(ad) ) {
  463. X                     BSET( arg_flags(ad), ARGGIVEN );
  464. X                  }
  465. X                  else {
  466. X                     (VOID) get_argname(arg_sname(ad), name);
  467. X                     usrerr( "%s required for %c%c flag",
  468. X                             name, OptPrefix, arg_cname(ad) );
  469. X                     arg_flags(ad) = flags;
  470. X                     parse_error = pe_SYNTAX;
  471. X                  }/*else*/
  472. X
  473. X                  if ( isUNIXISH )  av--;
  474. X                  break;
  475. X               }/*if arg*/
  476. X               if ( isUNIXISH )  BSET( arg_flags(ad), ARGVALSEP );
  477. X            }/*if empty*/
  478. X
  479. X               /* try to convert the type */
  480. X            ad_okay = HANDLE(ad, p, cmd_flags(cmd));
  481. X            if ( !ad_okay ) {
  482. X               arg_flags(ad) = flags;
  483. X               parse_error = pe_SYNTAX;
  484. X               p += strlen(p);
  485. X            }/*if*/
  486. X            else {
  487. X               BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
  488. X               if ( isUNIXISH  &&  ad_okay < 0  &&  !ARG_isVALSEPARATE(ad) ) {
  489. X                  p -= ad_okay;
  490. X               }
  491. X               else {
  492. X                  p += strlen(p);
  493. X               }
  494. X            }/*else*/
  495. X
  496. X            if ( !isUNIXISH  &&  *p == OptPrefix )  ++p;
  497. X         }/*while*/
  498. X      }/*elif option*/
  499. X      else {
  500. X            /* parsing a list of arguments */
  501. X         if ( cmd_list(cmd) ) {  /* we're in the middle of a list/vector */
  502. X            ad = cmd_list(cmd);
  503. X            flags = arg_flags(ad);  /* reset flags for this argv-item */
  504. X            if ( ARG_isGIVEN(ad) ) {
  505. X               BCLEAR( arg_flags(ad), ARGVALSEP | ARGKEYWORD );
  506. X            }
  507. X
  508. X            BSET( arg_flags(ad), ARGVALSEP );
  509. X
  510. X            ad_okay = HANDLE(ad, p, cmd_flags(cmd));
  511. X            if ( !ad_okay ) {
  512. X               arg_flags(ad) = flags;
  513. X               parse_error = pe_SYNTAX;
  514. X            }
  515. X
  516. X            continue;
  517. X         }
  518. X            /* positional argument */
  519. X         is_match = FALSE;
  520. X         for (args = argd; args  &&  !is_match ; args = cmd_defargs(args)) {
  521. X            for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
  522. X               if (arg_type(ad) == argDummy)  continue;
  523. X
  524. X               if ( ARG_isPOSITIONAL(ad)  &&
  525. X                    (!ARG_isGIVEN(ad) ||  ARG_isMULTIVAL(ad)) ) {
  526. X                  is_match = TRUE;
  527. X                  break;
  528. X               }/*if*/
  529. X            }
  530. X         }
  531. X
  532. X         if ( !is_match ) {
  533. X            usrerr("too many arguments");
  534. X            parse_error = pe_SYNTAX;
  535. X            continue;
  536. X         }
  537. X
  538. X         flags = arg_flags(ad);
  539. X         if ( ARG_isGIVEN(ad) ) {
  540. X            BCLEAR( arg_flags(ad), ARGVALSEP | ARGKEYWORD );
  541. X            if ( !ARG_isMULTIVAL(ad) )  BCLEAR( arg_flags(ad), ARGVALGIVEN );
  542. X         }
  543. X
  544. X         if ( ARG_isMULTIVAL(ad) ) {
  545. X            cmd_list(cmd) = ad;
  546. X         }
  547. X
  548. X         /* if FLAGS1ST is set then first positional marks end-of-flags */
  549. X         if ( BTEST(cmd_flags(cmd), pa_FLAGS1ST) ) {
  550. X            BSET( cmd_state(cmd), ps_NOFLAGS );
  551. X         }
  552. X
  553. X         BSET( arg_flags(ad), ARGVALSEP );
  554. X
  555. X            /* try to convert */
  556. X         ad_okay = HANDLE(ad, p, cmd_flags(cmd));
  557. X         if ( !ad_okay ) {
  558. X            arg_flags(ad) = flags;
  559. X            parse_error = pe_SYNTAX;
  560. X         }
  561. X         else {
  562. X            BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
  563. X         }
  564. X      }/*else*/
  565. X   }/*while*/
  566. X
  567. X   return  parse_error;
  568. X}
  569. X
  570. X
  571. X/***************************************************************************
  572. X** ^FUNCTION: fmtarg - format command-argument syntax
  573. X**
  574. X** ^SYNOPSIS:
  575. X*/
  576. X#ifndef __ANSI_C__
  577. X   static int fmtarg( ad, buf, usgflags )
  578. X/*
  579. X** ^PARAMETERS:
  580. X*/
  581. X   ARGDESC *ad;
  582. X/*    -- pointer to the argument to format
  583. X*/
  584. X   char *buf;
  585. X/*    -- character buffer to hold the formatted result
  586. X*/
  587. X   argMask_t usgflags;
  588. X/*    -- set of bitmasks corresponding to the value of the user's USAGECNTL
  589. X**       environment variable
  590. X*/
  591. X#endif  /* !__ANSI_C__ */
  592. X
  593. X/* ^DESCRIPTION:
  594. X**    Fmtarg will determine the proper command-line syntax for the
  595. X**    given argument and write the result to the given buffer.
  596. X**
  597. X** ^REQUIREMENTS:
  598. X**    buf must be large enough to hold the formatted result (100 characters
  599. X**    should do the trick).
  600. X**
  601. X** ^SIDE-EFFECTS:
  602. X**    buf is overwritten.
  603. X**
  604. X** ^RETURN-VALUE:
  605. X**    The number of printable characters in the argument-syntax-string
  606. X**
  607. X** ^ALGORITHM:
  608. X**    Print argument usage based on whether or not the argument is
  609. X**    positional, hidden, multi-valued (list or vector), etc ....
  610. X**    Optional arguments and values are enclosed in square braces.
  611. X**
  612. X**    Any syntax biases reflected in usgflags will be used.
  613. X***^^**********************************************************************/
  614. X#ifdef __ANSI_C__
  615. X   static int fmtarg( const ARGDESC *ad, char *buf, argMask_t usgflags )
  616. X#endif
  617. X{
  618. X   /* buf must already be large enough */
  619. X   char *pos;
  620. X   argName_t   name, keyword;
  621. X
  622. X   (VOID) get_argname( arg_sname(ad), name );
  623. X
  624. X   if (ARG_isPOSITIONAL(ad)) {
  625. X      sprintf( buf, "<%s>", name );
  626. X   }
  627. X   else {
  628. X      (VOID) get_kwdname( arg_sname(ad), keyword );
  629. X
  630. X      if ( isupper(arg_cname(ad))  &&  toupper(*keyword) == arg_cname(ad) ) {
  631. X         *keyword = toupper(*keyword);
  632. X      }
  633. X
  634. X      if ( !(usgflags & usg_LONGOPTS) ) {
  635. X         sprintf( buf, "%c%c", OptPrefix, arg_cname(ad) );
  636. X      }
  637. X      else if ( !(usgflags & usg_OPTS) ) {
  638. X         sprintf( buf, "%c%s", KwdPrefix, keyword );
  639. X      }
  640. X      else  {  /* use both */
  641. X         if ( OptPrefix == KwdPrefix  &&  *keyword == arg_cname(ad) ) {
  642. X            if ( !*(keyword+1) )
  643. X               sprintf( buf, "%c%c", OptPrefix, arg_cname(ad) );
  644. X            else
  645. X               sprintf( buf, "%c%c[%s]", OptPrefix, arg_cname(ad), keyword+1 );
  646. X         }
  647. X         else {
  648. X            sprintf( buf, "%c%c|%c%s", OptPrefix, arg_cname(ad),
  649. X                                       KwdPrefix, keyword );
  650. X         }
  651. X      }
  652. X
  653. X      pos = buf + strlen(buf);
  654. X
  655. X      if ( ARG_isVALTAKEN(ad)  &&  !ARG_isBOOLEAN(ad)  &&  !ARG_isPSEUDOARG(ad) ) {
  656. X         if ( isUNIXISH )  *(pos++) = ' ';
  657. X         if ( ARG_isVALOPTIONAL(ad) )  *(pos++) = '[';
  658. X         if ( !isUNIXISH )  *(pos++) = *s_ARG_SEP;
  659. X         sprintf( pos, "<%s>", name );
  660. X         if ( ARG_isVALOPTIONAL(ad) )  strcat(pos, "]");
  661. X      }/*if*/
  662. X   }/*else*/
  663. X
  664. X   return  strlen(buf);
  665. X}
  666. X
  667. X
  668. X/***************************************************************************
  669. X** ^FUNCTION: ibm_usage - print a usage message
  670. X**
  671. X** ^SYNOPSIS:
  672. X*/
  673. X#ifndef __ANSI_C__
  674. X   VOID ibm_usage( argd, usage_flags )
  675. X/*
  676. X** ^PARAMETERS:
  677. X*/
  678. X   ARGDESC *argd;
  679. X/*    -- the command-descriptor array
  680. X*/
  681. X   argMask_t usage_flags;
  682. X/*    -- flags set by $USAGECNTL
  683. X*/
  684. X#endif  /* !__ANSI_C__ */
  685. X
  686. X/* ^DESCRIPTION:
  687. X**    Ibm_usage will print the Unix command-line usage of the given
  688. X**    command on standard diagnostic output (stderr). The content of the
  689. X**    usage message is controlled by the bitmasks in usage_flags which
  690. X**    correspond to the settings in the user's USAGECNTL variable.
  691. X**
  692. X** ^REQUIREMENTS:
  693. X**    argd should be a non-null command-line argument-descriptor array
  694. X**
  695. X** ^SIDE-EFFECTS:
  696. X**    Prints on stderr.
  697. X**
  698. X** ^RETURN-VALUE:
  699. X**    None.
  700. X**
  701. X** ^ALGORITHM:
  702. X**    - if no usage is desired then exit
  703. X**    - if paging is requested print to the pager instead of stderr
  704. X**    - print the command-line syntax
  705. X**    - if the description is requested print it
  706. X**    - if verbose mode is requested, print the description of each argument
  707. X***^^**********************************************************************/
  708. X#ifdef __ANSI_C__
  709. X   void ibm_usage( const ARGDESC *argd, argMask_t usage_flags )
  710. X#endif
  711. X{
  712. X   register CONST ARGDESC  *ad, *args, *cmd;
  713. X   int  max_cols = 80, max_lines  = 24;
  714. X   int  ll, margin, options, longest, positionals;
  715. X   BOOL first = TRUE;
  716. X   FILE *fp;
  717. X
  718. X   if ( !argd )  return;
  719. X
  720. X      /* initialize command-structure */
  721. X   if ( !CMD_isINIT(argd) )  init_args( (ARGDESC *)argd );
  722. X   cmd = argd;
  723. X
  724. X      /* force verbose-mode if requested */
  725. X   if ( Usage_Requested )   BSET( usage_flags, usg_VERBOSE );
  726. X
  727. X   if ( BTEST(usage_flags, usg_NONE) )  return;
  728. X
  729. X   fp = ( BTEST(usage_flags, usg_PAGED) )
  730. X      ? pgopen( stderr, getenv("USAGE_PAGER") )
  731. X      : stderr;
  732. X
  733. X      /* get screen size */
  734. X   get_winsize( fileno(fp), &max_lines, &max_cols );
  735. X
  736. X   fprintf(fp, "Usage: %.*s", ProgNameLen, (ProgName) ? ProgName : "");
  737. X
  738. X   ll = ProgNameLen + 7;
  739. X   margin = ll + 1;
  740. X   longest = 0;
  741. X
  742. X      /* print Synopsis */
  743. X   for ( positionals = 0 ; positionals < 2 ; positionals++ ) {
  744. X      for ( args = argd ; args ; args = cmd_defargs(args) ) {
  745. X         for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
  746. X            argName_t  buf;
  747. X            int pl;
  748. X
  749. X               /* don't display hidden arguments */
  750. X            if ( ARG_isHIDDEN(ad) )  continue;
  751. X            if ( !positionals  &&  ARG_isPOSITIONAL(ad) )  continue;
  752. X            if ( positionals  &&  !ARG_isPOSITIONAL(ad) )  continue;
  753. X
  754. X               /* figure out how wide this parameter is (for printing) */
  755. X            pl = fmtarg(ad, buf, usage_flags);
  756. X
  757. X            if ( pl > longest)  longest = pl;
  758. X
  759. X            if  ( ARG_isMULTIVAL(ad) ) {
  760. X               strcat( buf, "..." );
  761. X               pl += 3;
  762. X            }
  763. X            if ( !ARG_isREQUIRED(ad) ) {
  764. X               pl += 2;
  765. X            }
  766. X
  767. X            /* see if this will fit */
  768. X            if ( (ll + pl + 1) > (max_cols - first) ) {
  769. X                  /* no... start a new line */
  770. X               fprintf(fp, "\n%*s", margin, "");
  771. X               ll = margin;
  772. X            }
  773. X            else {
  774. X                  /* yes... just throw in a space */
  775. X               fputc(' ', fp);
  776. X               ++ll;
  777. X            }
  778. X            ll += pl;
  779. X
  780. X               /* show the argument */
  781. X            if ( !ARG_isREQUIRED(ad) )  fputc('[', fp);
  782. X            fprintf(fp, buf);
  783. X            if ( !ARG_isREQUIRED(ad) )  fputc(']', fp);
  784. X
  785. X            first = FALSE;  /* not first line anymore */
  786. X         }/*for each ad */
  787. X      }/* for each argd */
  788. X   }/* for each parm-type */
  789. X
  790. X   fputc('\n', fp);
  791. X
  792. X   if ( BTEST(usage_flags, usg_DESCRIPTION) ) {
  793. X      CONST char *description = cmd_description(cmd);
  794. X
  795. X      if ( description  &&  *description ) {
  796. X         fprintf( fp, "Description:\n" );
  797. X         indent_para(fp, max_cols, 8, "", 0, description, 0);
  798. X         fputc( '\n', fp );
  799. X      }
  800. X   }/*if*/
  801. X
  802. X   if ( !BTEST(usage_flags, usg_VERBOSE) )  {
  803. X      if ( pgactive(fp) )  (VOID) pgclose( fp );
  804. X      return;
  805. X   }
  806. X
  807. X   options = 0;
  808. X
  809. X      /* print Argument descriptions */
  810. X   for ( positionals = 0 ; positionals < 2 ; positionals++ ) {
  811. X      for ( args = argd ; args ; args = cmd_defargs(args) ) {
  812. X         for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
  813. X            argName_t  buf;
  814. X            char  *desc;
  815. X            int  desclen;
  816. X
  817. X               /* don't display hidden arguments */
  818. X            if ( ARG_isHIDDEN(ad) )  continue;
  819. X            if ( !positionals  &&  ARG_isPOSITIONAL(ad) )  continue;
  820. X            if ( positionals  &&  !ARG_isPOSITIONAL(ad) )  continue;
  821. X
  822. X            if ( !options++ )   fprintf(fp, "Options/Arguments:\n");
  823. X            fmtarg(ad, buf, usage_flags);
  824. X            desc = get_argdesc(arg_description(ad), &desclen);
  825. X            indent_para( fp, max_cols, 8, buf, longest+2, desc, desclen );
  826. X         }/*for each ad */
  827. X      }/* for each argd */
  828. X   }/* for each parm-type */
  829. X
  830. X   if ( pgactive(fp) )  (VOID) pgclose( fp );
  831. X}
  832. X
  833. END_OF_FILE
  834. if test 25618 -ne `wc -c <'ibm_args.c'`; then
  835.     echo shar: \"'ibm_args.c'\" unpacked with wrong size!
  836. fi
  837. # end of 'ibm_args.c'
  838. fi
  839. if test -f 'vms_args.c' -a "${1}" != "-c" ; then 
  840.   echo shar: Will not clobber existing file \"'vms_args.c'\"
  841. else
  842. echo shar: Extracting \"'vms_args.c'\" \(32340 characters\)
  843. sed "s/^X//" >'vms_args.c' <<'END_OF_FILE'
  844. X/*************************************************************************
  845. X** ^FILE: vms_args.c - parse VMS/DCL argument vectors
  846. X**
  847. X** ^DESCRIPTION:
  848. X**    This file contains the routines used to parse VMS/DCL argument
  849. X**    vectors and to print VMS/DCL usage messages.
  850. X**
  851. X** ^HISTORY:
  852. X**    11/21/91    Brad Appleton    <brad@ssd.csd.harris.com>
  853. X**    - added Mike Levins fix to is_cmdline() to check for 0 length
  854. X**      returned by lib$get_foreign.
  855. X**    - added check of ps_NOTCMDLINE state-flag before calling is_cmdline()
  856. X**    - fixed problem in vms_parse() where ARGVALGIVEN was getting set in
  857. X**      place of ARGGIVEN.
  858. X**
  859. X**    08/27/91     Earl Chew     <cechew@bruce.cs.monash.edu.au>
  860. X**    - Use ProgNameLen when accessing ProgName
  861. X**    - Use get_argdesc() to access description
  862. X**
  863. X**    12/03/90    Brad Appleton    <brad@ssd.csd.harris.com>    Created
  864. X***^^**********************************************************************/
  865. X
  866. X#include <stdio.h>
  867. X#include <ctype.h>
  868. X#include <useful.h>
  869. X
  870. X#ifdef vms
  871. X# include <descrip.h>
  872. X#endif
  873. X
  874. X#include "strfuncs.h"
  875. X#include "pgopen.h"
  876. X#include "exit_codes.h"
  877. X
  878. X#define PARSEARGS_PRIVATE   /* include private definitions */
  879. X#include "parseargs.h"
  880. X
  881. XEXTERN  VOID  syserr       ARGS((const char *, ...));
  882. XEXTERN  VOID  usrerr       ARGS((const char *, ...));
  883. XEXTERN  VOID  get_winsize  ARGS((int, int *, int *));
  884. XEXTERN  BOOL  argInput     ARGS((ARGDESC *, char *, BOOL));
  885. XEXTERN  BOOL  argOutput    ARGS((ARGDESC *, char *, BOOL));
  886. X
  887. XVERSIONID("$Header: vms_args.c,v 1.1 90/08/23 18:00:00 brad Exp $");
  888. X
  889. X/***************************************************************************
  890. X** ^GLOBAL-VARIABLE: Usage_Requested
  891. X**
  892. X** ^VISIBILITY:
  893. X**    static-global (visible to all functions in this file).
  894. X**
  895. X** ^DESCRIPTION:
  896. X**    Indicates whether a usage message was requested by the user
  897. X**    (as opposed to triggerred by a syntax error).  If the message
  898. X**    is requested by the user then it is always printed in verbose
  899. X**    mode and does not return an error-status-code.
  900. X***^^**********************************************************************/
  901. Xstatic  BOOL  Usage_Requested = FALSE;
  902. X
  903. X
  904. X#define MAXCMDLINE 255
  905. X#define VNULL (VOID *) 0
  906. X
  907. X#define TOGGLE(flag)  flag = (flag) ? FALSE : TRUE
  908. X
  909. X   /* define mappings */
  910. X#define  c_SPACE   '\001'   /* whitespace */
  911. X#define  c_QUAL    '\002'   /* qualifier-delimiter */
  912. X#define  c_EQUAL   '\003'   /* qualifier-argument separator */
  913. X#define  c_COLON   '\004'   /* qualifier-argument separator */
  914. X#define  c_PLUS    '\005'   /* list-item separator character */
  915. X#define  c_COMMA   '\006'   /* list-item separator character */
  916. X
  917. X
  918. Xtypedef enum {
  919. X   Parameter,   /* token is a parameter */
  920. X   Qualifier,   /* token is a qualifier */
  921. X   EndOfLine    /* NUL-token (signifies end of tokens) */
  922. X} dcl_arg_t;
  923. X
  924. X
  925. Xtypedef struct {
  926. X   dcl_arg_t  type;   /* token type */
  927. X   char      *token;  /* token value */
  928. X} dcl_token_t;
  929. X
  930. X
  931. X
  932. X/***************************************************************************
  933. X** ^FUNCTION: is_cmdline - retrieve the original command-line
  934. X**
  935. X** ^SYNOPSIS:
  936. X*/
  937. X#ifndef __ANSI_C__
  938. X   static BOOL is_cmdline( argv, result )
  939. X/*
  940. X** ^PARAMETERS:
  941. X*/
  942. X   char *argv[];
  943. X/*    -- array of strings
  944. X*/
  945. X   char **result;
  946. X/*    -- pointer to resultant command-line
  947. X*/
  948. X#endif  /* !__ANSI_C__ */
  949. X
  950. X/* ^DESCRIPTION:
  951. X**    Is_cmdline will compare the given vector of strings to the actual
  952. X**    string given on the command-line. If the two are approximately 
  953. X**    equivalent (modulo quotes and case) then the original command-line
  954. X**    is copied to result, otherwise all the elements of argv are concat-
  955. X**    enated together (in order and separated by whitespace) and assigned
  956. X**    to *result.
  957. X**
  958. X** ^REQUIREMENTS:
  959. X**    argv must be non-null
  960. X**
  961. X** ^SIDE-EFFECTS:
  962. X**    *result is assigned to either the concatenated argv string or the
  963. X**    original command-line. The result should be freed using free().
  964. X**
  965. X** ^RETURN-VALUE:
  966. X**    FALSE if the argv given is different from the command-line;
  967. X**    TRUE otherwise.
  968. X**
  969. X** ^CAVEATS:
  970. X**    The comparison is case blind and double quotes are ignored in the
  971. X**    command-line.  This is because lib$get_foreign returns double quotes
  972. X**    intact, while VAX-C strips them off.
  973. X**
  974. X** ^ACKNOWLEDGEMENTS:
  975. X**    Thanx to Jim Barbour for writing most of this code. --BDA
  976. X**
  977. X** ^ALGORITHM:
  978. X**    - Make a single string out of argv
  979. X**    - compare the "big" string to the command-line
  980. X**    - IF they are "equivalent" assign command-line to result & return TRUE.
  981. X**      ELSE assign the "big" string to result and return FALSE.
  982. X***^^**********************************************************************/
  983. X#ifdef __ANSI_C__
  984. X   static BOOL is_cmdline( const char *argv[], char **result )
  985. X#endif
  986. X{
  987. X   register CONST char *avstr;
  988. X#ifdef vms
  989. X   unsigned long int stat;
  990. X   unsigned short int len;
  991. X   register CONST char *aptr, *sptr;
  992. X   static char str[ MAXCMDLINE ];
  993. X   static BOOL got_cmd_line = FALSE;
  994. X   $DESCRIPTOR(str_d, str);
  995. X#endif
  996. X
  997. X      /* make a single string out of argv */
  998. X   avstr = strjoin( argv, " " );
  999. X
  1000. X#ifndef vms
  1001. X   *result = (char *)avstr;
  1002. X   return  FALSE;
  1003. X
  1004. X#else
  1005. X      /* get the original command-line */
  1006. X   if ( ! got_cmd_line ) {
  1007. X      stat = lib$get_foreign( &str_d, VNULL, &len, VNULL );
  1008. X      str[len] = '\0';
  1009. X      got_cmd_line = TRUE;
  1010. X      if (! (stat & 1))  exit( stat );
  1011. X   }
  1012. X
  1013. X      /* if we didnt have a command-line, dont bother comparing */
  1014. X   if ( !*str ) {
  1015. X      *result = (char *)avstr;
  1016. X      return  FALSE;
  1017. X   }
  1018. X
  1019. X      /* compare the two */
  1020. X   for ( aptr = avstr, sptr = str ; *aptr && *sptr ; sptr++ ) {
  1021. X      if ( toupper(*sptr) == toupper(*aptr) ) {
  1022. X         ++aptr;
  1023. X      }
  1024. X      else  if ( *sptr != '"' ) {
  1025. X         *result = (char *)avstr;
  1026. X         return  FALSE;
  1027. X      }
  1028. X   }
  1029. X
  1030. X   *result = strdup( str );
  1031. X   free( avstr );
  1032. X   return  TRUE;
  1033. X#endif
  1034. X}
  1035. X
  1036. X
  1037. X/***************************************************************************
  1038. X** ^FUNCTION: dcl_strxlat - translate a string according to DCL syntax
  1039. X**
  1040. X** ^SYNOPSIS:
  1041. X*/
  1042. X#ifndef __ANSI_C__
  1043. X   static char *dcl_strxlat( str )
  1044. X/*
  1045. X** ^PARAMETERS:
  1046. X*/
  1047. X   char *str;
  1048. X/*    -- the string to translate.
  1049. X*/
  1050. X#endif  /* !__ANSI_C__ */
  1051. X
  1052. X/* ^DESCRIPTION:
  1053. X**    Dcl_strxlat will attempt to convert the given string to canonical
  1054. X**    form by escaping any unquoted special characters, and removing any
  1055. X**    unquoted whitespace around special characters (such as '=' and '/').
  1056. X**    Since the special characters are replaced with special codes, quotes
  1057. X**    are also removed.
  1058. X**
  1059. X** ^REQUIREMENTS:
  1060. X**    <str> should be non-null and non-empty
  1061. X**
  1062. X** ^SIDE-EFFECTS:
  1063. X**    <str> is "trimmed" to canonical form and special characters are mapped
  1064. X**    to a unique code.
  1065. X**
  1066. X** ^RETURN-VALUE:
  1067. X**    The address of the translated string.
  1068. X**
  1069. X** ^ALGORITHM:
  1070. X**    - remove all unquoted whitespace following any unquoted "/:=+("
  1071. X**    - remove all unquoted whitespace preceding any unquoted "/:=+)"
  1072. X**    - compress all unquoted whitespace,
  1073. X**    - remove all unquoted parentheses,
  1074. X**    - re-map all other unquoted special characters and remove quotes.
  1075. X**      use the following mapping:
  1076. X**           whitespace   ==>   '\001'
  1077. X**             '/'        ==>   '\002'
  1078. X**             ':' & '='  ==>   '\003'
  1079. X**             ',' & '+'  ==>   '\004'
  1080. X***^^**********************************************************************/
  1081. X#ifdef __ANSI_C__
  1082. X   static char *dcl_strxlat( char *str )
  1083. X#endif
  1084. X{
  1085. X   register char c, *pread = str, *pwrite = str;
  1086. X   BOOL quoted = FALSE;
  1087. X
  1088. X   /*
  1089. X   ** pass1 - scan forward, removing all whitespace after unquoted "/:=+,("
  1090. X   */
  1091. X   while ( c = *pwrite++ = *pread++ ) {
  1092. X      if ( c == '"' )   TOGGLE(quoted);
  1093. X      if ( !quoted   &&   strchr("/:=+,(", c) )
  1094. X         while( isspace(*pread) )   ++pread;
  1095. X   }
  1096. X   *--pwrite = '\0';   /* NUL terminate */
  1097. X
  1098. X   /*
  1099. X   ** pass2 - scan backward, removing all whitespace before unquoted "/:=+,)"
  1100. X   */
  1101. X   pread = --pwrite;  /* set to last NON-NUL char */
  1102. X   quoted = FALSE;
  1103. X   while ( pread >= str ) {
  1104. X      c = *pwrite-- = *pread--;
  1105. X      if ( c == '"' )   TOGGLE(quoted);
  1106. X      if ( !quoted   &&   strchr("/:=+,)", c) )
  1107. X         while( isspace(*pread) )   --pread;
  1108. X   }
  1109. X   strcpy(str, ++pwrite);   /* reset BOS */
  1110. X
  1111. X   /*
  1112. X   ** pass3 - compress all unquoted whitespace,
  1113. X   **         remove all unquoted parentheses,
  1114. X   **         re-map all other unquoted special characters and remove quotes.
  1115. X   **           use the following mapping:
  1116. X   **    whitespace   ->   '\001'
  1117. X   **      '/'        ->   '\002'
  1118. X   **      ':' & '='  ->   '\003'
  1119. X   **      ',' & '+'  ->   '\004'
  1120. X   */
  1121. X   pread = pwrite = str;
  1122. X   quoted = FALSE;
  1123. X   while ( c = *pread++ ) {
  1124. X      if ( c == '"' )
  1125. X         TOGGLE(quoted);
  1126. X      else if ( !quoted   &&   isspace(c) ) {
  1127. X         *pwrite++ = c_SPACE;
  1128. X         while( isspace(*pread) )   ++pread;
  1129. X      }
  1130. X      else if ( !quoted   &&   (c == '(' || c == ')') )
  1131. X         continue;
  1132. X      else if ( !quoted   &&   c == '/' )
  1133. X         *pwrite++ = c_QUAL;
  1134. X      else if ( !quoted   &&   c == ':' )
  1135. X         *pwrite++ = c_COLON;
  1136. X      else if ( !quoted   &&   c == '=' )
  1137. X         *pwrite++ = c_EQUAL;
  1138. X      else if ( !quoted   &&   c == '+' )
  1139. X         *pwrite++ = c_PLUS;
  1140. X      else if ( !quoted   &&   c == ',' )
  1141. X         *pwrite++ = c_COMMA;
  1142. X      else
  1143. X         *pwrite++ = c;
  1144. X   }/*while*/
  1145. X
  1146. X   *pwrite = '\0';   /* NUL-terminate */
  1147. X   return   str;
  1148. X}
  1149. X
  1150. X
  1151. X/***************************************************************************
  1152. X** ^FUNCTION: dcl_split - split a string up into a vector of DCL tokens
  1153. X**
  1154. X** ^SYNOPSIS:
  1155. X*/
  1156. X#ifndef __ANSI_C__
  1157. X   static dcl_token_t  *dcl_split( str )
  1158. X/*
  1159. X** ^PARAMETERS:
  1160. X*/
  1161. X   char *str;
  1162. X/*    -- the string to split up into tokens
  1163. X*/
  1164. X#endif  /* !__ANSI_C__ */
  1165. X
  1166. X/* ^DESCRIPTION:
  1167. X**    Dcl_split will split a string up into tokens (according to DCL grammar
  1168. X**    rules) and will additionally associate each token with a type (namely:
  1169. X**    a qualifier, a positional paramater, or the End-of-Tokens symbol).
  1170. X**
  1171. X** ^REQUIREMENTS:
  1172. X**    Assume dcl_strxlat(str) has already been performed.
  1173. X**
  1174. X** ^SIDE-EFFECTS:
  1175. X**    <str> is modified in much the same manner as it would have 
  1176. X**    been modified if it were passed as the vector_string to strsplit().
  1177. X**
  1178. X** ^RETURN-VALUE:
  1179. X**    A vector of dcl_tokens.
  1180. X**
  1181. X** ^ALGORITHM:
  1182. X**    - first count the number of tokens and also try to interpret stuff
  1183. X**      like  "parm1.1/qual1,parm1.2" by replacing the comma with a space.
  1184. X**    - allocate space for the vector of DCL tokens.
  1185. X**    - assign the approriate value and type for each token.
  1186. X**
  1187. X** ^CAVEATS:
  1188. X**    Does not treate "/qual=(val1,val2/str,..)" as illegal
  1189. X**        ( parses it as if it were "/qual=(val1,val2)/str" )
  1190. X**
  1191. X**    Replaces "parm1.1/qual,parm1.2" with "parm1.1/qual parm1.2"
  1192. X**        which works only because parseargs requires a VMS
  1193. X**        positional list to be comma OR whitespace separated
  1194. X**        (not just comma separated).
  1195. X***^^**********************************************************************/
  1196. X#ifdef __ANSI_C__
  1197. X   static dcl_token_t  *dcl_split( char *str )
  1198. X#endif
  1199. X{
  1200. X   int tokc = 1;  /* number of tokens */
  1201. X   dcl_token_t *tokv = (dcl_token_t *)NULL;  /* vector of tokens */
  1202. X   register char *pread, c;
  1203. X   register int i;
  1204. X
  1205. X   if ( !str  ||  !(*str) )  return  (dcl_token_t *)NULL;
  1206. X
  1207. X    /* 1st pass (left-to-right) : count tokens */
  1208. X   pread = ( *str == c_QUAL ) ? (str + 1) : str;
  1209. X   while ( c = *pread++ ) {
  1210. X      if ( c == c_QUAL  ||  c == c_SPACE )  ++tokc;
  1211. X      if ( c == c_QUAL ) {
  1212. X           /* replace "p1.1/qual,p1.2" with "p1.1/qual p1.2" */
  1213. X        char *p, delims[5];
  1214. X
  1215. X        sprintf( delims, "%c%c%c%c", c_EQUAL, c_PLUS, c_QUAL, c_SPACE );
  1216. X        if ( (p = strpbrk((str + 1), delims))  &&
  1217. X             ((*p == c_PLUS) || (*p == c_COMMA)) )
  1218. X           *p == c_SPACE;
  1219. X      }
  1220. X   }
  1221. X
  1222. X
  1223. X    /* allocate vector */
  1224. X   tokv = (dcl_token_t *)malloc( (tokc + 1) * sizeof(dcl_token_t) );
  1225. X   if ( tokv == (dcl_token_t *)NULL ) {
  1226. X      syserr( "malloc() failed in dcl_split()" );
  1227. X   }
  1228. X   tokv[ tokc ].type = EndOfLine;
  1229. X   tokv[ tokc ].token = CHARNULL;
  1230. X
  1231. X    /* 2nd pass (right-to-left) : assign tokens to strings */
  1232. X   for ( i = 1, --pread ; pread >= str ; pread-- ) {
  1233. X      if ( *pread == c_SPACE  ||  *pread == c_QUAL ) {
  1234. X         tokv[ tokc - i ].token = pread + 1;
  1235. X         tokv[ tokc - i ].type = ( *pread == c_QUAL ) ? Qualifier : Parameter;
  1236. X         *pread = '\0';
  1237. X         ++i;
  1238. X      }
  1239. X   }
  1240. X
  1241. X   if ( *str ) {  /* then 1st char could NOT have been '/' */
  1242. X     tokv -> token = str;
  1243. X     tokv -> type  = Parameter;
  1244. X   }
  1245. X
  1246. X   return  tokv;
  1247. X}
  1248. X
  1249. X
  1250. X/***************************************************************************
  1251. X** ^FUNCTION: dcl_restore - restore the `escaped' characters in a token
  1252. X**
  1253. X** ^SYNOPSIS:
  1254. X*/
  1255. X#ifndef __ANSI_C__
  1256. X   static char *dcl_restore( tokstr )
  1257. X/*
  1258. X** ^PARAMETERS:
  1259. X*/
  1260. X   char *tokstr;
  1261. X/*    -- the token string to restore
  1262. X*/
  1263. X#endif  /* !__ANSI_C__ */
  1264. X
  1265. X/* ^DESCRIPTION:
  1266. X**    Dcl_restore will attempt to restore any DCL special characters (such as
  1267. X**    '/' and '=') that may have been escaped by dcl_strxlat().
  1268. X**
  1269. X** ^REQUIREMENTS:
  1270. X**    tokstr should be non-null and non-empty
  1271. X**
  1272. X** ^SIDE-EFFECTS:
  1273. X**    Any escape characters (such as c_QUAL) are restored to their ascii
  1274. X**    representation.
  1275. X**
  1276. X** ^RETURN-VALUE:
  1277. X**    The address of the restored string
  1278. X**
  1279. X** ^ALGORITHM:
  1280. X**    - for each character in tokstr
  1281. X**      - if it is special then replace it with its ascii code
  1282. X**        end-if
  1283. X**      end-for
  1284. X**
  1285. X** ^CAVEATS:
  1286. X**    The string is not restored to way it was before it was processed by
  1287. X**    dcl_strxlat(). Any characters that were removed are still missing.
  1288. X***^^**********************************************************************/
  1289. X#ifdef __ANSI_C__
  1290. X   static char *dcl_restore( char *tokstr )
  1291. X#endif
  1292. X{
  1293. X   register  char *str = tokstr;
  1294. X
  1295. X   if ( !str || !*str )  return  str;
  1296. X
  1297. X   for ( ; *str ; str++ ) {
  1298. X      switch( *str ) {
  1299. X         case c_SPACE  : *str = ' '; break;
  1300. X         case c_QUAL   : *str = '/'; break;
  1301. X         case c_EQUAL  : *str = '='; break;
  1302. X         case c_COLON  : *str = ':'; break;
  1303. X         case c_PLUS   : *str = '+'; break;
  1304. X         case c_COMMA  : *str = ','; break;
  1305. X         default : break;
  1306. X      }
  1307. X   }
  1308. X
  1309. X   return  tokstr;
  1310. X}
  1311. X
  1312. X
  1313. X
  1314. X
  1315. X/***************************************************************************
  1316. X** ^FUNCTION: split_list - function to handle ARGLISTs and ARGVECs
  1317. X**
  1318. X** ^SYNOPSIS:
  1319. X*/
  1320. X#ifndef __ANSI_C__
  1321. X   static BOOL split_list( ad, vp, cmd )
  1322. X/*
  1323. X** ^PARAMETERS:
  1324. X*/
  1325. X   ARGDESC *ad;
  1326. X/*    -- the argument which takes multiple values
  1327. X*/
  1328. X   char *vp;
  1329. X/*    -- the string of values for the argument
  1330. X*/
  1331. X   ARGDESC *cmd;
  1332. X/*    -- the command to which the argument belongs
  1333. X*/
  1334. X#endif  /* !__ANSI_C__ */
  1335. X
  1336. X/* ^DESCRIPTION:
  1337. X**    Split_list will split the string containing the set of values into
  1338. X**    a set of tokens and will then attempt to convert each token (in the
  1339. X**    order given) using the ad_type function of the argument structure.
  1340. X**
  1341. X** ^REQUIREMENTS:
  1342. X**    <vp> must already be preprocessed by dcl_strxlat to escape any quoted
  1343. X**    characters and to map special characters to their corresponding values.
  1344. X**
  1345. X** ^SIDE-EFFECTS:
  1346. X**    Ad has some of its flags modified as well as any modifications that
  1347. X**    are made by the ad_type function.
  1348. X**
  1349. X**    <vp> is modified by strsplit().
  1350. X**
  1351. X** ^RETURN-VALUE:
  1352. X**    TRUE if all is hunky-dory; FALSE otherwise
  1353. X**
  1354. X** ^ALGORITHM:
  1355. X**    - Split vp into a vector of tokens
  1356. X**    - foreach token
  1357. X**      - call ad_type(ad, token, copyf)
  1358. X**      end-if
  1359. X**    - set the ARGGIVEN and ARGVALGIVEN flags accordingly
  1360. X***^^**********************************************************************/
  1361. X#ifdef __ANSI_C__
  1362. X   static BOOL  split_list( ARGDESC *ad, char *vp, ARGDESC *cmd )
  1363. X#endif
  1364. X{
  1365. X   char **arg_vec = (char **)NULL;
  1366. X   int  i, arg_num = 0;
  1367. X   BOOL err = FALSE;
  1368. X   char delims[3];
  1369. X
  1370. X      /* set-up delimiter string */
  1371. X   *delims = c_PLUS;
  1372. X   *(delims + 1) = c_COMMA;
  1373. X   *(delims + 2) = '\0';
  1374. X
  1375. X      /* break string up into to tokens and handle each one */
  1376. X   arg_num = strsplit( &arg_vec, vp, delims );
  1377. X   for ( i = 0 ; i < arg_num ; i++ ) {
  1378. X      vp = arg_vec[i];
  1379. X
  1380. X         /* try to convert the type */
  1381. X      if ( !HANDLE(ad, dcl_restore(vp), cmd_flags(cmd)) )  err = TRUE;
  1382. X   }
  1383. X   if ( !err )  BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
  1384. X
  1385. X   if ( ARG_isPOSITIONAL(ad) ) {
  1386. X      cmd_list(cmd) = ad;
  1387. X   }
  1388. X   else {
  1389. X      cmd_list(cmd) = ARGDESCNULL;
  1390. X   }
  1391. X
  1392. X   free( arg_vec );
  1393. X
  1394. X   return  !err;
  1395. X}
  1396. X
  1397. X
  1398. X/***************************************************************************
  1399. X** ^FUNCTION: vms_parse - parse VMS/DCL arg-vectors
  1400. X**
  1401. X** ^SYNOPSIS:
  1402. X*/
  1403. X#ifndef __ANSI_C__
  1404. X   int vms_parse( argv, argd )
  1405. X/*
  1406. X** ^PARAMETERS:
  1407. X*/
  1408. X   char *argv[];
  1409. X/*    -- the vector of string arguments from the command-line
  1410. X*/
  1411. X   ARGDESC argd[];
  1412. X/*    -- the programmer description of the command and its args
  1413. X*/
  1414. X#endif  /* !__ANSI_C__ */
  1415. X
  1416. X/* ^DESCRIPTION:
  1417. X**    Vms_parse will parse the arguments in the given vector of strings,
  1418. X**    assign the corresponding values to the command-line arguments specified
  1419. X**    in argd, and check the syntax of the command-line.
  1420. X**
  1421. X** ^REQUIREMENTS:
  1422. X**    The final element in argv must be a NULL pointer.
  1423. X**
  1424. X** ^SIDE-EFFECTS:
  1425. X**    argd is modified according to the command-line description and parameters
  1426. X**
  1427. X** ^RETURN-VALUE:
  1428. X**    pe_SUCCESS (0) if no errors are encountered
  1429. X**    pe_SYSTEM (-1) if a system error is encountered
  1430. X**    pe_SYNTAX if a syntax error is encountered
  1431. X**
  1432. X** ^ALGORITHM:
  1433. X**    - compare argv to the command-line (use the command-line if equal)
  1434. X**    - put argv back into a single string and translate it using dcl_strxlat
  1435. X**    - reparse the string into DCL tokens using dcl_strsplit
  1436. X**    - for each DCL token
  1437. X**       - attempt to match the token as a qualifier
  1438. X**       - if it is a qualifier
  1439. X**          - record and convert its value (if any)
  1440. X**       - else it is a positional parameter
  1441. X**          - record and convert its value (if any)
  1442. X**       - else there are too many arguments
  1443. X**          - return pe_SYNTAX
  1444. X**         end-if
  1445. X**       end-for
  1446. X***^^**********************************************************************/
  1447. X#ifdef __ANSI_C__
  1448. X   int  vms_parse( char *argv[], ARGDESC argd[] )
  1449. X#endif
  1450. X{
  1451. X   register ARGDESC *ad, *args, *cmd;
  1452. X   register char *p;
  1453. X   char *avstr;
  1454. X   BOOL  is_match = FALSE;
  1455. X   int  parse_error = pe_SUCCESS;
  1456. X   dcl_token_t  *tok, *tokvec;
  1457. X   argName_t  keyword;
  1458. X   argMask_t  saveflags, flags;
  1459. X
  1460. X   if ( !argd )  return  parse_error;
  1461. X
  1462. X      /* initialize command-structure */
  1463. X   if ( !CMD_isINIT(argd) )  init_args( argd );
  1464. X   cmd = argd;
  1465. X   saveflags = cmd_flags(cmd);
  1466. X
  1467. X   if ( !argv || !*argv )  return  parse_error;
  1468. X
  1469. X   if ( !BTEST(cmd_state(cmd), ps_NOTCMDLINE) ) {
  1470. X      (VOID) is_cmdline( (CONST char **)argv, &avstr );
  1471. X   }
  1472. X   else {
  1473. X      avstr = strjoin( argv, " " );
  1474. X   }
  1475. X
  1476. X   BSET( cmd_flags(cmd), pa_COPYF );
  1477. X   (VOID) dcl_strxlat( avstr );
  1478. X   if ( !avstr || !*avstr )  return  parse_error;
  1479. X   tokvec = dcl_split( avstr );
  1480. X
  1481. X      /* run through the token vector */
  1482. X   for ( tok = tokvec ; (p = tok -> token) ; tok++ ) {
  1483. X
  1484. X      if ( tok -> type == Qualifier  &&  !BTEST(cmd_state(cmd), ps_NOFLAGS) ) {
  1485. X         char c = '\0', *s, delims[3];
  1486. X
  1487. X            /* set-up delimiter string */
  1488. X         *delims = c_EQUAL;
  1489. X         *(delims + 1) = c_COLON;
  1490. X         *(delims + 2) = '\0';
  1491. X
  1492. X            /* skip past qualifier prefix and look for possible argument */
  1493. X         s  = strpbrk(p, delims);
  1494. X         if (s) {
  1495. X            c = *s;
  1496. X            *s++ = '\0';
  1497. X         }
  1498. X
  1499. X         is_match = FALSE;
  1500. X         for ( args = argd ; args && !is_match ; args = cmd_defargs(args) ) {
  1501. X            for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
  1502. X               if (arg_type(ad) == argDummy)  continue;
  1503. X
  1504. X               if (!ARG_isPOSONLY(ad)  &&  match(p, arg_sname(ad)) == 0) {
  1505. X                  is_match = TRUE;
  1506. X                  break;
  1507. X               }/*if*/
  1508. X            }
  1509. X         }
  1510. X
  1511. X         if (c)  *(s-1) = c;  /* restore the equal sign */
  1512. X
  1513. X         if ( !is_match ) {
  1514. X            if (s)  *(s-1) = '\0';
  1515. X            usrerr( "undefined qualifier %s", s_KWD_PFX, p );
  1516. X            if (s)  *(s-1) = c;
  1517. X            parse_error = pe_SYNTAX;
  1518. X            continue;
  1519. X         }
  1520. X
  1521. X            /* end-qualifiers */
  1522. X         if ( arg_type(ad) == argEnd ) {
  1523. X            BSET( cmd_state(cmd), ps_NOFLAGS );
  1524. X            continue;
  1525. X         }
  1526. X            /* if usage - just print usage and exit */
  1527. X         if ( arg_type(ad) == argUsage ) {
  1528. X            Usage_Requested = TRUE;
  1529. X            usage( argd );
  1530. X            free( avstr );
  1531. X            if ( tokvec )  free( tokvec );
  1532. X            cmd_flags(cmd) = saveflags;
  1533. X            exit(exit_USAGE);
  1534. X         }
  1535. X         /* reset the argument flags - if this arg was already given, some
  1536. X         ** of its flags may be set to indicate how it was given before.
  1537. X         ** we need to know how it was given now (but save the old ones
  1538. X         ** just in case the new one fails).
  1539. X         */
  1540. X         flags = arg_flags(ad);
  1541. X         if ( ARG_isGIVEN(ad) ) {
  1542. X            BCLEAR( arg_flags(ad), ARGVALSEP );
  1543. X            if ( !ARG_isMULTIVAL(ad) )  BCLEAR( arg_flags(ad), ARGVALGIVEN );
  1544. X         }
  1545. X
  1546. X            /* ARGNOVALs are special, having no value */
  1547. X         if ( ! ARG_isVALTAKEN(ad) ) {
  1548. X            if ( !HANDLE(ad, dcl_restore(s), cmd_flags(cmd)) ) {
  1549. X               arg_flags(ad) = flags;
  1550. X               parse_error = pe_SYNTAX;
  1551. X            }
  1552. X            else {
  1553. X               BSET( arg_flags(ad), ARGGIVEN );
  1554. X               ad = ARGDESCNULL;
  1555. X            }
  1556. X            continue;
  1557. X         }/*if ARGNOVAL*/
  1558. X
  1559. X            /* now get the real value */
  1560. X         if ( !s || !(*s) ) {
  1561. X            if ( ARG_isVALOPTIONAL(ad) ) {
  1562. X               BSET( arg_flags(ad), ARGGIVEN );
  1563. X            }
  1564. X            else {
  1565. X               (VOID) get_kwdname( arg_sname(ad), keyword );
  1566. X               usrerr("qualifier %s requires an argument", keyword);
  1567. X               arg_flags(ad) = flags;
  1568. X               parse_error = pe_SYNTAX;
  1569. X            }
  1570. X            continue;
  1571. X         }/*if*/
  1572. X
  1573. X         if( ARG_isMULTIVAL(ad) ) {
  1574. X            if( !split_list(ad, s, cmd) ) {
  1575. X               arg_flags(ad) = flags;
  1576. X               parse_error = pe_SYNTAX;
  1577. X            }
  1578. X            else {
  1579. X               BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
  1580. X            }
  1581. X            continue;
  1582. X         }/*if list*/
  1583. X
  1584. X            /* try to convert the type */
  1585. X         if ( !HANDLE(ad, dcl_restore(s), cmd_flags(cmd)) ) {
  1586. X            arg_flags(ad) = flags;
  1587. X            parse_error = pe_SYNTAX;
  1588. X         }
  1589. X         else {
  1590. X            BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
  1591. X         }
  1592. X
  1593. X         continue;
  1594. X      }/*if qual*/
  1595. X      else {
  1596. X            /* parsing a vector of arguments */
  1597. X         if ( cmd_list(cmd) ) {
  1598. X            ad = cmd_list(cmd);
  1599. X            flags = arg_flags(ad);
  1600. X            if ( ARG_isGIVEN(ad) ) {
  1601. X               BCLEAR( arg_flags(ad), ARGVALSEP );
  1602. X            }
  1603. X
  1604. X            BSET( arg_flags(ad), ARGVALSEP );
  1605. X
  1606. X            if( ARG_isMULTIVAL(ad) ) {
  1607. X               if( !split_list(ad, p, cmd) )  parse_error = pe_SYNTAX;
  1608. X            }
  1609. X            else if ( !HANDLE(ad, dcl_restore(p), cmd_flags(cmd)) ) {
  1610. X               arg_flags(ad) = flags;
  1611. X               parse_error = pe_SYNTAX;
  1612. X            }
  1613. X
  1614. X            if ( !parse_error )  BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
  1615. X
  1616. X            continue;
  1617. X         }
  1618. X            /* positional argument */
  1619. X         is_match = FALSE;
  1620. X         for ( args = argd ; args && !is_match ; args = cmd_defargs(args) ) {
  1621. X            for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
  1622. X               if (arg_type(ad) == argDummy)  continue;
  1623. X
  1624. X               if ( ARG_isPOSITIONAL(ad)  &&
  1625. X                    (!ARG_isGIVEN(ad) || ARG_isMULTIVAL(ad)) ) {
  1626. X                  is_match = TRUE;
  1627. X                  break;
  1628. X               }/*if*/
  1629. X            }
  1630. X         }
  1631. X
  1632. X         if ( !is_match ) {
  1633. X            usrerr("too many arguments");
  1634. X            parse_error = pe_SYNTAX;
  1635. X            continue;
  1636. X         }
  1637. X
  1638. X         /* if FLAGS1ST is set then first positional marks end-of-flags */
  1639. X         if ( BTEST(cmd_flags(cmd), pa_FLAGS1ST) ) {
  1640. X            BSET( cmd_state(cmd), ps_NOFLAGS );
  1641. X         }
  1642. X
  1643. X         /* reset the argument flags - if this arg was already given, some
  1644. X         ** of its flags may be set to indicate how it was given before.
  1645. X         ** we need to know how it was given now (but save the old ones
  1646. X         ** just in case the new one fails).
  1647. X         */
  1648. X         flags = arg_flags(ad);
  1649. X         if ( ARG_isGIVEN(ad) ) {
  1650. X            BCLEAR( arg_flags(ad), ARGVALSEP );
  1651. X            if ( !ARG_isMULTIVAL(ad) )  BCLEAR( arg_flags(ad), ARGVALGIVEN );
  1652. X         }
  1653. X
  1654. X         BSET( arg_flags(ad), ARGVALSEP );
  1655. X
  1656. X         if( ARG_isMULTIVAL(ad) ) {
  1657. X            if( !split_list(ad, p, cmd) ) {
  1658. X               arg_flags(ad) = flags;
  1659. X               parse_error = pe_SYNTAX;
  1660. X            }
  1661. X            else {
  1662. X               BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
  1663. X            }
  1664. X            continue;
  1665. X         }/*if list*/
  1666. X
  1667. X            /* try to convert */
  1668. X         if ( !HANDLE(ad, dcl_restore(p), cmd_flags(cmd)) ) {
  1669. X            arg_flags(ad) = flags;
  1670. X            parse_error = TRUE;
  1671. X         }
  1672. X         else {
  1673. X            BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
  1674. X         }
  1675. X
  1676. X      }/*if parameter*/
  1677. X   }/*while*/
  1678. X
  1679. X   free( avstr );
  1680. X   if ( tokvec )  free( tokvec );
  1681. X   cmd_flags(cmd) = saveflags;
  1682. X   return  parse_error;
  1683. X}
  1684. X
  1685. X
  1686. X/***************************************************************************
  1687. X** ^FUNCTION: fmtarg - format command-argument syntax
  1688. X**
  1689. X** ^SYNOPSIS:
  1690. X*/
  1691. X#ifndef __ANSI_C__
  1692. X   static int fmtarg( ad, buf )
  1693. X/*
  1694. X** ^PARAMETERS:
  1695. X*/
  1696. X   ARGDESC *ad;
  1697. X/*    -- pointer to the argument to format
  1698. X*/
  1699. X   char *buf;
  1700. X/*    -- character buffer to hold the formatted result
  1701. X*/
  1702. X#endif  /* !__ANSI_C__ */
  1703. X
  1704. X/* ^DESCRIPTION:
  1705. X**    Fmtarg will determine the proper command-line syntax for the
  1706. X**    given argument and write the result to the given buffer.
  1707. X**
  1708. X** ^REQUIREMENTS:
  1709. X**    buf must be large enough to hold the formatted result (100 characters
  1710. X**    should do the trick).
  1711. X**
  1712. X** ^SIDE-EFFECTS:
  1713. X**    buf is overwritten.
  1714. X**
  1715. X** ^RETURN-VALUE:
  1716. X**    The number of printable characters in the argument-syntax-string
  1717. X**
  1718. X** ^ALGORITHM:
  1719. X**    Print argument usage based on whether or not the argument is
  1720. X**    positional, hidden, multi-valued (list or vector), etc ....
  1721. X**    Optional arguments and values are enclosed in square braces.
  1722. X***^^**********************************************************************/
  1723. X#ifdef __ANSI_C__
  1724. X   static int fmtarg( const ARGDESC *ad, char *buf )
  1725. X#endif
  1726. X{
  1727. X   /* buf must already be large enough */
  1728. X   char * pos;
  1729. X   argName_t  keyword, name;
  1730. X
  1731. X   (VOID) get_argname( arg_sname(ad), name );
  1732. X
  1733. X   if (ARG_isPOSITIONAL(ad)) {
  1734. X      sprintf( buf, "<%s>", name );
  1735. X   }
  1736. X   else {
  1737. X      (VOID) get_kwdname( arg_sname(ad), keyword );
  1738. X      sprintf( buf, "%c%s", *s_KWD_PFX, keyword );
  1739. X      pos = buf + strlen(buf);
  1740. X
  1741. X      if ( ARG_isVALTAKEN(ad) && !ARG_isBOOLEAN(ad) && !ARG_isPSEUDOARG(ad) ) {
  1742. X         if  ( ARG_isVALOPTIONAL(ad)) {
  1743. X            sprintf( pos, "[%c<%s>]", *s_ARG_SEP, name );
  1744. X         }
  1745. X         else {
  1746. X            sprintf( pos, "%c<%s>", *s_ARG_SEP, name );
  1747. X         }
  1748. X      }/*if*/
  1749. X   }/*else*/
  1750. X
  1751. X   return  (int) strlen(buf);
  1752. X}
  1753. X
  1754. X
  1755. X/***************************************************************************
  1756. X** ^FUNCTION: vms_usage - print a usage message
  1757. X**
  1758. X** ^SYNOPSIS:
  1759. X*/
  1760. X#ifndef __ANSI_C__
  1761. X   VOID vms_usage( argd, usage_flags )
  1762. X/*
  1763. X** ^PARAMETERS:
  1764. X*/
  1765. X   ARGDESC *argd;
  1766. X/*    -- the command-descriptor array
  1767. X*/
  1768. X   argMask_t usage_flags;
  1769. X/*    -- flags set by $USAGECNTL
  1770. X*/
  1771. X#endif  /* !__ANSI_C__ */
  1772. X
  1773. X/* ^DESCRIPTION:
  1774. X**    Vms_usage will print the VMS/DCL command-line usage of the given
  1775. X**    command on standard diagnostic output (stderr). The content of the
  1776. X**    usage message is controlled by the bitmasks in usage_flags which
  1777. X**    correspond to the settings in the user's USAGECNTL symbol.
  1778. X**
  1779. X** ^REQUIREMENTS:
  1780. X**    argd should be a non-null command-line argument-descriptor array
  1781. X**
  1782. X** ^SIDE-EFFECTS:
  1783. X**    Prints on stderr.
  1784. X**
  1785. X** ^RETURN-VALUE:
  1786. X**    None.
  1787. X**
  1788. X** ^ALGORITHM:
  1789. X**    - if no usage is desired then exit
  1790. X**    - if paging is requested print to the pager instead of stderr
  1791. X**    - print the command-line syntax
  1792. X**    - if the description is requested print it
  1793. X**    - if verbose mode is requested, print the description of each argument
  1794. X***^^**********************************************************************/
  1795. X#ifdef __ANSI_C__
  1796. X   void vms_usage( const ARGDESC *argd, argMask_t usage_flags )
  1797. X#endif
  1798. X{
  1799. X   register CONST ARGDESC  *ad, *args, *cmd;
  1800. X   int  max_cols = 80, max_lines  = 24;
  1801. X   int  margin, ll, pl, qualifiers, longest, positionals;
  1802. X   BOOL first = TRUE;
  1803. X   FILE *fp;
  1804. X
  1805. X   if ( !argd )  return;
  1806. X
  1807. X      /* initialize command-structure */
  1808. X   if ( !CMD_isINIT(argd) )  init_args( (ARGDESC *)argd );
  1809. X   cmd = argd;
  1810. X
  1811. X      /* get screen size */
  1812. X   get_winsize( fileno(stderr), &max_lines, &max_cols );
  1813. X
  1814. X      /* force verbose-mode if requested */
  1815. X   if ( Usage_Requested )   BSET( usage_flags, usg_VERBOSE );
  1816. X
  1817. X   if ( BTEST(usage_flags, usg_NONE) )  return;
  1818. X
  1819. X   fp = ( BTEST(usage_flags, usg_PAGED) )
  1820. X      ? pgopen( stderr, getenv("USAGE_PAGER") )
  1821. X      : stderr;
  1822. X
  1823. X      /* allow null argument descriptor */
  1824. X   fprintf(fp, "Format: %.*s", ProgNameLen, (ProgName) ? ProgName : "");
  1825. X
  1826. X   ll = ProgNameLen + 8;
  1827. X   margin = ll + 1;
  1828. X   longest = 0;
  1829. X
  1830. X   for ( positionals = 0 ; positionals < 2 ; positionals++ ) {
  1831. X      for ( args = argd ; args ; args = cmd_defargs(args) ) {
  1832. X         for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
  1833. X            argName_t  buf, name;
  1834. X
  1835. X               /* don't display hidden arguments */
  1836. X            if ( ARG_isHIDDEN(ad) )  continue;
  1837. X            if ( !positionals  &&  ARG_isPOSITIONAL(ad) )  continue;
  1838. X            if ( positionals  &&  !ARG_isPOSITIONAL(ad) )  continue;
  1839. X
  1840. X               /* figure out how wide this parameter is (for printing) */
  1841. X            pl = fmtarg(ad, buf);
  1842. X
  1843. X            if ( pl > longest )  longest = pl;
  1844. X
  1845. X
  1846. X            if ( ARG_isMULTIVAL(ad) ) {
  1847. X               (VOID) get_argname( arg_sname(ad), name );
  1848. X               strcat(buf, "[,<");
  1849. X               strcat(buf, name);
  1850. X               strcat(buf, ">...]");
  1851. X               pl += 8 + strlen(name);
  1852. X            }
  1853. X            if ( !ARG_isREQUIRED(ad) ) {
  1854. X               pl += 2;  /* [] */
  1855. X            }
  1856. X
  1857. X            /* see if this will fit */
  1858. X            if ( (ll + pl + 1) > (max_cols - first) ) {
  1859. X                  /* no... start a new line */
  1860. X               fprintf(fp, "\n%*s", margin, "");
  1861. X               ll = margin;
  1862. X            }
  1863. X            else {
  1864. X                  /* yes... just throw in a space */
  1865. X               fputc(' ', fp);
  1866. X               ++ll;
  1867. X            }
  1868. X            ll += pl;
  1869. X
  1870. X                /* show the argument */
  1871. X            if ( !ARG_isREQUIRED(ad) )  fputc('[', fp);
  1872. X            fprintf(fp, buf);
  1873. X            if ( !ARG_isREQUIRED(ad) )  fputc(']', fp);
  1874. X
  1875. X            first = FALSE;  /* not first line anymore */
  1876. X         }/*for each ad */
  1877. X      }/* for each argd */
  1878. X   }/* for each parm-type */
  1879. X
  1880. X   fputc('\n', fp);
  1881. X
  1882. X   if ( BTEST(usage_flags, usg_DESCRIPTION) ) {
  1883. X      CONST char *description = cmd_description(cmd);
  1884. X
  1885. X      if ( description  &&  *description ) {
  1886. X         fprintf( fp, "Description:\n" );
  1887. X         indent_para(fp, max_cols, 8, "", 0, description, 0);
  1888. X         fputc( '\n', fp );
  1889. X      }
  1890. X   }/*if*/
  1891. X
  1892. X   if ( !BTEST(usage_flags, usg_VERBOSE) )  {
  1893. X      if ( pgactive(fp) )  (VOID) pgclose( fp );
  1894. X      return;
  1895. X   }
  1896. X
  1897. X   qualifiers = 0;
  1898. X   for ( positionals = 0 ; positionals < 2 ; positionals++ ) {
  1899. X      for ( args = argd ; args ; args = cmd_defargs(args) ) {
  1900. X         for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
  1901. X            argName_t  buf;
  1902. X        char  *desc;
  1903. X        int  desclen;
  1904. X
  1905. X               /* don't display hidden arguments */
  1906. X            if ( ARG_isHIDDEN(ad) )  continue;
  1907. X            if ( !positionals  &&  ARG_isPOSITIONAL(ad) )  continue;
  1908. X            if ( positionals  &&  !ARG_isPOSITIONAL(ad) )  continue;
  1909. X
  1910. X            if ( !qualifiers++ )  fprintf(fp, "Qualifiers/Parameters:\n");
  1911. X            (VOID) fmtarg(ad, buf);
  1912. X        desc = get_argdesc(arg_description(ad), &desclen);
  1913. X            indent_para(fp, max_cols, 8, buf, longest+2, desc, desclen );
  1914. X         }/*for each ad */
  1915. X      }/* for each argd */
  1916. X   }/* for each parm-type */
  1917. X
  1918. X   if ( pgactive(fp) )  (VOID) pgclose( fp );
  1919. X}
  1920. X
  1921. END_OF_FILE
  1922. if test 32340 -ne `wc -c <'vms_args.c'`; then
  1923.     echo shar: \"'vms_args.c'\" unpacked with wrong size!
  1924. fi
  1925. # end of 'vms_args.c'
  1926. fi
  1927. echo shar: End of archive 6 \(of 10\).
  1928. cp /dev/null ark6isdone
  1929. MISSING=""
  1930. for I in 1 2 3 4 5 6 7 8 9 10 ; do
  1931.     if test ! -f ark${I}isdone ; then
  1932.     MISSING="${MISSING} ${I}"
  1933.     fi
  1934. done
  1935. if test "${MISSING}" = "" ; then
  1936.     echo You have unpacked all 10 archives.
  1937.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1938. else
  1939.     echo You still need to unpack the following archives:
  1940.     echo "        " ${MISSING}
  1941. fi
  1942. ##  End of shell archive.
  1943. exit 0
  1944.  
  1945. exit 0 # Just in case...
  1946.