home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume29 / parseargs / part06 / ibm_args.c next >
C/C++ Source or Header  |  1992-05-19  |  26KB  |  804 lines

  1. /*************************************************************************
  2. ** ^FILE: ibm_args.c - parse MS-DOS and OS/2 argument vectors
  3. **
  4. ** ^DESCRIPTION:
  5. **    This file contains the routines used to parse MS-DOS and OS/2
  6. **    argument vectors and to print MS-DOS and OS/2 usage messages.
  7. **
  8. ** ^HISTORY:
  9. **    27/08/91     Earl Chew     <cechew@bruce.cs.monash.edu.au>
  10. **    - Use ProgNameLen when accessing ProgName
  11. **    - Use get_argdesc() to access description
  12. **
  13. **    01/02/91     Brad Appleton     <brad@ssd.csd.harris.com>    Created
  14. ***^^**********************************************************************/
  15.  
  16. #include <ctype.h>
  17. #include <useful.h>
  18. #include "strfuncs.h"
  19. #include "pgopen.h"
  20. #include "exit_codes.h"
  21.  
  22. #define PARSEARGS_PRIVATE   /* include private definitions */
  23. #include "parseargs.h"
  24.  
  25. EXTERN  VOID  syserr       ARGS((const char *, ...));
  26. EXTERN  VOID  usrerr       ARGS((const char *, ...));
  27. EXTERN  char *getenv       ARGS((const char *));
  28. EXTERN  VOID  get_winsize  ARGS((int, int *, int *));
  29.  
  30. VERSIONID("$Header: parseargs.c,v 2.1 89/12/30 20:59:48 eric Exp $");
  31.  
  32. /***************************************************************************
  33. ** ^GLOBAL-VARIABLE: OptPrefix, KwdPrefix
  34. **
  35. ** ^VISIBILITY:
  36. **    static-global (visible to all functions in this file).
  37. **
  38. ** ^DESCRIPTION:
  39. **    OptPrefix contains the single character prefix used to precede
  40. **    an option switch on the command-line.
  41. **
  42. **    KwdPrefix contains the single character prefix used to precede
  43. **    a keyword switch on the command-line.
  44. ***^^**********************************************************************/
  45. static  char  OptPrefix='/';
  46. static  char  KwdPrefix='/';
  47.  
  48. #define  isUNIXISH  ( OptPrefix == '-' )
  49.  
  50.  
  51. /***************************************************************************
  52. ** ^GLOBAL-VARIABLE: Usage_Requested
  53. **
  54. ** ^VISIBILITY:
  55. **    static-global (visible to all functions in this file).
  56. **
  57. ** ^DESCRIPTION:
  58. **    Indicates whether a usage message was requested by the user
  59. **    (as opposed to triggerred by a syntax error).  If the message
  60. **    is requested by the user then it is always printed in verbose
  61. **    mode and does not return an error-status-code.
  62. ***^^**********************************************************************/
  63. static  BOOL  Usage_Requested = FALSE;
  64.  
  65.  
  66.    /* macros to detect an option/keyword -- watch out for side effects!! */
  67. #define isOPT(s)  \
  68.    ( !BTEST(cmd_flags(cmd), pa_KWDSONLY)  && \
  69.      !BTEST(cmd_state(cmd), ps_NOFLAGS)  && \
  70.      *s == OptPrefix  &&  *(s+1) \
  71.    )
  72.  
  73. #define isKWD(s)  \
  74.    ( !BTEST(cmd_flags(cmd), pa_OPTSONLY)  && \
  75.      !BTEST(cmd_state(cmd), ps_NOFLAGS)  && \
  76.      *s == KwdPrefix  &&  *(s+1) \
  77.    )
  78.  
  79.  
  80. /***************************************************************************
  81. ** ^FUNCTION: get_prefixes - determine short and long keyword prefixes
  82. **
  83. ** ^SYNOPSIS:
  84. */
  85. #ifndef __ANSI_C__
  86.    static VOID get_prefixes()
  87. #endif
  88. /*  
  89. ** ^PARAMETERS:
  90. **    None.
  91. **
  92. ** ^DESCRIPTION:
  93. **    Get_prefixes will determine the prefixes to used to denote option
  94. **    switches and keyword switches on the command-line.  The prefixes
  95. **    are determined by the $SWITCHAR environment varaible. The first
  96. **    character of the variable is the option-switch prefix and the second
  97. **    character is the keyword-switch prefix.
  98. **
  99. **    If The option-switch prefix is '-' then Unix-style command-line parsing
  100. **    is performed, otherwise MS-DOS style command-line parsing is used.
  101. **
  102. ** ^REQUIREMENTS:
  103. **    None.
  104. **
  105. ** ^SIDE-EFFECTS:
  106. **    Sets the global variables "OptPrefix" and "KwdPrefix'.
  107. **
  108. ** ^RETURN-VALUE:
  109. **    None.
  110. **
  111. ** ^ALGORITHM:
  112. **    - If $SWITCHAR is NULL or empty
  113. **      - use the defaults ('/' and '/').
  114. **    - Else
  115. **      - set the OptPrefix to the first character in SWITCHAR
  116. **      End-if
  117. **
  118. **    - If there is a second character in SWITCHAR
  119. **      - assign it to KwdPrefix
  120. **    - Else if OptPrefix is '-'
  121. **      - then use '+' as the default KwdPrefix
  122. **    - Else
  123. **      - use '/' as the default KwdPrefix
  124. **      End-if
  125. ***^^**********************************************************************/
  126. #ifdef __ANSI_C__
  127.    static VOID  get_prefixes( void )
  128. #endif
  129. {
  130.    char *prefixes = getenv( "SWITCHAR" );
  131.  
  132.    if ( prefixes &&  *prefixes ) {
  133.       OptPrefix = *prefixes;
  134.       KwdPrefix = *(prefixes + 1);
  135.       if ( !KwdPrefix )  KwdPrefix = (( OptPrefix == '-' ) ? '+' : '/');
  136.    }
  137.    else {
  138.       OptPrefix = '/';
  139.       KwdPrefix = '/';
  140.    }
  141. }
  142.  
  143.  
  144. /***************************************************************************
  145. ** ^FUNCTION: ibm_parse - parse MS-DOS and OS/2 arg-vectors
  146. **
  147. ** ^SYNOPSIS:
  148. */
  149. #ifndef __ANSI_C__
  150.    int ibm_parse( argv, argd )
  151. /*
  152. ** ^PARAMETERS:
  153. */
  154.    char *argv[];
  155. /*    -- the vector of string arguments from the command-line
  156. */
  157.    ARGDESC argd[];
  158. /*    -- the programmer description of the command and its args
  159. */
  160. #endif  /* !__ANSI_C__ */
  161.   
  162. /* ^DESCRIPTION:
  163. **    Ibm_parse will parse the arguments in the given vector of strings,
  164. **    assign the corresponding values to the command-line arguments specified
  165. **    in argd, and check the syntax of the command-line.
  166. **
  167. ** ^REQUIREMENTS:
  168. **    The final element in argv must be a NULL pointer.
  169. **
  170. ** ^SIDE-EFFECTS:
  171. **    argd is modified according to the command-line description and parameters
  172. **
  173. ** ^RETURN-VALUE:
  174. **    pe_SUCCESS (0) if no errors are encountered
  175. **    pe_SYSTEM (-1) if a system error is encountered
  176. **    pe_SYNTAX if a syntax error is encountered
  177. **
  178. ** ^ALGORITHM:
  179. **    - get the active option and keyword prefixes
  180. **    - determine whether to use Unix style or not (based on the prefixes)
  181. **    - for each command-line argument
  182. **       - attempt to match the argument as a keyword
  183. **       - if it is a keyword argument
  184. **          - record and convert its value (if any)
  185. **         else attempt to match the argument as an option
  186. **         if it is an option
  187. **          - record and convert its value (if any)
  188. **         else it is a positional parameter
  189. **          - record and convert its value (if any)
  190. **         else there are too many arguments
  191. **          - return pe_SYNTAX
  192. **         end-if
  193. **       end-for
  194. ***^^**********************************************************************/
  195. #ifdef __ANSI_C__
  196.    int ibm_parse( char *argv[], ARGDESC argd[] )
  197. #endif
  198. {
  199.    register ARGDESC *ad, *args, *cmd;
  200.    register char **av = argv;
  201.    register char *p;
  202.    argName_t  name;
  203.    argMask_t  flags;
  204.    int  parse_error = pe_SUCCESS;
  205.    BOOL  ad_okay, is_match = FALSE;
  206.  
  207.    if ( !argd )  return  parse_error;
  208.  
  209.       /* initialize command-structure */
  210.    if ( !CMD_isINIT(argd) )  init_args( argd );
  211.    cmd = argd;
  212.  
  213.    get_prefixes();
  214.  
  215.    while ( av  &&  (p = *av++) ) {
  216.       /* is this a keyword */
  217.       if ( isKWD(p) &&
  218.           ( (OptPrefix != KwdPrefix) || *(p+2) && !strchr(s_ARG_SEP, *(p+2)) )
  219.          ) {
  220.          char *s, c = '\0';
  221.  
  222.          /* check for `++' to end flags */
  223.          if ( *(p+1) == KwdPrefix  &&  !*(p+2) ) {
  224.             BSET( cmd_state(cmd), ps_NOFLAGS );
  225.             cmd_list(cmd) = ARGDESCNULL;
  226.             continue;
  227.          }
  228.  
  229.             /* get past prefix and look for possible argument */
  230.          s = strpbrk(++p, s_ARG_SEP);
  231.          if(s) {
  232.             c = *s;
  233.             *s++ = '\0';
  234.          }
  235.  
  236.          is_match = FALSE;
  237.          for ( args = argd ; args  &&  !is_match ; args = cmd_defargs(args) ) {
  238.             for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
  239.                if ( arg_type(ad) == argDummy )  continue;
  240.  
  241.                if ( !ARG_isPOSONLY(ad)  &&  match(p, arg_sname(ad)) == 0 ) {
  242.                   is_match = TRUE;
  243.                   break;
  244.                }/*if*/
  245.             }
  246.          }
  247.  
  248.          if ( c )  *(s-1) = c;  /* restore the equal sign */
  249.  
  250.          if ( !is_match ) {
  251.             if ( OptPrefix == KwdPrefix ) {
  252.                goto  MATCHOPT;  /* maybe its an option (and NOT a keyword) */
  253.             }
  254.             usrerr("%c%s switch unknown", KwdPrefix, p);
  255.             parse_error = pe_SYNTAX;
  256.             cmd_list(cmd) = ARGDESCNULL;
  257.             continue;
  258.          }
  259.  
  260.          /* reset the argument flags - if this arg was already given, some
  261.          ** of its flags may be set to indicate how it was given before.
  262.          ** we need to know how it was given now (but save the old ones
  263.          ** just in case the new one fails).
  264.          */
  265.          flags = arg_flags(ad);
  266.          if ( ARG_isGIVEN(ad) ) {
  267.             BCLEAR( arg_flags(ad), ARGVALSEP | ARGKEYWORD );
  268.             if ( !ARG_isMULTIVAL(ad) )  BCLEAR( arg_flags(ad), ARGVALGIVEN );
  269.          }
  270.  
  271.          BSET( arg_flags(ad), ARGKEYWORD );
  272.  
  273.          if( ARG_isMULTIVAL(ad) ) {
  274.             cmd_list(cmd) = ad;  /* we matched a lst or a vector */
  275.          }
  276.          else {
  277.             cmd_list(cmd) = ARGDESCNULL;
  278.          }
  279.  
  280.             /* if usage - just print usage and exit */
  281.          if ( arg_type(ad) == argUsage ) {
  282.             Usage_Requested = TRUE;
  283.             usage(argd);
  284.             exit(exit_USAGE);
  285.          }
  286.  
  287.             /* ARGNOVALs are special, having no value */
  288.          if ( ! ARG_isVALTAKEN(ad) ) {
  289.             ad_okay = HANDLE(ad, s, cmd_flags(cmd));
  290.             if ( !ad_okay ) {
  291.                arg_flags(ad) = flags;
  292.                parse_error = pe_SYNTAX;
  293.             }
  294.             else {
  295.                BSET( arg_flags(ad), ARGGIVEN );
  296.                ad = ARGDESCNULL;
  297.             }
  298.             continue;
  299.          }/*if ARGNOVAL*/
  300.  
  301.             /* now get the real value */
  302.          if (!s) {
  303.             if ( isUNIXISH )  s = *av++;
  304.             if ( !isUNIXISH  ||  !s  ||  isOPT(s)  ||  isKWD(s) ) {
  305.                if ( ARG_isVALOPTIONAL(ad) ) {
  306.                   BSET( arg_flags(ad), ARGGIVEN );
  307.                }
  308.                else {
  309.                   (VOID) get_kwdname( arg_sname(ad), name );
  310.                   usrerr("%c%s switch requires an argument", KwdPrefix, name);
  311.                   arg_flags(ad) = flags;
  312.                   parse_error = pe_SYNTAX;
  313.                }
  314.  
  315.                if ( isUNIXISH )  av--;
  316.                continue;
  317.             }/*if arg*/
  318.             if ( isUNIXISH )  BSET( arg_flags(ad), ARGVALSEP );
  319.          }/*if empty*/
  320.  
  321.             /* try to convert the type */
  322.          ad_okay = HANDLE(ad, s, cmd_flags(cmd));
  323.          if ( !ad_okay ) {
  324.             arg_flags(ad) = flags;
  325.             parse_error = pe_SYNTAX;
  326.          }
  327.          else {
  328.             BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
  329.          }
  330.  
  331.          continue;
  332.       }/*if keyword*/
  333.       else if ( isOPT(p) ) {
  334.          p++;  /* skip over option prefix */
  335.  
  336. MATCHOPT:
  337.             /* check for `--' to end flags */
  338.          if ( *p == OptPrefix  &&  !*(p+1) ) {
  339.             BSET( cmd_state(cmd), ps_NOFLAGS );
  340.             cmd_list(cmd) = ARGDESCNULL;
  341.             continue;
  342.          }
  343.  
  344.          /* We have a flag argument;
  345.          ** remember that in the case of single character keywords,
  346.          ** the conversion function (ad_type) tells us how many characters
  347.          ** were used. We need that information to decide how many 
  348.          ** characters to skip before the next iteration of the while loop.
  349.          */
  350.          while (*p) {  /* while not end of switch-chars */
  351.  
  352.                /* find the flag in the list */
  353.             is_match = FALSE;
  354.             for (args = argd; args  &&  !is_match ; args = cmd_defargs(args)) {
  355.                for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
  356.                   register char c1 = arg_cname(ad);
  357.                   register char c2 = *p;
  358.  
  359.                   if ( arg_type(ad) == argDummy )   continue;
  360.                   if ( ARG_isPOSONLY(ad) )   continue;
  361.  
  362.                   if ( BTEST(cmd_flags(cmd), pa_ANYCASE) ) {
  363.                      c1 = TOUPPER( c1 );
  364.                      c2 = TOUPPER( c2 );
  365.                   }/*if*/
  366.  
  367.                   if ( c1 == c2 ) {
  368.                      is_match = TRUE;
  369.                      break;
  370.                   }/*if*/
  371.                }
  372.             }
  373.             if ( !is_match ) {
  374.                   usrerr("%c%c switch unknown", OptPrefix, *p++);
  375.                   parse_error = pe_SYNTAX;
  376.                   cmd_list(cmd) = ARGDESCNULL;
  377.                   if ( !isUNIXISH  &&  *p == *s_ARG_SEP )  p += strlen(p);
  378.                   if ( !isUNIXISH  &&  *p == OptPrefix )  ++p;
  379.                   continue;
  380.             }/* if unknown-option */
  381.  
  382.             /* reset the argument flags - if this arg was already given, some
  383.             ** of its flags may be set to indicate how it was given before.
  384.             ** we need to know how it was given now (but save the old ones
  385.             ** just in case the new one fails).
  386.             */
  387.             flags = arg_flags(ad);
  388.             if ( ARG_isGIVEN(ad) ) {
  389.                BCLEAR( arg_flags(ad), ARGVALSEP | ARGKEYWORD );
  390.                if ( !ARG_isMULTIVAL(ad) )  BCLEAR( arg_flags(ad), ARGVALGIVEN );
  391.             }
  392.  
  393.             if ( ARG_isMULTIVAL(ad) ) {
  394.                cmd_list(cmd) = ad;  /* we matched a list (or a vector) */
  395.             }
  396.             else {
  397.                cmd_list(cmd) = ARGDESCNULL;
  398.             }
  399.  
  400.                /* move p up to point to the (possible) value */
  401.             p++;
  402.             if ( !isUNIXISH  &&  *p  &&  strchr(s_ARG_SEP, *p) )  ++p;
  403.  
  404.             /* if usage - just print usage and exit */
  405.             if (arg_type(ad) == argUsage) {
  406.                Usage_Requested = TRUE;
  407.                usage(argd);
  408.                exit(exit_USAGE);
  409.             }
  410.  
  411.                /* ARGNOVALs are special, having no value */
  412.             if (! ARG_isVALTAKEN(ad)) {
  413.                ad_okay = HANDLE(ad, p, cmd_flags(cmd));
  414.  
  415.                if ( !ad_okay ) {
  416.                   arg_flags(ad) = flags;
  417.                   parse_error = pe_SYNTAX;
  418.                }/*if*/
  419.                else {
  420.                   BSET( arg_flags(ad), ARGGIVEN );
  421.                   ad = ARGDESCNULL;
  422.                   if ( ad_okay < 0 )  p -= ad_okay;
  423.                }/*else*/
  424.  
  425.                if ( !isUNIXISH  &&  *p == OptPrefix )  ++p;
  426.                continue;
  427.             }/*if*/
  428.  
  429.                /* now get the real value */
  430.             if ( !(*p) ) {
  431.                if ( isUNIXISH )  p = *av++;
  432.                if ( !isUNIXISH  ||  !p  ||  isOPT(p)  ||  isKWD(p) ) {
  433.                   if ( ARG_isVALOPTIONAL(ad) ) {
  434.                      BSET( arg_flags(ad), ARGGIVEN );
  435.                   }
  436.                   else {
  437.                      (VOID) get_argname(arg_sname(ad), name);
  438.                      usrerr( "%s required for %c%c flag",
  439.                              name, OptPrefix, arg_cname(ad) );
  440.                      arg_flags(ad) = flags;
  441.                      parse_error = pe_SYNTAX;
  442.                   }/*else*/
  443.  
  444.                   if ( isUNIXISH )  av--;
  445.                   break;
  446.                }/*if arg*/
  447.                if ( isUNIXISH )  BSET( arg_flags(ad), ARGVALSEP );
  448.             }/*if empty*/
  449.  
  450.                /* try to convert the type */
  451.             ad_okay = HANDLE(ad, p, cmd_flags(cmd));
  452.             if ( !ad_okay ) {
  453.                arg_flags(ad) = flags;
  454.                parse_error = pe_SYNTAX;
  455.                p += strlen(p);
  456.             }/*if*/
  457.             else {
  458.                BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
  459.                if ( isUNIXISH  &&  ad_okay < 0  &&  !ARG_isVALSEPARATE(ad) ) {
  460.                   p -= ad_okay;
  461.                }
  462.                else {
  463.                   p += strlen(p);
  464.                }
  465.             }/*else*/
  466.  
  467.             if ( !isUNIXISH  &&  *p == OptPrefix )  ++p;
  468.          }/*while*/
  469.       }/*elif option*/
  470.       else {
  471.             /* parsing a list of arguments */
  472.          if ( cmd_list(cmd) ) {  /* we're in the middle of a list/vector */
  473.             ad = cmd_list(cmd);
  474.             flags = arg_flags(ad);  /* reset flags for this argv-item */
  475.             if ( ARG_isGIVEN(ad) ) {
  476.                BCLEAR( arg_flags(ad), ARGVALSEP | ARGKEYWORD );
  477.             }
  478.  
  479.             BSET( arg_flags(ad), ARGVALSEP );
  480.  
  481.             ad_okay = HANDLE(ad, p, cmd_flags(cmd));
  482.             if ( !ad_okay ) {
  483.                arg_flags(ad) = flags;
  484.                parse_error = pe_SYNTAX;
  485.             }
  486.  
  487.             continue;
  488.          }
  489.             /* positional argument */
  490.          is_match = FALSE;
  491.          for (args = argd; args  &&  !is_match ; args = cmd_defargs(args)) {
  492.             for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
  493.                if (arg_type(ad) == argDummy)  continue;
  494.  
  495.                if ( ARG_isPOSITIONAL(ad)  &&
  496.                     (!ARG_isGIVEN(ad) ||  ARG_isMULTIVAL(ad)) ) {
  497.                   is_match = TRUE;
  498.                   break;
  499.                }/*if*/
  500.             }
  501.          }
  502.  
  503.          if ( !is_match ) {
  504.             usrerr("too many arguments");
  505.             parse_error = pe_SYNTAX;
  506.             continue;
  507.          }
  508.  
  509.          flags = arg_flags(ad);
  510.          if ( ARG_isGIVEN(ad) ) {
  511.             BCLEAR( arg_flags(ad), ARGVALSEP | ARGKEYWORD );
  512.             if ( !ARG_isMULTIVAL(ad) )  BCLEAR( arg_flags(ad), ARGVALGIVEN );
  513.          }
  514.  
  515.          if ( ARG_isMULTIVAL(ad) ) {
  516.             cmd_list(cmd) = ad;
  517.          }
  518.  
  519.          /* if FLAGS1ST is set then first positional marks end-of-flags */
  520.          if ( BTEST(cmd_flags(cmd), pa_FLAGS1ST) ) {
  521.             BSET( cmd_state(cmd), ps_NOFLAGS );
  522.          }
  523.  
  524.          BSET( arg_flags(ad), ARGVALSEP );
  525.  
  526.             /* try to convert */
  527.          ad_okay = HANDLE(ad, p, cmd_flags(cmd));
  528.          if ( !ad_okay ) {
  529.             arg_flags(ad) = flags;
  530.             parse_error = pe_SYNTAX;
  531.          }
  532.          else {
  533.             BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
  534.          }
  535.       }/*else*/
  536.    }/*while*/
  537.  
  538.    return  parse_error;
  539. }
  540.  
  541.  
  542. /***************************************************************************
  543. ** ^FUNCTION: fmtarg - format command-argument syntax
  544. **
  545. ** ^SYNOPSIS:
  546. */
  547. #ifndef __ANSI_C__
  548.    static int fmtarg( ad, buf, usgflags )
  549. /*
  550. ** ^PARAMETERS:
  551. */
  552.    ARGDESC *ad;
  553. /*    -- pointer to the argument to format
  554. */
  555.    char *buf;
  556. /*    -- character buffer to hold the formatted result
  557. */
  558.    argMask_t usgflags;
  559. /*    -- set of bitmasks corresponding to the value of the user's USAGECNTL
  560. **       environment variable
  561. */
  562. #endif  /* !__ANSI_C__ */
  563.  
  564. /* ^DESCRIPTION:
  565. **    Fmtarg will determine the proper command-line syntax for the
  566. **    given argument and write the result to the given buffer.
  567. **
  568. ** ^REQUIREMENTS:
  569. **    buf must be large enough to hold the formatted result (100 characters
  570. **    should do the trick).
  571. **
  572. ** ^SIDE-EFFECTS:
  573. **    buf is overwritten.
  574. **
  575. ** ^RETURN-VALUE:
  576. **    The number of printable characters in the argument-syntax-string
  577. **
  578. ** ^ALGORITHM:
  579. **    Print argument usage based on whether or not the argument is
  580. **    positional, hidden, multi-valued (list or vector), etc ....
  581. **    Optional arguments and values are enclosed in square braces.
  582. **
  583. **    Any syntax biases reflected in usgflags will be used.
  584. ***^^**********************************************************************/
  585. #ifdef __ANSI_C__
  586.    static int fmtarg( const ARGDESC *ad, char *buf, argMask_t usgflags )
  587. #endif
  588. {
  589.    /* buf must already be large enough */
  590.    char *pos;
  591.    argName_t   name, keyword;
  592.  
  593.    (VOID) get_argname( arg_sname(ad), name );
  594.  
  595.    if (ARG_isPOSITIONAL(ad)) {
  596.       sprintf( buf, "<%s>", name );
  597.    }
  598.    else {
  599.       (VOID) get_kwdname( arg_sname(ad), keyword );
  600.  
  601.       if ( isupper(arg_cname(ad))  &&  toupper(*keyword) == arg_cname(ad) ) {
  602.          *keyword = toupper(*keyword);
  603.       }
  604.  
  605.       if ( !(usgflags & usg_LONGOPTS) ) {
  606.          sprintf( buf, "%c%c", OptPrefix, arg_cname(ad) );
  607.       }
  608.       else if ( !(usgflags & usg_OPTS) ) {
  609.          sprintf( buf, "%c%s", KwdPrefix, keyword );
  610.       }
  611.       else  {  /* use both */
  612.          if ( OptPrefix == KwdPrefix  &&  *keyword == arg_cname(ad) ) {
  613.             if ( !*(keyword+1) )
  614.                sprintf( buf, "%c%c", OptPrefix, arg_cname(ad) );
  615.             else
  616.                sprintf( buf, "%c%c[%s]", OptPrefix, arg_cname(ad), keyword+1 );
  617.          }
  618.          else {
  619.             sprintf( buf, "%c%c|%c%s", OptPrefix, arg_cname(ad),
  620.                                        KwdPrefix, keyword );
  621.          }
  622.       }
  623.  
  624.       pos = buf + strlen(buf);
  625.  
  626.       if ( ARG_isVALTAKEN(ad)  &&  !ARG_isBOOLEAN(ad)  &&  !ARG_isPSEUDOARG(ad) ) {
  627.          if ( isUNIXISH )  *(pos++) = ' ';
  628.          if ( ARG_isVALOPTIONAL(ad) )  *(pos++) = '[';
  629.          if ( !isUNIXISH )  *(pos++) = *s_ARG_SEP;
  630.          sprintf( pos, "<%s>", name );
  631.          if ( ARG_isVALOPTIONAL(ad) )  strcat(pos, "]");
  632.       }/*if*/
  633.    }/*else*/
  634.  
  635.    return  strlen(buf);
  636. }
  637.  
  638.  
  639. /***************************************************************************
  640. ** ^FUNCTION: ibm_usage - print a usage message
  641. **
  642. ** ^SYNOPSIS:
  643. */
  644. #ifndef __ANSI_C__
  645.    VOID ibm_usage( argd, usage_flags )
  646. /*
  647. ** ^PARAMETERS:
  648. */
  649.    ARGDESC *argd;
  650. /*    -- the command-descriptor array
  651. */
  652.    argMask_t usage_flags;
  653. /*    -- flags set by $USAGECNTL
  654. */
  655. #endif  /* !__ANSI_C__ */
  656.  
  657. /* ^DESCRIPTION:
  658. **    Ibm_usage will print the Unix command-line usage of the given
  659. **    command on standard diagnostic output (stderr). The content of the
  660. **    usage message is controlled by the bitmasks in usage_flags which
  661. **    correspond to the settings in the user's USAGECNTL variable.
  662. **
  663. ** ^REQUIREMENTS:
  664. **    argd should be a non-null command-line argument-descriptor array
  665. **
  666. ** ^SIDE-EFFECTS:
  667. **    Prints on stderr.
  668. **
  669. ** ^RETURN-VALUE:
  670. **    None.
  671. **
  672. ** ^ALGORITHM:
  673. **    - if no usage is desired then exit
  674. **    - if paging is requested print to the pager instead of stderr
  675. **    - print the command-line syntax
  676. **    - if the description is requested print it
  677. **    - if verbose mode is requested, print the description of each argument
  678. ***^^**********************************************************************/
  679. #ifdef __ANSI_C__
  680.    void ibm_usage( const ARGDESC *argd, argMask_t usage_flags )
  681. #endif
  682. {
  683.    register CONST ARGDESC  *ad, *args, *cmd;
  684.    int  max_cols = 80, max_lines  = 24;
  685.    int  ll, margin, options, longest, positionals;
  686.    BOOL first = TRUE;
  687.    FILE *fp;
  688.  
  689.    if ( !argd )  return;
  690.  
  691.       /* initialize command-structure */
  692.    if ( !CMD_isINIT(argd) )  init_args( (ARGDESC *)argd );
  693.    cmd = argd;
  694.  
  695.       /* force verbose-mode if requested */
  696.    if ( Usage_Requested )   BSET( usage_flags, usg_VERBOSE );
  697.  
  698.    if ( BTEST(usage_flags, usg_NONE) )  return;
  699.  
  700.    fp = ( BTEST(usage_flags, usg_PAGED) )
  701.       ? pgopen( stderr, getenv("USAGE_PAGER") )
  702.       : stderr;
  703.  
  704.       /* get screen size */
  705.    get_winsize( fileno(fp), &max_lines, &max_cols );
  706.  
  707.    fprintf(fp, "Usage: %.*s", ProgNameLen, (ProgName) ? ProgName : "");
  708.  
  709.    ll = ProgNameLen + 7;
  710.    margin = ll + 1;
  711.    longest = 0;
  712.  
  713.       /* print Synopsis */
  714.    for ( positionals = 0 ; positionals < 2 ; positionals++ ) {
  715.       for ( args = argd ; args ; args = cmd_defargs(args) ) {
  716.          for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
  717.             argName_t  buf;
  718.             int pl;
  719.  
  720.                /* don't display hidden arguments */
  721.             if ( ARG_isHIDDEN(ad) )  continue;
  722.             if ( !positionals  &&  ARG_isPOSITIONAL(ad) )  continue;
  723.             if ( positionals  &&  !ARG_isPOSITIONAL(ad) )  continue;
  724.  
  725.                /* figure out how wide this parameter is (for printing) */
  726.             pl = fmtarg(ad, buf, usage_flags);
  727.  
  728.             if ( pl > longest)  longest = pl;
  729.  
  730.             if  ( ARG_isMULTIVAL(ad) ) {
  731.                strcat( buf, "..." );
  732.                pl += 3;
  733.             }
  734.             if ( !ARG_isREQUIRED(ad) ) {
  735.                pl += 2;
  736.             }
  737.  
  738.             /* see if this will fit */
  739.             if ( (ll + pl + 1) > (max_cols - first) ) {
  740.                   /* no... start a new line */
  741.                fprintf(fp, "\n%*s", margin, "");
  742.                ll = margin;
  743.             }
  744.             else {
  745.                   /* yes... just throw in a space */
  746.                fputc(' ', fp);
  747.                ++ll;
  748.             }
  749.             ll += pl;
  750.  
  751.                /* show the argument */
  752.             if ( !ARG_isREQUIRED(ad) )  fputc('[', fp);
  753.             fprintf(fp, buf);
  754.             if ( !ARG_isREQUIRED(ad) )  fputc(']', fp);
  755.  
  756.             first = FALSE;  /* not first line anymore */
  757.          }/*for each ad */
  758.       }/* for each argd */
  759.    }/* for each parm-type */
  760.  
  761.    fputc('\n', fp);
  762.  
  763.    if ( BTEST(usage_flags, usg_DESCRIPTION) ) {
  764.       CONST char *description = cmd_description(cmd);
  765.  
  766.       if ( description  &&  *description ) {
  767.          fprintf( fp, "Description:\n" );
  768.          indent_para(fp, max_cols, 8, "", 0, description, 0);
  769.          fputc( '\n', fp );
  770.       }
  771.    }/*if*/
  772.  
  773.    if ( !BTEST(usage_flags, usg_VERBOSE) )  {
  774.       if ( pgactive(fp) )  (VOID) pgclose( fp );
  775.       return;
  776.    }
  777.  
  778.    options = 0;
  779.  
  780.       /* print Argument descriptions */
  781.    for ( positionals = 0 ; positionals < 2 ; positionals++ ) {
  782.       for ( args = argd ; args ; args = cmd_defargs(args) ) {
  783.          for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
  784.             argName_t  buf;
  785.             char  *desc;
  786.             int  desclen;
  787.  
  788.                /* don't display hidden arguments */
  789.             if ( ARG_isHIDDEN(ad) )  continue;
  790.             if ( !positionals  &&  ARG_isPOSITIONAL(ad) )  continue;
  791.             if ( positionals  &&  !ARG_isPOSITIONAL(ad) )  continue;
  792.  
  793.             if ( !options++ )   fprintf(fp, "Options/Arguments:\n");
  794.             fmtarg(ad, buf, usage_flags);
  795.             desc = get_argdesc(arg_description(ad), &desclen);
  796.             indent_para( fp, max_cols, 8, buf, longest+2, desc, desclen );
  797.          }/*for each ad */
  798.       }/* for each argd */
  799.    }/* for each parm-type */
  800.  
  801.    if ( pgactive(fp) )  (VOID) pgclose( fp );
  802. }
  803.  
  804.