File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / sntp / libopts / usage.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 7 months ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    1: 
    2: /*
    3:  * \file usage.c
    4:  *
    5:  * Time-stamp:      "2011-02-01 14:42:37 bkorb"
    6:  *
    7:  *  This module implements the default usage procedure for
    8:  *  Automated Options.  It may be overridden, of course.
    9:  *
   10:  *  Sort options:
   11:     --start=END-[S]TATIC-FORWARD --patt='^/\*($|[^:])' \
   12:     --out=xx.c key='^[a-zA-Z0-9_]+\(' --trail='^/\*:' \
   13:     --spac=2 --input=usage.c
   14:  */
   15: 
   16: /*
   17:  *  This file is part of AutoOpts, a companion to AutoGen.
   18:  *  AutoOpts is free software.
   19:  *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
   20:  *
   21:  *  AutoOpts is available under any one of two licenses.  The license
   22:  *  in use must be one of these two and the choice is under the control
   23:  *  of the user of the license.
   24:  *
   25:  *   The GNU Lesser General Public License, version 3 or later
   26:  *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
   27:  *
   28:  *   The Modified Berkeley Software Distribution License
   29:  *      See the file "COPYING.mbsd"
   30:  *
   31:  *  These files have the following md5sums:
   32:  *
   33:  *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
   34:  *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
   35:  *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
   36:  */
   37: 
   38: #define OPTPROC_L_N_S  (OPTPROC_LONGOPT | OPTPROC_SHORTOPT)
   39: 
   40: /* = = = START-STATIC-FORWARD = = = */
   41: static void
   42: set_usage_flags(tOptions * opts, char const * flg_txt);
   43: 
   44: static inline ag_bool
   45: do_gnu_usage(tOptions * pOpts);
   46: 
   47: static inline ag_bool
   48: skip_misuse_usage(tOptions * pOpts);
   49: 
   50: static void
   51: print_usage_details(tOptions * opts, int exit_code);
   52: 
   53: static void
   54: prt_extd_usage(tOptions * pOptions, tOptDesc * pOD, arg_types_t * pAT);
   55: 
   56: static void
   57: prt_ini_list(char const * const * papz, ag_bool * pInitIntro,
   58:              char const * pzRc, char const * pzPN);
   59: 
   60: static void
   61: prt_preamble(tOptions * pOptions, tOptDesc * pOD, arg_types_t * pAT);
   62: 
   63: static void
   64: prt_one_usage(tOptions * pOptions, tOptDesc * pOD, arg_types_t * pAT);
   65: 
   66: static void
   67: prt_opt_usage(tOptions * pOpts, int ex_code, char const * pOptTitle);
   68: 
   69: static void
   70: prt_prog_detail(tOptions* pOptions);
   71: 
   72: static int
   73: setGnuOptFmts(tOptions* pOpts, tCC** ppT);
   74: 
   75: static int
   76: setStdOptFmts(tOptions* pOpts, tCC** ppT);
   77: /* = = = END-STATIC-FORWARD = = = */
   78: 
   79: /*
   80:  *  NB: no entry may be a prefix of another entry
   81:  */
   82: #define AOFLAG_TABLE                            \
   83:     _aof_(gnu,             OPTPROC_GNUUSAGE )   \
   84:     _aof_(autoopts,        ~OPTPROC_GNUUSAGE)   \
   85:     _aof_(no_misuse_usage, OPTPROC_MISUSE   )   \
   86:     _aof_(misuse_usage,    ~OPTPROC_MISUSE  )
   87: 
   88: static void
   89: set_usage_flags(tOptions * opts, char const * flg_txt)
   90: {
   91:     typedef struct {
   92:         size_t          fnm_len;
   93:         uint32_t        fnm_mask;
   94:         char const *    fnm_name;
   95:     } ao_flag_names_t;
   96: 
   97: #   define _aof_(_n, _f)   AOUF_ ## _n ## _ID,
   98:     typedef enum { AOFLAG_TABLE AOUF_COUNT } ao_flag_id_t;
   99: #   undef  _aof_
  100: 
  101: #   define _aof_(_n, _f)   AOUF_ ## _n = (1 << AOUF_ ## _n ## _ID),
  102:     typedef enum { AOFLAG_TABLE } ao_flags_t;
  103: #   undef  _aof_
  104: 
  105: #   define _aof_(_n, _f)   { sizeof(#_n)-1, _f, #_n },
  106:     static ao_flag_names_t const fn_table[AOUF_COUNT] = {
  107:         AOFLAG_TABLE
  108:     };
  109: #   undef  _aof_
  110: 
  111:     ao_flags_t flg = 0;
  112: 
  113:     if (flg_txt == NULL) {
  114:         flg_txt = getenv("AUTOOPTS_USAGE");
  115:         if (flg_txt == NULL)
  116:             return;
  117:     }
  118: 
  119:     while (IS_WHITESPACE_CHAR(*flg_txt))  flg_txt++;
  120:     if (*flg_txt == NUL)
  121:         return;
  122: 
  123:     for (;;) {
  124:         int ix = 0;
  125:         ao_flag_names_t const * fnt = fn_table;
  126: 
  127:         for (;;) {
  128:             if (strneqvcmp(flg_txt, fnt->fnm_name, fnt->fnm_len) == 0)
  129:                 break;
  130:             if (++ix >= AOUF_COUNT)
  131:                 return;
  132:             fnt++;
  133:         }
  134: 
  135:         /*
  136:          *  Make sure we have a full match.  Look for whitespace,
  137:          *  a comma, or a NUL byte.
  138:          */
  139:         if (! IS_END_LIST_ENTRY_CHAR(flg_txt[fnt->fnm_len]))
  140:             return;
  141: 
  142:         flg |= 1 << ix;
  143:         flg_txt  += fnt->fnm_len;
  144:         while (IS_WHITESPACE_CHAR(*flg_txt))  flg_txt++;
  145: 
  146:         if (*flg_txt == NUL)
  147:             break;
  148: 
  149:         if (*flg_txt == ',') {
  150:             /*
  151:              *  skip the comma and following white space
  152:              */
  153:             while (IS_WHITESPACE_CHAR(*++flg_txt))  ;
  154:             if (*flg_txt == NUL)
  155:                 break;
  156:         }
  157:     }
  158: 
  159:     {
  160:         ao_flag_names_t const * fnm = fn_table;
  161: 
  162:         while (flg != 0) {
  163:             if ((flg & 1) != 0) {
  164:                 if ((fnm->fnm_mask & OPTPROC_LONGOPT) != 0)
  165:                      opts->fOptSet &= fnm->fnm_mask;
  166:                 else opts->fOptSet |= fnm->fnm_mask;
  167:             }
  168:             flg >>= 1;
  169:             fnm++;
  170:         }
  171:     }
  172: }
  173: 
  174: /*
  175:  *  Figure out if we should try to format usage text sort-of like
  176:  *  the way many GNU programs do.
  177:  */
  178: static inline ag_bool
  179: do_gnu_usage(tOptions * pOpts)
  180: {
  181:     return (pOpts->fOptSet & OPTPROC_GNUUSAGE) ? AG_TRUE : AG_FALSE;
  182: }
  183: 
  184: /*
  185:  *  Figure out if we should try to format usage text sort-of like
  186:  *  the way many GNU programs do.
  187:  */
  188: static inline ag_bool
  189: skip_misuse_usage(tOptions * pOpts)
  190: {
  191:     return (pOpts->fOptSet & OPTPROC_MISUSE) ? AG_TRUE : AG_FALSE;
  192: }
  193: 
  194: 
  195: /*=export_func  optionOnlyUsage
  196:  *
  197:  * what:  Print usage text for just the options
  198:  * arg:   + tOptions*   + pOpts    + program options descriptor +
  199:  * arg:   + int         + ex_code  + exit code for calling exit(3) +
  200:  *
  201:  * doc:
  202:  *  This routine will print only the usage for each option.
  203:  *  This function may be used when the emitted usage must incorporate
  204:  *  information not available to AutoOpts.
  205: =*/
  206: void
  207: optionOnlyUsage(tOptions * pOpts, int ex_code)
  208: {
  209:     char const * pOptTitle = NULL;
  210: 
  211:     set_usage_flags(pOpts, NULL);
  212:     if ((ex_code != EXIT_SUCCESS) &&
  213:         skip_misuse_usage(pOpts))
  214:         return;
  215: 
  216:     /*
  217:      *  Determine which header and which option formatting strings to use
  218:      */
  219:     if (do_gnu_usage(pOpts)) {
  220:         (void)setGnuOptFmts(pOpts, &pOptTitle);
  221:     }
  222:     else {
  223:         (void)setStdOptFmts(pOpts, &pOptTitle);
  224:     }
  225: 
  226:     prt_opt_usage(pOpts, ex_code, pOptTitle);
  227: 
  228:     fflush(option_usage_fp);
  229:     if (ferror(option_usage_fp) != 0) {
  230:         fputs(zOutputFail, stderr);
  231:         exit(EXIT_FAILURE);
  232:     }
  233: }
  234: 
  235: static void
  236: print_usage_details(tOptions * opts, int exit_code)
  237: {
  238:     {
  239:         char const * pOptTitle = NULL;
  240: 
  241:         /*
  242:          *  Determine which header and which option formatting strings to use
  243:          */
  244:         if (do_gnu_usage(opts)) {
  245:             int flen = setGnuOptFmts(opts, &pOptTitle);
  246:             sprintf(zOptFmtLine, zFmtFmt, flen);
  247:             fputc('\n', option_usage_fp);
  248:         }
  249:         else {
  250:             int flen = setStdOptFmts(opts, &pOptTitle);
  251:             sprintf(zOptFmtLine, zFmtFmt, flen);
  252: 
  253:             /*
  254:              *  When we exit with EXIT_SUCCESS and the first option is a doc
  255:              *  option, we do *NOT* want to emit the column headers.
  256:              *  Otherwise, we do.
  257:              */
  258:             if (  (exit_code != EXIT_SUCCESS)
  259:                || ((opts->pOptDesc->fOptState & OPTST_DOCUMENT) == 0) )
  260: 
  261:                 fputs(pOptTitle, option_usage_fp);
  262:         }
  263: 
  264:         prt_opt_usage(opts, exit_code, pOptTitle);
  265:     }
  266: 
  267:     /*
  268:      *  Describe the mechanics of denoting the options
  269:      */
  270:     switch (opts->fOptSet & OPTPROC_L_N_S) {
  271:     case OPTPROC_L_N_S:     fputs(zFlagOkay, option_usage_fp); break;
  272:     case OPTPROC_SHORTOPT:  break;
  273:     case OPTPROC_LONGOPT:   fputs(zNoFlags,  option_usage_fp); break;
  274:     case 0:                 fputs(zOptsOnly, option_usage_fp); break;
  275:     }
  276: 
  277:     if ((opts->fOptSet & OPTPROC_NUM_OPT) != 0)
  278:         fputs(zNumberOpt, option_usage_fp);
  279: 
  280:     if ((opts->fOptSet & OPTPROC_REORDER) != 0)
  281:         fputs(zReorder, option_usage_fp);
  282: 
  283:     if (opts->pzExplain != NULL)
  284:         fputs(opts->pzExplain, option_usage_fp);
  285: 
  286:     /*
  287:      *  IF the user is asking for help (thus exiting with SUCCESS),
  288:      *  THEN see what additional information we can provide.
  289:      */
  290:     if (exit_code == EXIT_SUCCESS)
  291:         prt_prog_detail(opts);
  292: 
  293:     /*
  294:      * Give bug notification preference to the packager information
  295:      */
  296:     if (HAS_pzPkgDataDir(opts) && (opts->pzPackager != NULL))
  297:         fputs(opts->pzPackager, option_usage_fp);
  298: 
  299:     else if (opts->pzBugAddr != NULL)
  300:         fprintf(option_usage_fp, zPlsSendBugs, opts->pzBugAddr);
  301: 
  302:     fflush(option_usage_fp);
  303: 
  304:     if (ferror(option_usage_fp) != 0) {
  305:         fputs(zOutputFail, stderr);
  306:         exit(EXIT_FAILURE);
  307:     }
  308: }
  309: 
  310: 
  311: /*=export_func  optionUsage
  312:  * private:
  313:  *
  314:  * what:  Print usage text
  315:  * arg:   + tOptions* + pOptions + program options descriptor +
  316:  * arg:   + int       + exitCode + exit code for calling exit(3) +
  317:  *
  318:  * doc:
  319:  *  This routine will print usage in both GNU-standard and AutoOpts-expanded
  320:  *  formats.  The descriptor specifies the default, but AUTOOPTS_USAGE will
  321:  *  over-ride this, providing the value of it is set to either "gnu" or
  322:  *  "autoopts".  This routine will @strong{not} return.
  323:  *
  324:  *  If "exitCode" is "EX_USAGE" (normally 64), then output will to to stdout
  325:  *  and the actual exit code will be "EXIT_SUCCESS".
  326: =*/
  327: void
  328: optionUsage(tOptions * pOptions, int usage_exit_code)
  329: {
  330:     int exit_code =
  331:         (usage_exit_code == EX_USAGE) ? EXIT_SUCCESS : usage_exit_code;
  332: 
  333:     displayEnum = AG_FALSE;
  334: 
  335:     /*
  336:      *  Paged usage will preset option_usage_fp to an output file.
  337:      *  If it hasn't already been set, then set it to standard output
  338:      *  on successful exit (help was requested), otherwise error out.
  339:      *
  340:      *  Test the version before obtaining pzFullUsage or pzShortUsage.
  341:      *  These fields do not exist before revision 30.
  342:      */
  343:     {
  344:         char const * pz;
  345: 
  346:         if (exit_code == EXIT_SUCCESS) {
  347:             pz = (pOptions->structVersion >= 30 * 4096)
  348:                 ? pOptions->pzFullUsage : NULL;
  349: 
  350:             if (option_usage_fp == NULL)
  351:                 option_usage_fp = stdout;
  352:         } else {
  353:             pz = (pOptions->structVersion >= 30 * 4096)
  354:                 ? pOptions->pzShortUsage : NULL;
  355: 
  356:             if (option_usage_fp == NULL)
  357:                 option_usage_fp = stderr;
  358:         }
  359: 
  360:         if (pz != NULL) {
  361:             fputs(pz, option_usage_fp);
  362:             exit(exit_code);
  363:         }
  364:     }
  365: 
  366:     fprintf(option_usage_fp, pOptions->pzUsageTitle, pOptions->pzProgName);
  367:     set_usage_flags(pOptions, NULL);
  368: 
  369:     if ((exit_code == EXIT_SUCCESS) ||
  370:         (! skip_misuse_usage(pOptions)))
  371: 
  372:         print_usage_details(pOptions, usage_exit_code);
  373: 
  374:     exit(exit_code);
  375: }
  376: 
  377: 
  378: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  379:  *
  380:  *   PER OPTION TYPE USAGE INFORMATION
  381:  */
  382: static void
  383: prt_extd_usage(tOptions * pOptions, tOptDesc * pOD, arg_types_t * pAT)
  384: {
  385:     /*
  386:      *  IF there are option conflicts or dependencies,
  387:      *  THEN print them here.
  388:      */
  389:     if (  (pOD->pOptMust != NULL)
  390:        || (pOD->pOptCant != NULL) ) {
  391: 
  392:         fputs(zTabHyp, option_usage_fp);
  393: 
  394:         /*
  395:          *  DEPENDENCIES:
  396:          */
  397:         if (pOD->pOptMust != NULL) {
  398:             const int* pOptNo = pOD->pOptMust;
  399: 
  400:             fputs(zReqThese, option_usage_fp);
  401:             for (;;) {
  402:                 fprintf(option_usage_fp, zTabout,
  403:                         pOptions->pOptDesc[*pOptNo].pz_Name);
  404:                 if (*++pOptNo == NO_EQUIVALENT)
  405:                     break;
  406:             }
  407: 
  408:             if (pOD->pOptCant != NULL)
  409:                 fputs(zTabHypAnd, option_usage_fp);
  410:         }
  411: 
  412:         /*
  413:          *  CONFLICTS:
  414:          */
  415:         if (pOD->pOptCant != NULL) {
  416:             const int* pOptNo = pOD->pOptCant;
  417: 
  418:             fputs(zProhib, option_usage_fp);
  419:             for (;;) {
  420:                 fprintf(option_usage_fp, zTabout,
  421:                         pOptions->pOptDesc[*pOptNo].pz_Name);
  422:                 if (*++pOptNo == NO_EQUIVALENT)
  423:                     break;
  424:             }
  425:         }
  426:     }
  427: 
  428:     /*
  429:      *  IF there is a disablement string
  430:      *  THEN print the disablement info
  431:      */
  432:     if (pOD->pz_DisableName != NULL )
  433:         fprintf(option_usage_fp, zDis, pOD->pz_DisableName);
  434: 
  435:     /*
  436:      *  Check for argument types that have callbacks with magical properties
  437:      */
  438:     switch (OPTST_GET_ARGTYPE(pOD->fOptState)) {
  439:     case OPARG_TYPE_NUMERIC:
  440:         /*
  441:          *  IF the numeric option has a special callback,
  442:          *  THEN call it, requesting the range or other special info
  443:          */
  444:         if (  (pOD->pOptProc != NULL)
  445:            && (pOD->pOptProc != optionNumericVal) ) {
  446:             (*(pOD->pOptProc))(OPTPROC_EMIT_USAGE, pOD);
  447:         }
  448:         break;
  449: 
  450:     case OPARG_TYPE_FILE:
  451:         (*(pOD->pOptProc))(OPTPROC_EMIT_USAGE, pOD);
  452:         break;
  453:     }
  454: 
  455:     /*
  456:      *  IF the option defaults to being enabled,
  457:      *  THEN print that out
  458:      */
  459:     if (pOD->fOptState & OPTST_INITENABLED)
  460:         fputs(zEnab, option_usage_fp);
  461: 
  462:     /*
  463:      *  IF  the option is in an equivalence class
  464:      *        AND not the designated lead
  465:      *  THEN print equivalence and leave it at that.
  466:      */
  467:     if (  (pOD->optEquivIndex != NO_EQUIVALENT)
  468:        && (pOD->optEquivIndex != pOD->optActualIndex )  )  {
  469:         fprintf(option_usage_fp, zAlt,
  470:                  pOptions->pOptDesc[ pOD->optEquivIndex ].pz_Name);
  471:         return;
  472:     }
  473: 
  474:     /*
  475:      *  IF this particular option can NOT be preset
  476:      *    AND some form of presetting IS allowed,
  477:      *    AND it is not an auto-managed option (e.g. --help, et al.)
  478:      *  THEN advise that this option may not be preset.
  479:      */
  480:     if (  ((pOD->fOptState & OPTST_NO_INIT) != 0)
  481:        && (  (pOptions->papzHomeList != NULL)
  482:           || (pOptions->pzPROGNAME != NULL)
  483:           )
  484:        && (pOD->optIndex < pOptions->presetOptCt)
  485:        )
  486: 
  487:         fputs(zNoPreset, option_usage_fp);
  488: 
  489:     /*
  490:      *  Print the appearance requirements.
  491:      */
  492:     if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_MEMBERSHIP)
  493:         fputs(zMembers, option_usage_fp);
  494: 
  495:     else switch (pOD->optMinCt) {
  496:     case 1:
  497:     case 0:
  498:         switch (pOD->optMaxCt) {
  499:         case 0:       fputs(zPreset, option_usage_fp); break;
  500:         case NOLIMIT: fputs(zNoLim, option_usage_fp);  break;
  501:         case 1:       break;
  502:             /*
  503:              * IF the max is more than one but limited, print "UP TO" message
  504:              */
  505:         default:      fprintf(option_usage_fp, zUpTo, pOD->optMaxCt);  break;
  506:         }
  507:         break;
  508: 
  509:     default:
  510:         /*
  511:          *  More than one is required.  Print the range.
  512:          */
  513:         fprintf(option_usage_fp, zMust, pOD->optMinCt, pOD->optMaxCt);
  514:     }
  515: 
  516:     if (  NAMED_OPTS(pOptions)
  517:        && (pOptions->specOptIdx.default_opt == pOD->optIndex))
  518:         fputs(zDefaultOpt, option_usage_fp);
  519: }
  520: 
  521: 
  522: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  523:  *
  524:  *   Figure out where all the initialization files might live.
  525:  *   This requires translating some environment variables and
  526:  *   testing to see if a name is a directory or a file.  It's
  527:  *   squishy, but important to tell users how to find these files.
  528:  */
  529: static void
  530: prt_ini_list(char const * const * papz, ag_bool * pInitIntro,
  531:              char const * pzRc, char const * pzPN)
  532: {
  533:     char zPath[AG_PATH_MAX+1];
  534: 
  535:     if (papz == NULL)
  536:         return;
  537: 
  538:     fputs(zPresetIntro, option_usage_fp);
  539:     *pInitIntro = AG_FALSE;
  540: 
  541:     for (;;) {
  542:         char const * pzPath = *(papz++);
  543:         char const * pzReal = zPath;
  544: 
  545:         if (pzPath == NULL)
  546:             break;
  547: 
  548:         /*
  549:          * Ignore any invalid paths
  550:          */
  551:         if (! optionMakePath(zPath, (int)sizeof(zPath), pzPath, pzPN))
  552:             pzReal = pzPath;
  553: 
  554:         /*
  555:          * Expand paths that are relative to the executable or installation
  556:          * directories.  Leave alone paths that use environment variables.
  557:          */
  558:         else if ((*pzPath == '$')
  559:                  && ((pzPath[1] == '$') || (pzPath[1] == '@')))
  560:             pzPath = pzReal;
  561: 
  562:         /*
  563:          *  Print the name of the "homerc" file.  If the "rcfile" name is
  564:          *  not empty, we may or may not print that, too...
  565:          */
  566:         fprintf(option_usage_fp, zPathFmt, pzPath);
  567:         if (*pzRc != NUL) {
  568:             struct stat sb;
  569: 
  570:             /*
  571:              *  IF the "homerc" file is a directory,
  572:              *  then append the "rcfile" name.
  573:              */
  574:             if ((stat(pzReal, &sb) == 0) && S_ISDIR(sb.st_mode)) {
  575:                 fputc(DIRCH, option_usage_fp);
  576:                 fputs(pzRc,  option_usage_fp);
  577:             }
  578:         }
  579: 
  580:         fputc('\n', option_usage_fp);
  581:     }
  582: }
  583: 
  584: 
  585: static void
  586: prt_preamble(tOptions * pOptions, tOptDesc * pOD, arg_types_t * pAT)
  587: {
  588:     /*
  589:      *  Flag prefix: IF no flags at all, then omit it.  If not printable
  590:      *  (not allowed for this option), then blank, else print it.
  591:      *  Follow it with a comma if we are doing GNU usage and long
  592:      *  opts are to be printed too.
  593:      */
  594:     if ((pOptions->fOptSet & OPTPROC_SHORTOPT) == 0)
  595:         fputs(pAT->pzSpc, option_usage_fp);
  596: 
  597:     else if (! IS_GRAPHIC_CHAR(pOD->optValue)) {
  598:         if (  (pOptions->fOptSet & (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT))
  599:            == (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT))
  600:             fputc(' ', option_usage_fp);
  601:         fputs(pAT->pzNoF, option_usage_fp);
  602: 
  603:     } else {
  604:         fprintf(option_usage_fp, "   -%c", pOD->optValue);
  605:         if (  (pOptions->fOptSet & (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT))
  606:            == (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT))
  607:             fputs(", ", option_usage_fp);
  608:     }
  609: }
  610: 
  611: /*
  612:  *  Print the usage information for a single option.
  613:  */
  614: static void
  615: prt_one_usage(tOptions * pOptions, tOptDesc * pOD, arg_types_t * pAT)
  616: {
  617:     prt_preamble(pOptions, pOD, pAT);
  618: 
  619:     {
  620:         char z[ 80 ];
  621:         char const *  pzArgType;
  622: 
  623:         /*
  624:          *  Determine the argument type string first on its usage, then,
  625:          *  when the option argument is required, base the type string on the
  626:          *  argument type.
  627:          */
  628:         if (pOD->fOptState & OPTST_ARG_OPTIONAL) {
  629:             pzArgType = pAT->pzOpt;
  630: 
  631:         } else switch (OPTST_GET_ARGTYPE(pOD->fOptState)) {
  632:         case OPARG_TYPE_NONE:        pzArgType = pAT->pzNo;   break;
  633:         case OPARG_TYPE_ENUMERATION: pzArgType = pAT->pzKey;  break;
  634:         case OPARG_TYPE_FILE:        pzArgType = pAT->pzFile; break;
  635:         case OPARG_TYPE_MEMBERSHIP:  pzArgType = pAT->pzKeyL; break;
  636:         case OPARG_TYPE_BOOLEAN:     pzArgType = pAT->pzBool; break;
  637:         case OPARG_TYPE_NUMERIC:     pzArgType = pAT->pzNum;  break;
  638:         case OPARG_TYPE_HIERARCHY:   pzArgType = pAT->pzNest; break;
  639:         case OPARG_TYPE_STRING:      pzArgType = pAT->pzStr;  break;
  640:         case OPARG_TYPE_TIME:        pzArgType = pAT->pzTime; break;
  641:         default:                     goto bogus_desc;
  642:         }
  643: 
  644:         snprintf(z, sizeof(z), pAT->pzOptFmt, pzArgType, pOD->pz_Name,
  645:                  (pOD->optMinCt != 0) ? pAT->pzReq : pAT->pzOpt);
  646: 
  647:         fprintf(option_usage_fp, zOptFmtLine, z, pOD->pzText);
  648: 
  649:         switch (OPTST_GET_ARGTYPE(pOD->fOptState)) {
  650:         case OPARG_TYPE_ENUMERATION:
  651:         case OPARG_TYPE_MEMBERSHIP:
  652:             displayEnum = (pOD->pOptProc != NULL) ? AG_TRUE : displayEnum;
  653:         }
  654:     }
  655:     return;
  656: 
  657:  bogus_desc:
  658:     fprintf(stderr, zInvalOptDesc, pOD->pz_Name);
  659:     exit(EX_SOFTWARE);
  660: }
  661: 
  662: 
  663: /*
  664:  *  Print out the usage information for just the options.
  665:  */
  666: static void
  667: prt_opt_usage(tOptions * pOpts, int ex_code, char const * pOptTitle)
  668: {
  669:     int         ct     = pOpts->optCt;
  670:     int         optNo  = 0;
  671:     tOptDesc *  pOD    = pOpts->pOptDesc;
  672:     int         docCt  = 0;
  673: 
  674:     do  {
  675:         if ((pOD->fOptState & OPTST_NO_USAGE_MASK) != 0) {
  676: 
  677:             /*
  678:              * IF      this is a compiled-out option
  679:              *   *AND* usage was requested with "omitted-usage"
  680:              *   *AND* this is NOT abbreviated usage
  681:              * THEN display this option.
  682:              */
  683:             if (  (pOD->fOptState == (OPTST_OMITTED | OPTST_NO_INIT))
  684:                && (pOD->pz_Name != NULL)
  685:                && (ex_code == EXIT_SUCCESS))  {
  686: 
  687:                 char const * why_pz =
  688:                     (pOD->pzText == NULL) ? zDisabledWhy : pOD->pzText;
  689:                 prt_preamble(pOpts, pOD, &argTypes);
  690:                 fprintf(option_usage_fp, zDisabledOpt, pOD->pz_Name, why_pz);
  691:             }
  692: 
  693:             continue;
  694:         }
  695: 
  696:         if ((pOD->fOptState & OPTST_DOCUMENT) != 0) {
  697:             if (ex_code == EXIT_SUCCESS) {
  698:                 fprintf(option_usage_fp, argTypes.pzBrk, pOD->pzText,
  699:                         pOptTitle);
  700:                 docCt++;
  701:             }
  702: 
  703:             continue;
  704:         }
  705: 
  706:         /*
  707:          *  IF       this is the first auto-opt maintained option
  708:          *    *AND*  we are doing a full help
  709:          *    *AND*  there are documentation options
  710:          *    *AND*  the last one was not a doc option,
  711:          *  THEN document that the remaining options are not user opts
  712:          */
  713:         if (  (pOpts->presetOptCt == optNo)
  714:            && (ex_code == EXIT_SUCCESS)
  715:            && (docCt > 0)
  716:            && ((pOD[-1].fOptState & OPTST_DOCUMENT) == 0) )
  717:             fprintf(option_usage_fp, argTypes.pzBrk, zAuto, pOptTitle);
  718: 
  719:         prt_one_usage(pOpts, pOD, &argTypes);
  720: 
  721:         /*
  722:          *  IF we were invoked because of the --help option,
  723:          *  THEN print all the extra info
  724:          */
  725:         if (ex_code == EXIT_SUCCESS)
  726:             prt_extd_usage(pOpts, pOD, &argTypes);
  727: 
  728:     }  while (pOD++, optNo++, (--ct > 0));
  729: 
  730:     fputc('\n', option_usage_fp);
  731: }
  732: 
  733: 
  734: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  735:  *
  736:  *   PROGRAM DETAILS
  737:  */
  738: static void
  739: prt_prog_detail(tOptions* pOptions)
  740: {
  741:     ag_bool  initIntro = AG_TRUE;
  742: 
  743:     /*
  744:      *  Display all the places we look for config files
  745:      */
  746:     prt_ini_list(pOptions->papzHomeList, &initIntro,
  747:                  pOptions->pzRcName, pOptions->pzProgPath);
  748: 
  749:     /*
  750:      *  Let the user know about environment variable settings
  751:      */
  752:     if ((pOptions->fOptSet & OPTPROC_ENVIRON) != 0) {
  753:         if (initIntro)
  754:             fputs(zPresetIntro, option_usage_fp);
  755: 
  756:         fprintf(option_usage_fp, zExamineFmt, pOptions->pzPROGNAME);
  757:     }
  758: 
  759:     /*
  760:      *  IF we found an enumeration,
  761:      *  THEN hunt for it again.  Call the handler proc with a NULL
  762:      *       option struct pointer.  That tells it to display the keywords.
  763:      */
  764:     if (displayEnum) {
  765:         int        ct     = pOptions->optCt;
  766:         int        optNo  = 0;
  767:         tOptDesc*  pOD    = pOptions->pOptDesc;
  768: 
  769:         fputc('\n', option_usage_fp);
  770:         fflush(option_usage_fp);
  771:         do  {
  772:             switch (OPTST_GET_ARGTYPE(pOD->fOptState)) {
  773:             case OPARG_TYPE_ENUMERATION:
  774:             case OPARG_TYPE_MEMBERSHIP:
  775:                 (*(pOD->pOptProc))(OPTPROC_EMIT_USAGE, pOD);
  776:             }
  777:         }  while (pOD++, optNo++, (--ct > 0));
  778:     }
  779: 
  780:     /*
  781:      *  If there is a detail string, now is the time for that.
  782:      */
  783:     if (pOptions->pzDetail != NULL)
  784:         fputs(pOptions->pzDetail, option_usage_fp);
  785: }
  786: 
  787: 
  788: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  789:  *
  790:  *   OPTION LINE FORMATTING SETUP
  791:  *
  792:  *  The "OptFmt" formats receive three arguments:
  793:  *  1.  the type of the option's argument
  794:  *  2.  the long name of the option
  795:  *  3.  "YES" or "no ", depending on whether or not the option must appear
  796:  *      on the command line.
  797:  *  These formats are used immediately after the option flag (if used) has
  798:  *  been printed.
  799:  *
  800:  *  Set up the formatting for GNU-style output
  801:  */
  802: static int
  803: setGnuOptFmts(tOptions* pOpts, tCC** ppT)
  804: {
  805:     int  flen = 22;
  806:     *ppT = zNoRq_ShrtTtl;
  807: 
  808:     argTypes.pzStr  = zGnuStrArg;
  809:     argTypes.pzReq  = zOneSpace;
  810:     argTypes.pzNum  = zGnuNumArg;
  811:     argTypes.pzKey  = zGnuKeyArg;
  812:     argTypes.pzKeyL = zGnuKeyLArg;
  813:     argTypes.pzTime = zGnuTimeArg;
  814:     argTypes.pzFile = zGnuFileArg;
  815:     argTypes.pzBool = zGnuBoolArg;
  816:     argTypes.pzNest = zGnuNestArg;
  817:     argTypes.pzOpt  = zGnuOptArg;
  818:     argTypes.pzNo   = zOneSpace;
  819:     argTypes.pzBrk  = zGnuBreak;
  820:     argTypes.pzNoF  = zSixSpaces;
  821:     argTypes.pzSpc  = zThreeSpaces;
  822: 
  823:     switch (pOpts->fOptSet & OPTPROC_L_N_S) {
  824:     case OPTPROC_L_N_S:    argTypes.pzOptFmt = zGnuOptFmt;     break;
  825:     case OPTPROC_LONGOPT:  argTypes.pzOptFmt = zGnuOptFmt;     break;
  826:     case 0:                argTypes.pzOptFmt = zGnuOptFmt + 2; break;
  827:     case OPTPROC_SHORTOPT:
  828:         argTypes.pzOptFmt = zShrtGnuOptFmt;
  829:         zGnuStrArg[0] = zGnuNumArg[0] = zGnuKeyArg[0] = zGnuBoolArg[0] = ' ';
  830:         argTypes.pzOpt = " [arg]";
  831:         flen = 8;
  832:         break;
  833:     }
  834: 
  835:     return flen;
  836: }
  837: 
  838: 
  839: /*
  840:  *  Standard (AutoOpts normal) option line formatting
  841:  */
  842: static int
  843: setStdOptFmts(tOptions* pOpts, tCC** ppT)
  844: {
  845:     int  flen = 0;
  846: 
  847:     argTypes.pzStr  = zStdStrArg;
  848:     argTypes.pzReq  = zStdReqArg;
  849:     argTypes.pzNum  = zStdNumArg;
  850:     argTypes.pzKey  = zStdKeyArg;
  851:     argTypes.pzKeyL = zStdKeyLArg;
  852:     argTypes.pzTime = zStdTimeArg;
  853:     argTypes.pzFile = zStdFileArg;
  854:     argTypes.pzBool = zStdBoolArg;
  855:     argTypes.pzNest = zStdNestArg;
  856:     argTypes.pzOpt  = zStdOptArg;
  857:     argTypes.pzNo   = zStdNoArg;
  858:     argTypes.pzBrk  = zStdBreak;
  859:     argTypes.pzNoF  = zFiveSpaces;
  860:     argTypes.pzSpc  = zTwoSpaces;
  861: 
  862:     switch (pOpts->fOptSet & (OPTPROC_NO_REQ_OPT | OPTPROC_SHORTOPT)) {
  863:     case (OPTPROC_NO_REQ_OPT | OPTPROC_SHORTOPT):
  864:         *ppT = zNoRq_ShrtTtl;
  865:         argTypes.pzOptFmt = zNrmOptFmt;
  866:         flen = 19;
  867:         break;
  868: 
  869:     case OPTPROC_NO_REQ_OPT:
  870:         *ppT = zNoRq_NoShrtTtl;
  871:         argTypes.pzOptFmt = zNrmOptFmt;
  872:         flen = 19;
  873:         break;
  874: 
  875:     case OPTPROC_SHORTOPT:
  876:         *ppT = zReq_ShrtTtl;
  877:         argTypes.pzOptFmt = zReqOptFmt;
  878:         flen = 24;
  879:         break;
  880: 
  881:     case 0:
  882:         *ppT = zReq_NoShrtTtl;
  883:         argTypes.pzOptFmt = zReqOptFmt;
  884:         flen = 24;
  885:     }
  886: 
  887:     return flen;
  888: }
  889: 
  890: 
  891: /*:
  892:  * Local Variables:
  893:  * mode: C
  894:  * c-file-style: "stroustrup"
  895:  * indent-tabs-mode: nil
  896:  * End:
  897:  * end of autoopts/usage.c */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>