1 2 /* 3 * \file usage.c 4 * 5 * This module implements the default usage procedure for 6 * Automated Options. It may be overridden, of course. 7 * 8 * @addtogroup autoopts 9 * @{ 10 */ 11 /* 12 * Sort options: 13 --start=END-[S]TATIC-FORWARD --patt='^/\*($|[^:])' \ 14 --out=xx.c key='^[a-zA-Z0-9_]+\(' --trail='^/\*:' \ 15 --spac=2 --input=usage.c 16 */ 17 18 /* 19 * This file is part of AutoOpts, a companion to AutoGen. 20 * AutoOpts is free software. 21 * AutoOpts is Copyright (C) 1992-2018 by Bruce Korb - all rights reserved 22 * 23 * AutoOpts is available under any one of two licenses. The license 24 * in use must be one of these two and the choice is under the control 25 * of the user of the license. 26 * 27 * The GNU Lesser General Public License, version 3 or later 28 * See the files "COPYING.lgplv3" and "COPYING.gplv3" 29 * 30 * The Modified Berkeley Software Distribution License 31 * See the file "COPYING.mbsd" 32 * 33 * These files have the following sha256 sums: 34 * 35 * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3 36 * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3 37 * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd 38 */ 39 40 #define GRAPH_CH(_ch) \ 41 ((((unsigned)_ch) <= 0x7E) && (((unsigned)_ch) > ' ')) 42 43 /** 44 * Parse the option usage flags string. Any parsing problems yield 45 * a zero (no flags set) result. This function is internal to 46 * set_usage_flags(). 47 * 48 * @param[in] fnt Flag Name Table - maps a name to a mask 49 * @param[in] txt the text to process. If NULL, then 50 * getenv("AUTOOPTS_USAGE") is used. 51 * @returns a bit mask indicating which \a fnt entries were found. 52 */ 53 static unsigned int 54 parse_usage_flags(ao_flag_names_t const * fnt, char const * txt) 55 { 56 unsigned int res = 0; 57 58 /* 59 * The text may be passed in. If not, use the environment variable. 60 */ 61 if (txt == NULL) { 62 txt = getenv("AUTOOPTS_USAGE"); 63 if (txt == NULL) 64 return 0; 65 } 66 67 txt = SPN_WHITESPACE_CHARS(txt); 68 if (*txt == NUL) 69 return 0; 70 71 /* 72 * search the string for table entries. We must understand everything 73 * we see in the string, or we give up on it. 74 */ 75 for (;;) { 76 int ix = 0; 77 78 for (;;) { 79 if (strneqvcmp(txt, fnt[ix].fnm_name, (int)fnt[ix].fnm_len) == 0) 80 break; 81 if (++ix >= AOUF_COUNT) 82 return 0; 83 } 84 85 /* 86 * Make sure we have a full match. Look for whitespace, 87 * a comma, or a NUL byte. 88 */ 89 if (! IS_END_LIST_ENTRY_CHAR(txt[fnt[ix].fnm_len])) 90 return 0; 91 92 res |= 1U << ix; 93 txt = SPN_WHITESPACE_CHARS(txt + fnt[ix].fnm_len); 94 95 switch (*txt) { 96 case NUL: 97 return res; 98 99 case ',': 100 txt = SPN_WHITESPACE_CHARS(txt + 1); 101 /* Something must follow the comma */ 102 /* FALLTHROUGH */ 103 104 default: 105 continue; 106 } 107 } 108 } 109 110 /** 111 * Set option usage flags. Any parsing problems yield no changes to options. 112 * Three different bits may be fiddled: \a OPTPROC_GNUUSAGE, \a OPTPROC_MISUSE 113 * and \a OPTPROC_COMPUTE. 114 * 115 * @param[in] flg_txt text to parse. If NULL, then the AUTOOPTS_USAGE 116 * environment variable is parsed. 117 * @param[in,out] opts the program option descriptor 118 */ 119 static void 120 set_usage_flags(tOptions * opts, char const * flg_txt) 121 { 122 # define _aof_(_n, _f) { sizeof(#_n)-1, _f, #_n }, 123 static ao_flag_names_t const fn_table[AOUF_COUNT] = { 124 AOFLAG_TABLE 125 }; 126 # undef _aof_ 127 128 /* 129 * the flag word holds a bit for each selected table entry. 130 */ 131 unsigned int flg = parse_usage_flags(fn_table, flg_txt); 132 if (flg == 0) return; 133 134 /* 135 * Ensure we do not have conflicting selections 136 */ 137 { 138 static unsigned int const form_mask = 139 AOUF_gnu | AOUF_autoopts; 140 static unsigned int const misuse_mask = 141 AOUF_no_misuse_usage | AOUF_misuse_usage; 142 if ( ((flg & form_mask) == form_mask) 143 || ((flg & misuse_mask) == misuse_mask) ) 144 return; 145 } 146 147 /* 148 * Now fiddle the fOptSet bits, based on settings. 149 * The OPTPROC_LONGOPT bit is immutable, thus if it is set, 150 * then fnm points to a mask off mask. 151 */ 152 { 153 ao_flag_names_t const * fnm = fn_table; 154 for (;;) { 155 if ((flg & 1) != 0) { 156 if ((fnm->fnm_mask & OPTPROC_LONGOPT) != 0) 157 opts->fOptSet &= fnm->fnm_mask; 158 else opts->fOptSet |= fnm->fnm_mask; 159 } 160 flg >>= 1; 161 if (flg == 0) 162 break; 163 fnm++; 164 } 165 } 166 } 167 168 /* 169 * Figure out if we should try to format usage text sort-of like 170 * the way many GNU programs do. 171 */ 172 static inline bool 173 do_gnu_usage(tOptions * pOpts) 174 { 175 return (pOpts->fOptSet & OPTPROC_GNUUSAGE) ? true : false; 176 } 177 178 /* 179 * Figure out if we should try to format usage text sort-of like 180 * the way many GNU programs do. 181 */ 182 static inline bool 183 skip_misuse_usage(tOptions * pOpts) 184 { 185 return (pOpts->fOptSet & OPTPROC_MISUSE) ? true : false; 186 } 187 188 189 /*=export_func optionOnlyUsage 190 * 191 * what: Print usage text for just the options 192 * arg: + tOptions * + pOpts + program options descriptor + 193 * arg: + int + ex_code + exit code for calling exit(3) + 194 * 195 * doc: 196 * This routine will print only the usage for each option. 197 * This function may be used when the emitted usage must incorporate 198 * information not available to AutoOpts. 199 =*/ 200 void 201 optionOnlyUsage(tOptions * pOpts, int ex_code) 202 { 203 char const * pOptTitle = NULL; 204 205 set_usage_flags(pOpts, NULL); 206 if ((ex_code != EXIT_SUCCESS) && 207 skip_misuse_usage(pOpts)) 208 return; 209 210 /* 211 * Determine which header and which option formatting strings to use 212 */ 213 if (do_gnu_usage(pOpts)) 214 (void)setGnuOptFmts(pOpts, &pOptTitle); 215 else 216 (void)setStdOptFmts(pOpts, &pOptTitle); 217 218 prt_opt_usage(pOpts, ex_code, pOptTitle); 219 220 fflush(option_usage_fp); 221 if (ferror(option_usage_fp) != 0) 222 fserr_exit(pOpts->pzProgName, zwriting, (option_usage_fp == stderr) 223 ? zstderr_name : zstdout_name); 224 } 225 226 /** 227 * Print a message suggesting how to get help. 228 * 229 * @param[in] opts the program options 230 */ 231 static void 232 print_offer_usage(tOptions * opts) 233 { 234 char help[24]; 235 236 if (HAS_opt_usage_t(opts)) { 237 int ix = opts->presetOptCt; 238 tOptDesc * od = opts->pOptDesc + ix; 239 while (od->optUsage != AOUSE_HELP) { 240 if (++ix >= opts->optCt) 241 ao_bug(zmissing_help_msg); 242 od++; 243 } 244 switch (opts->fOptSet & (OPTPROC_LONGOPT | OPTPROC_SHORTOPT)) { 245 case OPTPROC_SHORTOPT: 246 help[0] = '-'; 247 help[1] = od->optValue; 248 help[2] = NUL; 249 break; 250 251 case OPTPROC_LONGOPT: 252 case (OPTPROC_LONGOPT | OPTPROC_SHORTOPT): 253 help[0] = help[1] = '-'; 254 strncpy(help + 2, od->pz_Name, 20); 255 break; 256 257 case 0: 258 strncpy(help, od->pz_Name, 20); 259 break; 260 } 261 262 } else { 263 switch (opts->fOptSet & (OPTPROC_LONGOPT | OPTPROC_SHORTOPT)) { 264 case OPTPROC_SHORTOPT: 265 strcpy(help, "-h"); 266 break; 267 268 case OPTPROC_LONGOPT: 269 case (OPTPROC_LONGOPT | OPTPROC_SHORTOPT): 270 strcpy(help, "--help"); 271 break; 272 273 case 0: 274 strcpy(help, "help"); 275 break; 276 } 277 } 278 279 fprintf(option_usage_fp, zoffer_usage_fmt, opts->pzProgName, help); 280 } 281 282 /** 283 * Print information about each option. 284 * 285 * @param[in] opts the program options 286 * @param[in] exit_code whether or not there was a usage error reported. 287 * used to select full usage versus abbreviated. 288 */ 289 static void 290 print_usage_details(tOptions * opts, int exit_code) 291 { 292 { 293 char const * pOptTitle = NULL; 294 int flen; 295 296 /* 297 * Determine which header and which option formatting strings to use 298 */ 299 if (do_gnu_usage(opts)) { 300 flen = setGnuOptFmts(opts, &pOptTitle); 301 sprintf(line_fmt_buf, zFmtFmt, flen); 302 fputc(NL, option_usage_fp); 303 304 } else { 305 flen = setStdOptFmts(opts, &pOptTitle); 306 sprintf(line_fmt_buf, zFmtFmt, flen); 307 308 /* 309 * When we exit with EXIT_SUCCESS and the first option is a doc 310 * option, we do *NOT* want to emit the column headers. 311 * Otherwise, we do. 312 */ 313 if ( (exit_code != EXIT_SUCCESS) 314 || ((opts->pOptDesc->fOptState & OPTST_DOCUMENT) == 0) ) 315 316 fputs(pOptTitle, option_usage_fp); 317 } 318 319 flen = 4 - ((flen + 15) / 8); 320 if (flen > 0) 321 tab_skip_ct = flen; 322 prt_opt_usage(opts, exit_code, pOptTitle); 323 } 324 325 /* 326 * Describe the mechanics of denoting the options 327 */ 328 switch (opts->fOptSet & OPTPROC_L_N_S) { 329 case OPTPROC_L_N_S: fputs(zFlagOkay, option_usage_fp); break; 330 case OPTPROC_SHORTOPT: break; 331 case OPTPROC_LONGOPT: fputs(zNoFlags, option_usage_fp); break; 332 case 0: fputs(zOptsOnly, option_usage_fp); break; 333 } 334 335 if ((opts->fOptSet & OPTPROC_NUM_OPT) != 0) 336 fputs(zNumberOpt, option_usage_fp); 337 338 if ((opts->fOptSet & OPTPROC_REORDER) != 0) 339 fputs(zReorder, option_usage_fp); 340 341 if (opts->pzExplain != NULL) 342 fputs(opts->pzExplain, option_usage_fp); 343 344 /* 345 * IF the user is asking for help (thus exiting with SUCCESS), 346 * THEN see what additional information we can provide. 347 */ 348 if (exit_code == EXIT_SUCCESS) 349 prt_prog_detail(opts); 350 351 /* 352 * Give bug notification preference to the packager information 353 */ 354 if (HAS_pzPkgDataDir(opts) && (opts->pzPackager != NULL)) 355 fputs(opts->pzPackager, option_usage_fp); 356 357 else if (opts->pzBugAddr != NULL) 358 fprintf(option_usage_fp, zPlsSendBugs, opts->pzBugAddr); 359 360 fflush(option_usage_fp); 361 362 if (ferror(option_usage_fp) != 0) 363 fserr_exit(opts->pzProgName, zwriting, (option_usage_fp == stderr) 364 ? zstderr_name : zstdout_name); 365 } 366 367 static void 368 print_one_paragraph(char const * text, bool plain, FILE * fp) 369 { 370 if (plain) { 371 #ifdef ENABLE_NLS 372 #ifdef HAVE_LIBINTL_H 373 #ifdef DEBUG_ENABLED 374 #undef gettext 375 #endif 376 char * buf = dgettext("libopts", text); 377 if (buf == text) 378 text = gettext(text); 379 #endif /* HAVE_LIBINTL_H */ 380 #endif /* ENABLE_NLS */ 381 fputs(text, fp); 382 } 383 384 else { 385 char const * t = optionQuoteString(text, LINE_SPLICE); 386 fprintf(fp, PUTS_FMT, t); 387 AGFREE(t); 388 } 389 } 390 391 /*=export_func optionPrintParagraphs 392 * private: 393 * 394 * what: Print a paragraph of usage text 395 * arg: + char const * + text + a block of text that has bee i18n-ed + 396 * arg: + bool + plain + false -> wrap text in fputs() + 397 * arg: + FILE * + fp + the stream file pointer for output + 398 * 399 * doc: 400 * This procedure is called in two contexts: when a full or short usage text 401 * has been provided for display, and when autogen is assembling a list of 402 * translatable texts in the optmain.tlib template. In the former case, \a 403 * plain is set to \a true, otherwise \a false. 404 * 405 * Anything less than 256 characters in size is printed as a single unit. 406 * Otherwise, paragraphs are detected. A paragraph break is defined as just 407 * before a non-empty line preceded by two newlines or a line that starts 408 * with at least one space character but fewer than 8 space characters. 409 * Lines indented with tabs or more than 7 spaces are considered continuation 410 * lines. 411 * 412 * If 'plain' is true, we are emitting text for a user to see. So, if it is 413 * true and NLS is not enabled, then just write the whole thing at once. 414 =*/ 415 void 416 optionPrintParagraphs(char const * text, bool plain, FILE * fp) 417 { 418 size_t len = strlen(text); 419 char * buf; 420 #ifndef ENABLE_NLS 421 if (plain || (len < 256)) 422 #else 423 if (len < 256) 424 #endif 425 { 426 print_one_paragraph(text, plain, fp); 427 return; 428 } 429 430 AGDUPSTR(buf, text, "ppara"); 431 text = buf; 432 433 for (;;) { 434 char * scan; 435 436 if (len < 256) { 437 done: 438 print_one_paragraph(buf, plain, fp); 439 break; 440 } 441 scan = buf; 442 443 try_longer: 444 scan = strchr(scan, NL); 445 if (scan == NULL) 446 goto done; 447 448 if ((scan - buf) < 40) { 449 scan++; 450 goto try_longer; 451 } 452 453 scan++; 454 if ((! isspace((int)*scan)) || (*scan == HT)) 455 /* 456 * line starts with tab or non-whitespace --> continuation 457 */ 458 goto try_longer; 459 460 if (*scan == NL) { 461 /* 462 * Double newline -> paragraph break 463 * Include all newlines in current paragraph. 464 */ 465 while (*++scan == NL) /*continue*/; 466 467 } else { 468 char * p = scan; 469 int sp_ct = 0; 470 471 while (*p == ' ') { 472 if (++sp_ct >= 8) { 473 /* 474 * Too many spaces --> continuation line 475 */ 476 scan = p; 477 goto try_longer; 478 } 479 p++; 480 } 481 } 482 483 /* 484 * "scan" points to the first character of a paragraph or the 485 * terminating NUL byte. 486 */ 487 { 488 char svch = *scan; 489 *scan = NUL; 490 print_one_paragraph(buf, plain, fp); 491 len -= scan - buf; 492 if (len <= 0) 493 break; 494 *scan = svch; 495 buf = scan; 496 } 497 } 498 AGFREE(text); 499 } 500 501 /*=export_func optionUsage 502 * private: 503 * 504 * what: Print usage text 505 * arg: + tOptions * + opts + program options descriptor + 506 * arg: + int + exitCode + exit code for calling exit(3) + 507 * 508 * doc: 509 * This routine will print usage in both GNU-standard and AutoOpts-expanded 510 * formats. The descriptor specifies the default, but AUTOOPTS_USAGE will 511 * over-ride this, providing the value of it is set to either "gnu" or 512 * "autoopts". This routine will @strong{not} return. 513 * 514 * If "exitCode" is "AO_EXIT_REQ_USAGE" (normally 64), then output will to 515 * to stdout and the actual exit code will be "EXIT_SUCCESS". 516 =*/ 517 lo_noreturn void 518 optionUsage(tOptions * opts, int usage_exit_code) 519 { 520 int exit_code = (usage_exit_code == AO_EXIT_REQ_USAGE) 521 ? EXIT_SUCCESS : usage_exit_code; 522 523 displayEnum = false; 524 set_usage_flags(opts, NULL); 525 526 /* 527 * Paged usage will preset option_usage_fp to an output file. 528 * If it hasn't already been set, then set it to standard output 529 * on successful exit (help was requested), otherwise error out. 530 * 531 * Test the version before obtaining pzFullUsage or pzShortUsage. 532 * These fields do not exist before revision 30. 533 */ 534 { 535 char const * pz; 536 537 if (exit_code == EXIT_SUCCESS) { 538 pz = (opts->structVersion >= 30 * 4096) 539 ? opts->pzFullUsage : NULL; 540 541 if (option_usage_fp == NULL) 542 option_usage_fp = print_exit ? stderr : stdout; 543 544 } else { 545 pz = (opts->structVersion >= 30 * 4096) 546 ? opts->pzShortUsage : NULL; 547 548 if (option_usage_fp == NULL) 549 option_usage_fp = stderr; 550 } 551 552 if (((opts->fOptSet & OPTPROC_COMPUTE) == 0) && (pz != NULL)) { 553 if ((opts->fOptSet & OPTPROC_TRANSLATE) != 0) 554 optionPrintParagraphs(pz, true, option_usage_fp); 555 else 556 fputs(pz, option_usage_fp); 557 goto flush_and_exit; 558 } 559 } 560 561 fprintf(option_usage_fp, opts->pzUsageTitle, opts->pzProgName); 562 563 if ((exit_code == EXIT_SUCCESS) || 564 (! skip_misuse_usage(opts))) 565 566 print_usage_details(opts, usage_exit_code); 567 else 568 print_offer_usage(opts); 569 570 flush_and_exit: 571 fflush(option_usage_fp); 572 if (ferror(option_usage_fp) != 0) 573 fserr_exit(opts->pzProgName, zwriting, (option_usage_fp == stdout) 574 ? zstdout_name : zstderr_name); 575 576 option_exits(exit_code); 577 } 578 579 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 580 * PER OPTION TYPE USAGE INFORMATION 581 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 582 /** 583 * print option conflicts. 584 * 585 * @param opts the program option descriptor 586 * @param od the option descriptor 587 */ 588 static void 589 prt_conflicts(tOptions * opts, tOptDesc * od) 590 { 591 const int * opt_no; 592 fputs(zTabHyp + tab_skip_ct, option_usage_fp); 593 594 /* 595 * REQUIRED: 596 */ 597 if (od->pOptMust != NULL) { 598 opt_no = od->pOptMust; 599 600 if (opt_no[1] == NO_EQUIVALENT) { 601 fprintf(option_usage_fp, zReqOne, 602 opts->pOptDesc[*opt_no].pz_Name); 603 } else { 604 fputs(zReqThese, option_usage_fp); 605 for (;;) { 606 fprintf(option_usage_fp, zTabout + tab_skip_ct, 607 opts->pOptDesc[*opt_no].pz_Name); 608 if (*++opt_no == NO_EQUIVALENT) 609 break; 610 } 611 } 612 613 if (od->pOptCant != NULL) 614 fputs(zTabHypAnd + tab_skip_ct, option_usage_fp); 615 } 616 617 /* 618 * CONFLICTS: 619 */ 620 if (od->pOptCant == NULL) 621 return; 622 623 opt_no = od->pOptCant; 624 625 if (opt_no[1] == NO_EQUIVALENT) { 626 fprintf(option_usage_fp, zProhibOne, 627 opts->pOptDesc[*opt_no].pz_Name); 628 return; 629 } 630 631 fputs(zProhib, option_usage_fp); 632 for (;;) { 633 fprintf(option_usage_fp, zTabout + tab_skip_ct, 634 opts->pOptDesc[*opt_no].pz_Name); 635 if (*++opt_no == NO_EQUIVALENT) 636 break; 637 } 638 } 639 640 /** 641 * Print the usage information for a single vendor option. 642 * 643 * @param[in] opts the program option descriptor 644 * @param[in] od the option descriptor 645 * @param[in] argtp names of the option argument types 646 * @param[in] usefmt format for primary usage line 647 */ 648 static void 649 prt_one_vendor(tOptions * opts, tOptDesc * od, 650 arg_types_t * argtp, char const * usefmt) 651 { 652 prt_preamble(opts, od, argtp); 653 654 { 655 char z[ 80 ]; 656 char const * pzArgType; 657 658 /* 659 * Determine the argument type string first on its usage, then, 660 * when the option argument is required, base the type string on the 661 * argument type. 662 */ 663 if (od->fOptState & OPTST_ARG_OPTIONAL) { 664 pzArgType = argtp->pzOpt; 665 666 } else switch (OPTST_GET_ARGTYPE(od->fOptState)) { 667 case OPARG_TYPE_NONE: pzArgType = argtp->pzNo; break; 668 case OPARG_TYPE_ENUMERATION: pzArgType = argtp->pzKey; break; 669 case OPARG_TYPE_FILE: pzArgType = argtp->pzFile; break; 670 case OPARG_TYPE_MEMBERSHIP: pzArgType = argtp->pzKeyL; break; 671 case OPARG_TYPE_BOOLEAN: pzArgType = argtp->pzBool; break; 672 case OPARG_TYPE_NUMERIC: pzArgType = argtp->pzNum; break; 673 case OPARG_TYPE_HIERARCHY: pzArgType = argtp->pzNest; break; 674 case OPARG_TYPE_STRING: pzArgType = argtp->pzStr; break; 675 case OPARG_TYPE_TIME: pzArgType = argtp->pzTime; break; 676 default: goto bogus_desc; 677 } 678 679 pzArgType = SPN_WHITESPACE_CHARS(pzArgType); 680 if (*pzArgType == NUL) 681 snprintf(z, sizeof(z), "%s", od->pz_Name); 682 else 683 snprintf(z, sizeof(z), "%s=%s", od->pz_Name, pzArgType); 684 fprintf(option_usage_fp, usefmt, z, od->pzText); 685 686 switch (OPTST_GET_ARGTYPE(od->fOptState)) { 687 case OPARG_TYPE_ENUMERATION: 688 case OPARG_TYPE_MEMBERSHIP: 689 displayEnum = (od->pOptProc != NULL) ? true : displayEnum; 690 } 691 } 692 693 return; 694 695 bogus_desc: 696 fprintf(stderr, zbad_od, opts->pzProgName, od->pz_Name); 697 ao_bug(zbad_arg_type_msg); 698 } 699 700 /** 701 * Print the long options processed with "-W". These options will be the 702 * ones that do *not* have flag characters. 703 * 704 * @param opts the program option descriptor 705 * @param title the title for the options 706 */ 707 static void 708 prt_vendor_opts(tOptions * opts, char const * title) 709 { 710 static unsigned int const not_vended_mask = 711 OPTST_NO_USAGE_MASK | OPTST_DOCUMENT; 712 713 static char const vfmtfmt[] = "%%-%us %%s\n"; 714 char vfmt[sizeof(vfmtfmt)]; 715 716 /* 717 * Only handle client specified options. The "vendor option" follows 718 * "presetOptCt", so we won't loop/recurse indefinitely. 719 */ 720 int ct = opts->presetOptCt; 721 tOptDesc * od = opts->pOptDesc; 722 fprintf(option_usage_fp, zTabout + tab_skip_ct, zVendOptsAre); 723 724 { 725 size_t nmlen = 0; 726 do { 727 size_t l; 728 if ( ((od->fOptState & not_vended_mask) != 0) 729 || GRAPH_CH(od->optValue)) 730 continue; 731 732 l = strlen(od->pz_Name); 733 if (l > nmlen) nmlen = l; 734 } while (od++, (--ct > 0)); 735 736 snprintf(vfmt, sizeof(vfmt), vfmtfmt, (unsigned int)nmlen + 4); 737 } 738 739 if (tab_skip_ct > 0) 740 tab_skip_ct--; 741 742 ct = opts->presetOptCt; 743 od = opts->pOptDesc; 744 745 do { 746 if ( ((od->fOptState & not_vended_mask) != 0) 747 || GRAPH_CH(od->optValue)) 748 continue; 749 750 prt_one_vendor(opts, od, &argTypes, vfmt); 751 prt_extd_usage(opts, od, title); 752 753 } while (od++, (--ct > 0)); 754 755 /* no need to restore "tab_skip_ct" - options are done now */ 756 } 757 758 /** 759 * Print extended usage. Usage/help was requested. 760 * 761 * @param opts the program option descriptor 762 * @param od the option descriptor 763 * @param title the title for the options 764 */ 765 static void 766 prt_extd_usage(tOptions * opts, tOptDesc * od, char const * title) 767 { 768 if ( ((opts->fOptSet & OPTPROC_VENDOR_OPT) != 0) 769 && (od->optActualValue == VENDOR_OPTION_VALUE)) { 770 prt_vendor_opts(opts, title); 771 return; 772 } 773 774 /* 775 * IF there are option conflicts or dependencies, 776 * THEN print them here. 777 */ 778 if ((od->pOptMust != NULL) || (od->pOptCant != NULL)) 779 prt_conflicts(opts, od); 780 781 /* 782 * IF there is a disablement string 783 * THEN print the disablement info 784 */ 785 if (od->pz_DisableName != NULL ) 786 fprintf(option_usage_fp, zDis + tab_skip_ct, od->pz_DisableName); 787 788 /* 789 * Check for argument types that have callbacks with magical properties 790 */ 791 switch (OPTST_GET_ARGTYPE(od->fOptState)) { 792 case OPARG_TYPE_NUMERIC: 793 /* 794 * IF the numeric option has a special callback, 795 * THEN call it, requesting the range or other special info 796 */ 797 if ( (od->pOptProc != NULL) 798 && (od->pOptProc != optionNumericVal) ) { 799 (*(od->pOptProc))(OPTPROC_EMIT_USAGE, od); 800 } 801 break; 802 803 case OPARG_TYPE_FILE: 804 (*(od->pOptProc))(OPTPROC_EMIT_USAGE, od); 805 break; 806 } 807 808 /* 809 * IF the option defaults to being enabled, 810 * THEN print that out 811 */ 812 if (od->fOptState & OPTST_INITENABLED) 813 fputs(zEnab + tab_skip_ct, option_usage_fp); 814 815 /* 816 * IF the option is in an equivalence class 817 * AND not the designated lead 818 * THEN print equivalence and leave it at that. 819 */ 820 if ( (od->optEquivIndex != NO_EQUIVALENT) 821 && (od->optEquivIndex != od->optActualIndex ) ) { 822 fprintf(option_usage_fp, zalt_opt + tab_skip_ct, 823 opts->pOptDesc[ od->optEquivIndex ].pz_Name); 824 return; 825 } 826 827 /* 828 * IF this particular option can NOT be preset 829 * AND some form of presetting IS allowed, 830 * AND it is not an auto-managed option (e.g. --help, et al.) 831 * THEN advise that this option may not be preset. 832 */ 833 if ( ((od->fOptState & OPTST_NO_INIT) != 0) 834 && ( (opts->papzHomeList != NULL) 835 || (opts->pzPROGNAME != NULL) 836 ) 837 && (od->optIndex < opts->presetOptCt) 838 ) 839 840 fputs(zNoPreset + tab_skip_ct, option_usage_fp); 841 842 /* 843 * Print the appearance requirements. 844 */ 845 if (OPTST_GET_ARGTYPE(od->fOptState) == OPARG_TYPE_MEMBERSHIP) 846 fputs(zMembers + tab_skip_ct, option_usage_fp); 847 848 else switch (od->optMinCt) { 849 case 1: 850 case 0: 851 switch (od->optMaxCt) { 852 case 0: fputs(zPreset + tab_skip_ct, option_usage_fp); break; 853 case NOLIMIT: fputs(zNoLim + tab_skip_ct, option_usage_fp); break; 854 case 1: break; 855 /* 856 * IF the max is more than one but limited, print "UP TO" message 857 */ 858 default: 859 fprintf(option_usage_fp, zUpTo + tab_skip_ct, od->optMaxCt); break; 860 } 861 break; 862 863 default: 864 /* 865 * More than one is required. Print the range. 866 */ 867 fprintf(option_usage_fp, zMust + tab_skip_ct, 868 od->optMinCt, od->optMaxCt); 869 } 870 871 if ( NAMED_OPTS(opts) 872 && (opts->specOptIdx.default_opt == od->optIndex)) 873 fputs(zDefaultOpt + tab_skip_ct, option_usage_fp); 874 } 875 876 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 877 /** 878 * Figure out where all the initialization files might live. This requires 879 * translating some environment variables and testing to see if a name is a 880 * directory or a file. It's squishy, but important to tell users how to 881 * find these files. 882 * 883 * @param[in] papz search path 884 * @param[out] ini_file an output buffer of AG_PATH_MAX+1 bytes 885 * @param[in] path_nm the name of the file we're hunting for 886 */ 887 static void 888 prt_ini_list(char const * const * papz, char const * ini_file, 889 char const * path_nm) 890 { 891 char pth_buf[AG_PATH_MAX+1]; 892 893 fputs(zPresetIntro, option_usage_fp); 894 895 for (;;) { 896 char const * path = *(papz++); 897 char const * nm_buf = pth_buf; 898 899 if (path == NULL) 900 break; 901 902 /* 903 * Ignore any invalid paths 904 */ 905 if (! optionMakePath(pth_buf, (int)sizeof(pth_buf), path, path_nm)) 906 nm_buf = path; 907 908 /* 909 * Expand paths that are relative to the executable or installation 910 * directories. Leave alone paths that use environment variables. 911 */ 912 else if ((*path == '$') 913 && ((path[1] == '$') || (path[1] == '@'))) 914 path = nm_buf; 915 916 /* 917 * Print the name of the "homerc" file. If the "rcfile" name is 918 * not empty, we may or may not print that, too... 919 */ 920 fprintf(option_usage_fp, zPathFmt, path); 921 if (*ini_file != NUL) { 922 struct stat sb; 923 924 /* 925 * IF the "homerc" file is a directory, 926 * then append the "rcfile" name. 927 */ 928 if ((stat(nm_buf, &sb) == 0) && S_ISDIR(sb.st_mode)) { 929 fputc(DIRCH, option_usage_fp); 930 fputs(ini_file, option_usage_fp); 931 } 932 } 933 934 fputc(NL, option_usage_fp); 935 } 936 } 937 938 /** 939 * Print the usage line preamble text 940 * 941 * @param opts the program option descriptor 942 * @param od the option descriptor 943 * @param at names of the option argument types 944 */ 945 static void 946 prt_preamble(tOptions * opts, tOptDesc * od, arg_types_t * at) 947 { 948 /* 949 * Flag prefix: IF no flags at all, then omit it. If not printable 950 * (not allowed for this option), then blank, else print it. 951 * Follow it with a comma if we are doing GNU usage and long 952 * opts are to be printed too. 953 */ 954 if ((opts->fOptSet & OPTPROC_SHORTOPT) == 0) 955 fputs(at->pzSpc, option_usage_fp); 956 957 else if (! GRAPH_CH(od->optValue)) { 958 if ( (opts->fOptSet & (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT)) 959 == (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT)) 960 fputc(' ', option_usage_fp); 961 fputs(at->pzNoF, option_usage_fp); 962 963 } else { 964 fprintf(option_usage_fp, " -%c", od->optValue); 965 if ( (opts->fOptSet & (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT)) 966 == (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT)) 967 fputs(", ", option_usage_fp); 968 } 969 } 970 971 /** 972 * Print the usage information for a single option. 973 * 974 * @param opts the program option descriptor 975 * @param od the option descriptor 976 * @param at names of the option argument types 977 */ 978 static void 979 prt_one_usage(tOptions * opts, tOptDesc * od, arg_types_t * at) 980 { 981 prt_preamble(opts, od, at); 982 983 { 984 char z[80]; 985 char const * atyp; 986 987 /* 988 * Determine the argument type string first on its usage, then, 989 * when the option argument is required, base the type string on the 990 * argument type. 991 */ 992 if (od->fOptState & OPTST_ARG_OPTIONAL) { 993 atyp = at->pzOpt; 994 995 } else switch (OPTST_GET_ARGTYPE(od->fOptState)) { 996 case OPARG_TYPE_NONE: atyp = at->pzNo; break; 997 case OPARG_TYPE_ENUMERATION: atyp = at->pzKey; break; 998 case OPARG_TYPE_FILE: atyp = at->pzFile; break; 999 case OPARG_TYPE_MEMBERSHIP: atyp = at->pzKeyL; break; 1000 case OPARG_TYPE_BOOLEAN: atyp = at->pzBool; break; 1001 case OPARG_TYPE_NUMERIC: atyp = at->pzNum; break; 1002 case OPARG_TYPE_HIERARCHY: atyp = at->pzNest; break; 1003 case OPARG_TYPE_STRING: atyp = at->pzStr; break; 1004 case OPARG_TYPE_TIME: atyp = at->pzTime; break; 1005 default: goto bogus_desc; 1006 } 1007 1008 #ifdef _WIN32 1009 if (at->pzOptFmt == zGnuOptFmt) 1010 snprintf(z, sizeof(z), "--%s%s", od->pz_Name, atyp); 1011 else if (at->pzOptFmt == zGnuOptFmt + 2) 1012 snprintf(z, sizeof(z), "%s%s", od->pz_Name, atyp); 1013 else 1014 #endif 1015 snprintf(z, sizeof(z), at->pzOptFmt, atyp, od->pz_Name, 1016 (od->optMinCt != 0) ? at->pzReq : at->pzOpt); 1017 1018 fprintf(option_usage_fp, line_fmt_buf, z, od->pzText); 1019 1020 switch (OPTST_GET_ARGTYPE(od->fOptState)) { 1021 case OPARG_TYPE_ENUMERATION: 1022 case OPARG_TYPE_MEMBERSHIP: 1023 displayEnum = (od->pOptProc != NULL) ? true : displayEnum; 1024 } 1025 } 1026 1027 return; 1028 1029 bogus_desc: 1030 fprintf(stderr, zbad_od, opts->pzProgName, od->pz_Name); 1031 option_exits(EX_SOFTWARE); 1032 } 1033 1034 /** 1035 * Print out the usage information for just the options. 1036 */ 1037 static void 1038 prt_opt_usage(tOptions * opts, int ex_code, char const * title) 1039 { 1040 int ct = opts->optCt; 1041 int optNo = 0; 1042 tOptDesc * od = opts->pOptDesc; 1043 int docCt = 0; 1044 1045 do { 1046 /* 1047 * no usage --> disallowed on command line (OPTST_NO_COMMAND), or 1048 * deprecated -- strongly discouraged (OPTST_DEPRECATED), or 1049 * compiled out of current object code (OPTST_OMITTED) 1050 */ 1051 if ((od->fOptState & OPTST_NO_USAGE_MASK) != 0) { 1052 1053 /* 1054 * IF this is a compiled-out option 1055 * *AND* usage was requested with "omitted-usage" 1056 * *AND* this is NOT abbreviated usage 1057 * THEN display this option. 1058 */ 1059 if ( (od->fOptState == (OPTST_OMITTED | OPTST_NO_INIT)) 1060 && (od->pz_Name != NULL) 1061 && (ex_code == EXIT_SUCCESS)) { 1062 1063 char const * why_pz = 1064 (od->pzText == NULL) ? zDisabledWhy : od->pzText; 1065 prt_preamble(opts, od, &argTypes); 1066 fprintf(option_usage_fp, zDisabledOpt, od->pz_Name, why_pz); 1067 } 1068 1069 continue; 1070 } 1071 1072 if ((od->fOptState & OPTST_DOCUMENT) != 0) { 1073 if (ex_code == EXIT_SUCCESS) { 1074 fprintf(option_usage_fp, argTypes.pzBrk, od->pzText, 1075 title); 1076 docCt++; 1077 } 1078 1079 continue; 1080 } 1081 1082 /* Skip name only options when we have a vendor option */ 1083 if ( ((opts->fOptSet & OPTPROC_VENDOR_OPT) != 0) 1084 && (! GRAPH_CH(od->optValue))) 1085 continue; 1086 1087 /* 1088 * IF this is the first auto-opt maintained option 1089 * *AND* we are doing a full help 1090 * *AND* there are documentation options 1091 * *AND* the last one was not a doc option, 1092 * THEN document that the remaining options are not user opts 1093 */ 1094 if ((docCt > 0) && (ex_code == EXIT_SUCCESS)) { 1095 if (opts->presetOptCt == optNo) { 1096 if ((od[-1].fOptState & OPTST_DOCUMENT) == 0) 1097 fprintf(option_usage_fp, argTypes.pzBrk, zAuto, title); 1098 1099 } else if ((ct == 1) && 1100 (opts->fOptSet & OPTPROC_VENDOR_OPT)) 1101 fprintf(option_usage_fp, argTypes.pzBrk, zVendIntro, title); 1102 } 1103 1104 prt_one_usage(opts, od, &argTypes); 1105 1106 /* 1107 * IF we were invoked because of the --help option, 1108 * THEN print all the extra info 1109 */ 1110 if (ex_code == EXIT_SUCCESS) 1111 prt_extd_usage(opts, od, title); 1112 1113 } while (od++, optNo++, (--ct > 0)); 1114 1115 fputc(NL, option_usage_fp); 1116 } 1117 1118 1119 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 1120 /** 1121 * Print program details. 1122 * @param[in] opts the program option descriptor 1123 */ 1124 static void 1125 prt_prog_detail(tOptions * opts) 1126 { 1127 bool need_intro = (opts->papzHomeList == NULL); 1128 1129 /* 1130 * Display all the places we look for config files, if we have 1131 * a list of directories to search. 1132 */ 1133 if (! need_intro) 1134 prt_ini_list(opts->papzHomeList, opts->pzRcName, opts->pzProgPath); 1135 1136 /* 1137 * Let the user know about environment variable settings 1138 */ 1139 if ((opts->fOptSet & OPTPROC_ENVIRON) != 0) { 1140 if (need_intro) 1141 fputs(zPresetIntro, option_usage_fp); 1142 1143 fprintf(option_usage_fp, zExamineFmt, opts->pzPROGNAME); 1144 } 1145 1146 /* 1147 * IF we found an enumeration, 1148 * THEN hunt for it again. Call the handler proc with a NULL 1149 * option struct pointer. That tells it to display the keywords. 1150 */ 1151 if (displayEnum) { 1152 int ct = opts->optCt; 1153 int optNo = 0; 1154 tOptDesc * od = opts->pOptDesc; 1155 1156 fputc(NL, option_usage_fp); 1157 fflush(option_usage_fp); 1158 do { 1159 switch (OPTST_GET_ARGTYPE(od->fOptState)) { 1160 case OPARG_TYPE_ENUMERATION: 1161 case OPARG_TYPE_MEMBERSHIP: 1162 (*(od->pOptProc))(OPTPROC_EMIT_USAGE, od); 1163 } 1164 } while (od++, optNo++, (--ct > 0)); 1165 } 1166 1167 /* 1168 * If there is a detail string, now is the time for that. 1169 */ 1170 if (opts->pzDetail != NULL) 1171 fputs(opts->pzDetail, option_usage_fp); 1172 } 1173 1174 1175 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1176 * 1177 * OPTION LINE FORMATTING SETUP 1178 * 1179 * The "OptFmt" formats receive three arguments: 1180 * 1. the type of the option's argument 1181 * 2. the long name of the option 1182 * 3. "YES" or "no ", depending on whether or not the option must appear 1183 * on the command line. 1184 * These formats are used immediately after the option flag (if used) has 1185 * been printed. 1186 * 1187 * Set up the formatting for GNU-style output 1188 */ 1189 static int 1190 setGnuOptFmts(tOptions * opts, char const ** ptxt) 1191 { 1192 static char const zOneSpace[] = " "; 1193 int flen = 22; 1194 *ptxt = zNoRq_ShrtTtl; 1195 1196 argTypes.pzStr = zGnuStrArg; 1197 argTypes.pzReq = zOneSpace; 1198 argTypes.pzNum = zGnuNumArg; 1199 argTypes.pzKey = zGnuKeyArg; 1200 argTypes.pzKeyL = zGnuKeyLArg; 1201 argTypes.pzTime = zGnuTimeArg; 1202 argTypes.pzFile = zGnuFileArg; 1203 argTypes.pzBool = zGnuBoolArg; 1204 argTypes.pzNest = zGnuNestArg; 1205 argTypes.pzOpt = zGnuOptArg; 1206 argTypes.pzNo = zOneSpace; 1207 argTypes.pzBrk = zGnuBreak; 1208 argTypes.pzNoF = zSixSpaces; 1209 argTypes.pzSpc = zThreeSpaces; 1210 1211 switch (opts->fOptSet & OPTPROC_L_N_S) { 1212 case OPTPROC_L_N_S: argTypes.pzOptFmt = zGnuOptFmt; break; 1213 case OPTPROC_LONGOPT: argTypes.pzOptFmt = zGnuOptFmt; break; 1214 case 0: argTypes.pzOptFmt = zGnuOptFmt + 2; break; 1215 case OPTPROC_SHORTOPT: 1216 argTypes.pzOptFmt = zShrtGnuOptFmt; 1217 zGnuStrArg[0] = zGnuNumArg[0] = zGnuKeyArg[0] = zGnuBoolArg[0] = ' '; 1218 argTypes.pzOpt = " [arg]"; 1219 flen = 8; 1220 break; 1221 } 1222 1223 return flen; 1224 } 1225 1226 1227 /* 1228 * Standard (AutoOpts normal) option line formatting 1229 */ 1230 static int 1231 setStdOptFmts(tOptions * opts, char const ** ptxt) 1232 { 1233 int flen = 0; 1234 1235 argTypes.pzStr = zStdStrArg; 1236 argTypes.pzReq = zStdReqArg; 1237 argTypes.pzNum = zStdNumArg; 1238 argTypes.pzKey = zStdKeyArg; 1239 argTypes.pzKeyL = zStdKeyLArg; 1240 argTypes.pzTime = zStdTimeArg; 1241 argTypes.pzFile = zStdFileArg; 1242 argTypes.pzBool = zStdBoolArg; 1243 argTypes.pzNest = zStdNestArg; 1244 argTypes.pzOpt = zStdOptArg; 1245 argTypes.pzNo = zStdNoArg; 1246 argTypes.pzBrk = zStdBreak; 1247 argTypes.pzNoF = zFiveSpaces; 1248 argTypes.pzSpc = zTwoSpaces; 1249 1250 switch (opts->fOptSet & (OPTPROC_NO_REQ_OPT | OPTPROC_SHORTOPT)) { 1251 case (OPTPROC_NO_REQ_OPT | OPTPROC_SHORTOPT): 1252 *ptxt = zNoRq_ShrtTtl; 1253 argTypes.pzOptFmt = zNrmOptFmt; 1254 flen = 19; 1255 break; 1256 1257 case OPTPROC_NO_REQ_OPT: 1258 *ptxt = zNoRq_NoShrtTtl; 1259 argTypes.pzOptFmt = zNrmOptFmt; 1260 flen = 19; 1261 break; 1262 1263 case OPTPROC_SHORTOPT: 1264 *ptxt = zReq_ShrtTtl; 1265 argTypes.pzOptFmt = zReqOptFmt; 1266 flen = 24; 1267 break; 1268 1269 case 0: 1270 *ptxt = zReq_NoShrtTtl; 1271 argTypes.pzOptFmt = zReqOptFmt; 1272 flen = 24; 1273 } 1274 1275 return flen; 1276 } 1277 1278 /** @} 1279 * 1280 * Local Variables: 1281 * mode: C 1282 * c-file-style: "stroustrup" 1283 * indent-tabs-mode: nil 1284 * End: 1285 * end of autoopts/usage.c */ 1286