1181834Sroberto 2181834Sroberto/* 3290001Sglebius * \file usage.c 4181834Sroberto * 5181834Sroberto * This module implements the default usage procedure for 6181834Sroberto * Automated Options. It may be overridden, of course. 7181834Sroberto * 8290001Sglebius * @addtogroup autoopts 9290001Sglebius * @{ 10290001Sglebius */ 11290001Sglebius/* 12181834Sroberto * Sort options: 13181834Sroberto --start=END-[S]TATIC-FORWARD --patt='^/\*($|[^:])' \ 14181834Sroberto --out=xx.c key='^[a-zA-Z0-9_]+\(' --trail='^/\*:' \ 15181834Sroberto --spac=2 --input=usage.c 16181834Sroberto */ 17181834Sroberto 18181834Sroberto/* 19290001Sglebius * This file is part of AutoOpts, a companion to AutoGen. 20290001Sglebius * AutoOpts is free software. 21290001Sglebius * AutoOpts is Copyright (C) 1992-2015 by Bruce Korb - all rights reserved 22181834Sroberto * 23290001Sglebius * AutoOpts is available under any one of two licenses. The license 24290001Sglebius * in use must be one of these two and the choice is under the control 25290001Sglebius * of the user of the license. 26181834Sroberto * 27290001Sglebius * The GNU Lesser General Public License, version 3 or later 28290001Sglebius * See the files "COPYING.lgplv3" and "COPYING.gplv3" 29181834Sroberto * 30290001Sglebius * The Modified Berkeley Software Distribution License 31290001Sglebius * See the file "COPYING.mbsd" 32181834Sroberto * 33290001Sglebius * These files have the following sha256 sums: 34181834Sroberto * 35290001Sglebius * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3 36290001Sglebius * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3 37290001Sglebius * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd 38181834Sroberto */ 39181834Sroberto 40290001Sglebius/* = = = START-STATIC-FORWARD = = = */ 41290001Sglebiusstatic unsigned int 42290001Sglebiusparse_usage_flags(ao_flag_names_t const * fnt, char const * txt); 43181834Sroberto 44290001Sglebiusstatic inline bool 45290001Sglebiusdo_gnu_usage(tOptions * pOpts); 46181834Sroberto 47290001Sglebiusstatic inline bool 48290001Sglebiusskip_misuse_usage(tOptions * pOpts); 49181834Sroberto 50290001Sglebiusstatic void 51290001Sglebiusprint_offer_usage(tOptions * opts); 52181834Sroberto 53181834Srobertostatic void 54290001Sglebiusprint_usage_details(tOptions * opts, int exit_code); 55181834Sroberto 56181834Srobertostatic void 57290001Sglebiusprint_one_paragraph(char const * text, bool plain, FILE * fp); 58181834Sroberto 59181834Srobertostatic void 60290001Sglebiusprt_conflicts(tOptions * opts, tOptDesc * od); 61181834Sroberto 62181834Srobertostatic void 63290001Sglebiusprt_one_vendor(tOptions * opts, tOptDesc * od, 64290001Sglebius arg_types_t * argtp, char const * usefmt); 65181834Sroberto 66181834Srobertostatic void 67290001Sglebiusprt_vendor_opts(tOptions * opts, char const * title); 68181834Sroberto 69290001Sglebiusstatic void 70290001Sglebiusprt_extd_usage(tOptions * opts, tOptDesc * od, char const * title); 71290001Sglebius 72290001Sglebiusstatic void 73290001Sglebiusprt_ini_list(char const * const * papz, char const * ini_file, 74290001Sglebius char const * path_nm); 75290001Sglebius 76290001Sglebiusstatic void 77290001Sglebiusprt_preamble(tOptions * opts, tOptDesc * od, arg_types_t * at); 78290001Sglebius 79290001Sglebiusstatic void 80290001Sglebiusprt_one_usage(tOptions * opts, tOptDesc * od, arg_types_t * at); 81290001Sglebius 82290001Sglebiusstatic void 83290001Sglebiusprt_opt_usage(tOptions * opts, int ex_code, char const * title); 84290001Sglebius 85290001Sglebiusstatic void 86290001Sglebiusprt_prog_detail(tOptions * opts); 87290001Sglebius 88181834Srobertostatic int 89290001SglebiussetGnuOptFmts(tOptions * opts, char const ** ptxt); 90181834Sroberto 91181834Srobertostatic int 92290001SglebiussetStdOptFmts(tOptions * opts, char const ** ptxt); 93181834Sroberto/* = = = END-STATIC-FORWARD = = = */ 94181834Sroberto 95290001Sglebius/** 96290001Sglebius * Parse the option usage flags string. Any parsing problems yield 97290001Sglebius * a zero (no flags set) result. This function is internal to 98290001Sglebius * set_usage_flags(). 99290001Sglebius * 100290001Sglebius * @param[in] fnt Flag Name Table - maps a name to a mask 101290001Sglebius * @param[in] txt the text to process. If NULL, then 102290001Sglebius * getenv("AUTOOPTS_USAGE") is used. 103290001Sglebius * @returns a bit mask indicating which \a fnt entries were found. 104290001Sglebius */ 105290001Sglebiusstatic unsigned int 106290001Sglebiusparse_usage_flags(ao_flag_names_t const * fnt, char const * txt) 107290001Sglebius{ 108290001Sglebius unsigned int res = 0; 109181834Sroberto 110290001Sglebius /* 111290001Sglebius * The text may be passed in. If not, use the environment variable. 112290001Sglebius */ 113290001Sglebius if (txt == NULL) { 114290001Sglebius txt = getenv("AUTOOPTS_USAGE"); 115290001Sglebius if (txt == NULL) 116290001Sglebius return 0; 117290001Sglebius } 118290001Sglebius 119290001Sglebius txt = SPN_WHITESPACE_CHARS(txt); 120290001Sglebius if (*txt == NUL) 121290001Sglebius return 0; 122290001Sglebius 123290001Sglebius /* 124290001Sglebius * search the string for table entries. We must understand everything 125290001Sglebius * we see in the string, or we give up on it. 126290001Sglebius */ 127290001Sglebius for (;;) { 128290001Sglebius int ix = 0; 129290001Sglebius 130290001Sglebius for (;;) { 131290001Sglebius if (strneqvcmp(txt, fnt[ix].fnm_name, (int)fnt[ix].fnm_len) == 0) 132290001Sglebius break; 133290001Sglebius if (++ix >= AOUF_COUNT) 134290001Sglebius return 0; 135290001Sglebius } 136290001Sglebius 137290001Sglebius /* 138290001Sglebius * Make sure we have a full match. Look for whitespace, 139290001Sglebius * a comma, or a NUL byte. 140290001Sglebius */ 141290001Sglebius if (! IS_END_LIST_ENTRY_CHAR(txt[fnt[ix].fnm_len])) 142290001Sglebius return 0; 143290001Sglebius 144290001Sglebius res |= 1U << ix; 145290001Sglebius txt = SPN_WHITESPACE_CHARS(txt + fnt[ix].fnm_len); 146290001Sglebius 147290001Sglebius switch (*txt) { 148290001Sglebius case NUL: 149290001Sglebius return res; 150290001Sglebius 151290001Sglebius case ',': 152290001Sglebius txt = SPN_WHITESPACE_CHARS(txt + 1); 153290001Sglebius /* Something must follow the comma */ 154290001Sglebius 155290001Sglebius default: 156290001Sglebius continue; 157290001Sglebius } 158290001Sglebius } 159290001Sglebius} 160290001Sglebius 161290001Sglebius/** 162290001Sglebius * Set option usage flags. Any parsing problems yield no changes to options. 163290001Sglebius * Three different bits may be fiddled: \a OPTPROC_GNUUSAGE, \a OPTPROC_MISUSE 164290001Sglebius * and \a OPTPROC_COMPUTE. 165290001Sglebius * 166290001Sglebius * @param[in] flg_txt text to parse. If NULL, then the AUTOOPTS_USAGE 167290001Sglebius * environment variable is parsed. 168290001Sglebius * @param[in,out] opts the program option descriptor 169290001Sglebius */ 170290001SglebiusLOCAL void 171290001Sglebiusset_usage_flags(tOptions * opts, char const * flg_txt) 172290001Sglebius{ 173290001Sglebius# define _aof_(_n, _f) { sizeof(#_n)-1, _f, #_n }, 174290001Sglebius static ao_flag_names_t const fn_table[AOUF_COUNT] = { 175290001Sglebius AOFLAG_TABLE 176290001Sglebius }; 177290001Sglebius# undef _aof_ 178290001Sglebius 179290001Sglebius /* 180290001Sglebius * the flag word holds a bit for each selected table entry. 181290001Sglebius */ 182290001Sglebius unsigned int flg = parse_usage_flags(fn_table, flg_txt); 183290001Sglebius if (flg == 0) return; 184290001Sglebius 185290001Sglebius /* 186290001Sglebius * Ensure we do not have conflicting selections 187290001Sglebius */ 188290001Sglebius { 189290001Sglebius static unsigned int const form_mask = 190290001Sglebius AOUF_gnu | AOUF_autoopts; 191290001Sglebius static unsigned int const misuse_mask = 192290001Sglebius AOUF_no_misuse_usage | AOUF_misuse_usage; 193290001Sglebius if ( ((flg & form_mask) == form_mask) 194290001Sglebius || ((flg & misuse_mask) == misuse_mask) ) 195290001Sglebius return; 196290001Sglebius } 197290001Sglebius 198290001Sglebius /* 199290001Sglebius * Now fiddle the fOptSet bits, based on settings. 200290001Sglebius * The OPTPROC_LONGOPT bit is immutable, thus if it is set, 201290001Sglebius * then fnm points to a mask off mask. 202290001Sglebius */ 203290001Sglebius { 204290001Sglebius ao_flag_names_t const * fnm = fn_table; 205290001Sglebius for (;;) { 206290001Sglebius if ((flg & 1) != 0) { 207290001Sglebius if ((fnm->fnm_mask & OPTPROC_LONGOPT) != 0) 208290001Sglebius opts->fOptSet &= fnm->fnm_mask; 209290001Sglebius else opts->fOptSet |= fnm->fnm_mask; 210290001Sglebius } 211290001Sglebius flg >>= 1; 212290001Sglebius if (flg == 0) 213290001Sglebius break; 214290001Sglebius fnm++; 215290001Sglebius } 216290001Sglebius } 217290001Sglebius} 218290001Sglebius 219181834Sroberto/* 220181834Sroberto * Figure out if we should try to format usage text sort-of like 221181834Sroberto * the way many GNU programs do. 222181834Sroberto */ 223290001Sglebiusstatic inline bool 224290001Sglebiusdo_gnu_usage(tOptions * pOpts) 225181834Sroberto{ 226290001Sglebius return (pOpts->fOptSet & OPTPROC_GNUUSAGE) ? true : false; 227290001Sglebius} 228181834Sroberto 229290001Sglebius/* 230290001Sglebius * Figure out if we should try to format usage text sort-of like 231290001Sglebius * the way many GNU programs do. 232290001Sglebius */ 233290001Sglebiusstatic inline bool 234290001Sglebiusskip_misuse_usage(tOptions * pOpts) 235290001Sglebius{ 236290001Sglebius return (pOpts->fOptSet & OPTPROC_MISUSE) ? true : false; 237181834Sroberto} 238181834Sroberto 239181834Sroberto 240181834Sroberto/*=export_func optionOnlyUsage 241181834Sroberto * 242181834Sroberto * what: Print usage text for just the options 243290001Sglebius * arg: + tOptions * + pOpts + program options descriptor + 244181834Sroberto * arg: + int + ex_code + exit code for calling exit(3) + 245181834Sroberto * 246181834Sroberto * doc: 247181834Sroberto * This routine will print only the usage for each option. 248181834Sroberto * This function may be used when the emitted usage must incorporate 249181834Sroberto * information not available to AutoOpts. 250181834Sroberto=*/ 251181834Srobertovoid 252290001SglebiusoptionOnlyUsage(tOptions * pOpts, int ex_code) 253181834Sroberto{ 254290001Sglebius char const * pOptTitle = NULL; 255181834Sroberto 256290001Sglebius set_usage_flags(pOpts, NULL); 257290001Sglebius if ((ex_code != EXIT_SUCCESS) && 258290001Sglebius skip_misuse_usage(pOpts)) 259290001Sglebius return; 260290001Sglebius 261181834Sroberto /* 262181834Sroberto * Determine which header and which option formatting strings to use 263181834Sroberto */ 264290001Sglebius if (do_gnu_usage(pOpts)) 265290001Sglebius (void)setGnuOptFmts(pOpts, &pOptTitle); 266290001Sglebius else 267290001Sglebius (void)setStdOptFmts(pOpts, &pOptTitle); 268181834Sroberto 269290001Sglebius prt_opt_usage(pOpts, ex_code, pOptTitle); 270290001Sglebius 271290001Sglebius fflush(option_usage_fp); 272290001Sglebius if (ferror(option_usage_fp) != 0) 273290001Sglebius fserr_exit(pOpts->pzProgName, zwriting, (option_usage_fp == stderr) 274290001Sglebius ? zstderr_name : zstdout_name); 275181834Sroberto} 276181834Sroberto 277290001Sglebius/** 278290001Sglebius * Print a message suggesting how to get help. 279181834Sroberto * 280290001Sglebius * @param[in] opts the program options 281290001Sglebius */ 282290001Sglebiusstatic void 283290001Sglebiusprint_offer_usage(tOptions * opts) 284181834Sroberto{ 285290001Sglebius char help[24]; 286181834Sroberto 287290001Sglebius if (HAS_opt_usage_t(opts)) { 288290001Sglebius int ix = opts->presetOptCt; 289290001Sglebius tOptDesc * od = opts->pOptDesc + ix; 290290001Sglebius while (od->optUsage != AOUSE_HELP) { 291290001Sglebius if (++ix >= opts->optCt) 292290001Sglebius ao_bug(zmissing_help_msg); 293290001Sglebius od++; 294290001Sglebius } 295290001Sglebius switch (opts->fOptSet & (OPTPROC_LONGOPT | OPTPROC_SHORTOPT)) { 296290001Sglebius case OPTPROC_SHORTOPT: 297290001Sglebius help[0] = '-'; 298290001Sglebius help[1] = od->optValue; 299290001Sglebius help[2] = NUL; 300290001Sglebius break; 301181834Sroberto 302290001Sglebius case OPTPROC_LONGOPT: 303290001Sglebius case (OPTPROC_LONGOPT | OPTPROC_SHORTOPT): 304290001Sglebius help[0] = help[1] = '-'; 305290001Sglebius strncpy(help + 2, od->pz_Name, 20); 306290001Sglebius break; 307290001Sglebius 308290001Sglebius case 0: 309290001Sglebius strncpy(help, od->pz_Name, 20); 310290001Sglebius break; 311290001Sglebius } 312181834Sroberto 313290001Sglebius } else { 314290001Sglebius switch (opts->fOptSet & (OPTPROC_LONGOPT | OPTPROC_SHORTOPT)) { 315290001Sglebius case OPTPROC_SHORTOPT: 316290001Sglebius strcpy(help, "-h"); 317290001Sglebius break; 318181834Sroberto 319290001Sglebius case OPTPROC_LONGOPT: 320290001Sglebius case (OPTPROC_LONGOPT | OPTPROC_SHORTOPT): 321290001Sglebius strcpy(help, "--help"); 322290001Sglebius break; 323290001Sglebius 324290001Sglebius case 0: 325290001Sglebius strcpy(help, "help"); 326290001Sglebius break; 327290001Sglebius } 328290001Sglebius } 329290001Sglebius 330290001Sglebius fprintf(option_usage_fp, zoffer_usage_fmt, opts->pzProgName, help); 331290001Sglebius} 332290001Sglebius 333290001Sglebius/** 334290001Sglebius * Print information about each option. 335290001Sglebius * 336290001Sglebius * @param[in] opts the program options 337290001Sglebius * @param[in] exit_code whether or not there was a usage error reported. 338290001Sglebius * used to select full usage versus abbreviated. 339290001Sglebius */ 340290001Sglebiusstatic void 341290001Sglebiusprint_usage_details(tOptions * opts, int exit_code) 342290001Sglebius{ 343181834Sroberto { 344290001Sglebius char const * pOptTitle = NULL; 345290001Sglebius int flen; 346181834Sroberto 347181834Sroberto /* 348181834Sroberto * Determine which header and which option formatting strings to use 349181834Sroberto */ 350290001Sglebius if (do_gnu_usage(opts)) { 351290001Sglebius flen = setGnuOptFmts(opts, &pOptTitle); 352290001Sglebius sprintf(line_fmt_buf, zFmtFmt, flen); 353290001Sglebius fputc(NL, option_usage_fp); 354181834Sroberto } 355181834Sroberto else { 356290001Sglebius flen = setStdOptFmts(opts, &pOptTitle); 357290001Sglebius sprintf(line_fmt_buf, zFmtFmt, flen); 358181834Sroberto 359181834Sroberto /* 360181834Sroberto * When we exit with EXIT_SUCCESS and the first option is a doc 361181834Sroberto * option, we do *NOT* want to emit the column headers. 362181834Sroberto * Otherwise, we do. 363181834Sroberto */ 364290001Sglebius if ( (exit_code != EXIT_SUCCESS) 365290001Sglebius || ((opts->pOptDesc->fOptState & OPTST_DOCUMENT) == 0) ) 366181834Sroberto 367290001Sglebius fputs(pOptTitle, option_usage_fp); 368181834Sroberto } 369181834Sroberto 370290001Sglebius flen = 4 - ((flen + 15) / 8); 371290001Sglebius if (flen > 0) 372290001Sglebius tab_skip_ct = flen; 373290001Sglebius prt_opt_usage(opts, exit_code, pOptTitle); 374181834Sroberto } 375181834Sroberto 376181834Sroberto /* 377181834Sroberto * Describe the mechanics of denoting the options 378181834Sroberto */ 379290001Sglebius switch (opts->fOptSet & OPTPROC_L_N_S) { 380290001Sglebius case OPTPROC_L_N_S: fputs(zFlagOkay, option_usage_fp); break; 381181834Sroberto case OPTPROC_SHORTOPT: break; 382290001Sglebius case OPTPROC_LONGOPT: fputs(zNoFlags, option_usage_fp); break; 383290001Sglebius case 0: fputs(zOptsOnly, option_usage_fp); break; 384181834Sroberto } 385181834Sroberto 386290001Sglebius if ((opts->fOptSet & OPTPROC_NUM_OPT) != 0) 387290001Sglebius fputs(zNumberOpt, option_usage_fp); 388181834Sroberto 389290001Sglebius if ((opts->fOptSet & OPTPROC_REORDER) != 0) 390290001Sglebius fputs(zReorder, option_usage_fp); 391181834Sroberto 392290001Sglebius if (opts->pzExplain != NULL) 393290001Sglebius fputs(opts->pzExplain, option_usage_fp); 394181834Sroberto 395181834Sroberto /* 396181834Sroberto * IF the user is asking for help (thus exiting with SUCCESS), 397181834Sroberto * THEN see what additional information we can provide. 398181834Sroberto */ 399290001Sglebius if (exit_code == EXIT_SUCCESS) 400290001Sglebius prt_prog_detail(opts); 401181834Sroberto 402290001Sglebius /* 403290001Sglebius * Give bug notification preference to the packager information 404290001Sglebius */ 405290001Sglebius if (HAS_pzPkgDataDir(opts) && (opts->pzPackager != NULL)) 406290001Sglebius fputs(opts->pzPackager, option_usage_fp); 407181834Sroberto 408290001Sglebius else if (opts->pzBugAddr != NULL) 409290001Sglebius fprintf(option_usage_fp, zPlsSendBugs, opts->pzBugAddr); 410290001Sglebius 411290001Sglebius fflush(option_usage_fp); 412290001Sglebius 413290001Sglebius if (ferror(option_usage_fp) != 0) 414290001Sglebius fserr_exit(opts->pzProgName, zwriting, (option_usage_fp == stderr) 415290001Sglebius ? zstderr_name : zstdout_name); 416181834Sroberto} 417181834Sroberto 418290001Sglebiusstatic void 419290001Sglebiusprint_one_paragraph(char const * text, bool plain, FILE * fp) 420290001Sglebius{ 421290001Sglebius if (plain) { 422290001Sglebius#ifdef ENABLE_NLS 423290001Sglebius#ifdef HAVE_LIBINTL_H 424290001Sglebius#ifdef DEBUG_ENABLED 425290001Sglebius#undef gettext 426290001Sglebius#endif 427290001Sglebius char * buf = dgettext("libopts", text); 428290001Sglebius if (buf == text) 429290001Sglebius text = gettext(text); 430290001Sglebius#endif /* HAVE_LIBINTL_H */ 431290001Sglebius#endif /* ENABLE_NLS */ 432290001Sglebius fputs(text, fp); 433290001Sglebius } 434181834Sroberto 435290001Sglebius else { 436290001Sglebius char const * t = optionQuoteString(text, LINE_SPLICE); 437290001Sglebius fprintf(fp, PUTS_FMT, t); 438290001Sglebius AGFREE(t); 439290001Sglebius } 440290001Sglebius} 441290001Sglebius 442290001Sglebius/*=export_func optionPrintParagraphs 443290001Sglebius * private: 444290001Sglebius * 445290001Sglebius * what: Print a paragraph of usage text 446290001Sglebius * arg: + char const * + text + a block of text that has bee i18n-ed + 447290001Sglebius * arg: + bool + plain + false -> wrap text in fputs() + 448290001Sglebius * arg: + FILE * + fp + the stream file pointer for output + 449290001Sglebius * 450290001Sglebius * doc: 451290001Sglebius * This procedure is called in two contexts: when a full or short usage text 452290001Sglebius * has been provided for display, and when autogen is assembling a list of 453290001Sglebius * translatable texts in the optmain.tlib template. In the former case, \a 454290001Sglebius * plain is set to \a true, otherwise \a false. 455290001Sglebius * 456290001Sglebius * Anything less than 256 characters in size is printed as a single unit. 457290001Sglebius * Otherwise, paragraphs are detected. A paragraph break is defined as just 458290001Sglebius * before a non-empty line preceded by two newlines or a line that starts 459290001Sglebius * with at least one space character but fewer than 8 space characters. 460290001Sglebius * Lines indented with tabs or more than 7 spaces are considered continuation 461290001Sglebius * lines. 462290001Sglebius * 463290001Sglebius * If 'plain' is true, we are emitting text for a user to see. So, if it is 464290001Sglebius * true and NLS is not enabled, then just write the whole thing at once. 465290001Sglebius=*/ 466290001Sglebiusvoid 467290001SglebiusoptionPrintParagraphs(char const * text, bool plain, FILE * fp) 468290001Sglebius{ 469290001Sglebius size_t len = strlen(text); 470290001Sglebius char * buf; 471290001Sglebius#ifndef ENABLE_NLS 472290001Sglebius if (plain || (len < 256)) 473290001Sglebius#else 474290001Sglebius if (len < 256) 475290001Sglebius#endif 476290001Sglebius { 477290001Sglebius print_one_paragraph(text, plain, fp); 478290001Sglebius return; 479290001Sglebius } 480290001Sglebius 481290001Sglebius AGDUPSTR(buf, text, "ppara"); 482290001Sglebius text = buf; 483290001Sglebius 484290001Sglebius for (;;) { 485290001Sglebius char * scan; 486290001Sglebius 487290001Sglebius if (len < 256) { 488290001Sglebius done: 489290001Sglebius print_one_paragraph(buf, plain, fp); 490290001Sglebius break; 491290001Sglebius } 492290001Sglebius scan = buf; 493290001Sglebius 494290001Sglebius try_longer: 495290001Sglebius scan = strchr(scan, NL); 496290001Sglebius if (scan == NULL) 497290001Sglebius goto done; 498290001Sglebius 499290001Sglebius if ((scan - buf) < 40) { 500290001Sglebius scan++; 501290001Sglebius goto try_longer; 502290001Sglebius } 503290001Sglebius 504290001Sglebius scan++; 505290001Sglebius if ((! isspace((int)*scan)) || (*scan == HT)) 506290001Sglebius /* 507290001Sglebius * line starts with tab or non-whitespace --> continuation 508290001Sglebius */ 509290001Sglebius goto try_longer; 510290001Sglebius 511290001Sglebius if (*scan == NL) { 512290001Sglebius /* 513290001Sglebius * Double newline -> paragraph break 514290001Sglebius * Include all newlines in current paragraph. 515290001Sglebius */ 516290001Sglebius while (*++scan == NL) /*continue*/; 517290001Sglebius 518290001Sglebius } else { 519290001Sglebius char * p = scan; 520290001Sglebius int sp_ct = 0; 521290001Sglebius 522290001Sglebius while (*p == ' ') { 523290001Sglebius if (++sp_ct >= 8) { 524290001Sglebius /* 525290001Sglebius * Too many spaces --> continuation line 526290001Sglebius */ 527290001Sglebius scan = p; 528290001Sglebius goto try_longer; 529290001Sglebius } 530290001Sglebius p++; 531290001Sglebius } 532290001Sglebius } 533290001Sglebius 534290001Sglebius /* 535290001Sglebius * "scan" points to the first character of a paragraph or the 536290001Sglebius * terminating NUL byte. 537290001Sglebius */ 538290001Sglebius { 539290001Sglebius char svch = *scan; 540290001Sglebius *scan = NUL; 541290001Sglebius print_one_paragraph(buf, plain, fp); 542290001Sglebius len -= scan - buf; 543290001Sglebius if (len <= 0) 544290001Sglebius break; 545290001Sglebius *scan = svch; 546290001Sglebius buf = scan; 547290001Sglebius } 548290001Sglebius } 549290001Sglebius AGFREE(text); 550290001Sglebius} 551290001Sglebius 552290001Sglebius/*=export_func optionUsage 553290001Sglebius * private: 554290001Sglebius * 555290001Sglebius * what: Print usage text 556290001Sglebius * arg: + tOptions * + opts + program options descriptor + 557290001Sglebius * arg: + int + exitCode + exit code for calling exit(3) + 558290001Sglebius * 559290001Sglebius * doc: 560290001Sglebius * This routine will print usage in both GNU-standard and AutoOpts-expanded 561290001Sglebius * formats. The descriptor specifies the default, but AUTOOPTS_USAGE will 562290001Sglebius * over-ride this, providing the value of it is set to either "gnu" or 563290001Sglebius * "autoopts". This routine will @strong{not} return. 564290001Sglebius * 565290001Sglebius * If "exitCode" is "AO_EXIT_REQ_USAGE" (normally 64), then output will to 566290001Sglebius * to stdout and the actual exit code will be "EXIT_SUCCESS". 567290001Sglebius=*/ 568290001Sglebiusvoid 569290001SglebiusoptionUsage(tOptions * opts, int usage_exit_code) 570290001Sglebius{ 571290001Sglebius int exit_code = (usage_exit_code == AO_EXIT_REQ_USAGE) 572290001Sglebius ? EXIT_SUCCESS : usage_exit_code; 573290001Sglebius 574290001Sglebius displayEnum = false; 575290001Sglebius set_usage_flags(opts, NULL); 576290001Sglebius 577290001Sglebius /* 578290001Sglebius * Paged usage will preset option_usage_fp to an output file. 579290001Sglebius * If it hasn't already been set, then set it to standard output 580290001Sglebius * on successful exit (help was requested), otherwise error out. 581290001Sglebius * 582290001Sglebius * Test the version before obtaining pzFullUsage or pzShortUsage. 583290001Sglebius * These fields do not exist before revision 30. 584290001Sglebius */ 585290001Sglebius { 586290001Sglebius char const * pz; 587290001Sglebius 588290001Sglebius if (exit_code == EXIT_SUCCESS) { 589290001Sglebius pz = (opts->structVersion >= 30 * 4096) 590290001Sglebius ? opts->pzFullUsage : NULL; 591290001Sglebius 592290001Sglebius if (option_usage_fp == NULL) 593290001Sglebius option_usage_fp = print_exit ? stderr : stdout; 594290001Sglebius 595290001Sglebius } else { 596290001Sglebius pz = (opts->structVersion >= 30 * 4096) 597290001Sglebius ? opts->pzShortUsage : NULL; 598290001Sglebius 599290001Sglebius if (option_usage_fp == NULL) 600290001Sglebius option_usage_fp = stderr; 601290001Sglebius } 602290001Sglebius 603290001Sglebius if (((opts->fOptSet & OPTPROC_COMPUTE) == 0) && (pz != NULL)) { 604290001Sglebius if ((opts->fOptSet & OPTPROC_TRANSLATE) != 0) 605290001Sglebius optionPrintParagraphs(pz, true, option_usage_fp); 606290001Sglebius else 607290001Sglebius fputs(pz, option_usage_fp); 608290001Sglebius goto flush_and_exit; 609290001Sglebius } 610290001Sglebius } 611290001Sglebius 612290001Sglebius fprintf(option_usage_fp, opts->pzUsageTitle, opts->pzProgName); 613290001Sglebius 614290001Sglebius if ((exit_code == EXIT_SUCCESS) || 615290001Sglebius (! skip_misuse_usage(opts))) 616290001Sglebius 617290001Sglebius print_usage_details(opts, usage_exit_code); 618290001Sglebius else 619290001Sglebius print_offer_usage(opts); 620290001Sglebius 621290001Sglebius flush_and_exit: 622290001Sglebius fflush(option_usage_fp); 623290001Sglebius if (ferror(option_usage_fp) != 0) 624290001Sglebius fserr_exit(opts->pzProgName, zwriting, (option_usage_fp == stdout) 625290001Sglebius ? zstdout_name : zstderr_name); 626290001Sglebius 627290001Sglebius option_exits(exit_code); 628290001Sglebius} 629290001Sglebius 630181834Sroberto/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 631290001Sglebius * PER OPTION TYPE USAGE INFORMATION 632290001Sglebius * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 633290001Sglebius/** 634290001Sglebius * print option conflicts. 635181834Sroberto * 636290001Sglebius * @param opts the program option descriptor 637290001Sglebius * @param od the option descriptor 638181834Sroberto */ 639181834Srobertostatic void 640290001Sglebiusprt_conflicts(tOptions * opts, tOptDesc * od) 641181834Sroberto{ 642290001Sglebius const int * opt_no; 643290001Sglebius fputs(zTabHyp + tab_skip_ct, option_usage_fp); 644290001Sglebius 645181834Sroberto /* 646290001Sglebius * REQUIRED: 647181834Sroberto */ 648290001Sglebius if (od->pOptMust != NULL) { 649290001Sglebius opt_no = od->pOptMust; 650181834Sroberto 651290001Sglebius if (opt_no[1] == NO_EQUIVALENT) { 652290001Sglebius fprintf(option_usage_fp, zReqOne, 653290001Sglebius opts->pOptDesc[*opt_no].pz_Name); 654290001Sglebius } else { 655290001Sglebius fputs(zReqThese, option_usage_fp); 656181834Sroberto for (;;) { 657290001Sglebius fprintf(option_usage_fp, zTabout + tab_skip_ct, 658290001Sglebius opts->pOptDesc[*opt_no].pz_Name); 659290001Sglebius if (*++opt_no == NO_EQUIVALENT) 660181834Sroberto break; 661181834Sroberto } 662181834Sroberto } 663181834Sroberto 664290001Sglebius if (od->pOptCant != NULL) 665290001Sglebius fputs(zTabHypAnd + tab_skip_ct, option_usage_fp); 666290001Sglebius } 667290001Sglebius 668290001Sglebius /* 669290001Sglebius * CONFLICTS: 670290001Sglebius */ 671290001Sglebius if (od->pOptCant == NULL) 672290001Sglebius return; 673290001Sglebius 674290001Sglebius opt_no = od->pOptCant; 675290001Sglebius 676290001Sglebius if (opt_no[1] == NO_EQUIVALENT) { 677290001Sglebius fprintf(option_usage_fp, zProhibOne, 678290001Sglebius opts->pOptDesc[*opt_no].pz_Name); 679290001Sglebius return; 680290001Sglebius } 681290001Sglebius 682290001Sglebius fputs(zProhib, option_usage_fp); 683290001Sglebius for (;;) { 684290001Sglebius fprintf(option_usage_fp, zTabout + tab_skip_ct, 685290001Sglebius opts->pOptDesc[*opt_no].pz_Name); 686290001Sglebius if (*++opt_no == NO_EQUIVALENT) 687290001Sglebius break; 688290001Sglebius } 689290001Sglebius} 690290001Sglebius 691290001Sglebius/** 692290001Sglebius * Print the usage information for a single vendor option. 693290001Sglebius * 694290001Sglebius * @param[in] opts the program option descriptor 695290001Sglebius * @param[in] od the option descriptor 696290001Sglebius * @param[in] argtp names of the option argument types 697290001Sglebius * @param[in] usefmt format for primary usage line 698290001Sglebius */ 699290001Sglebiusstatic void 700290001Sglebiusprt_one_vendor(tOptions * opts, tOptDesc * od, 701290001Sglebius arg_types_t * argtp, char const * usefmt) 702290001Sglebius{ 703290001Sglebius prt_preamble(opts, od, argtp); 704290001Sglebius 705290001Sglebius { 706290001Sglebius char z[ 80 ]; 707290001Sglebius char const * pzArgType; 708290001Sglebius 709181834Sroberto /* 710290001Sglebius * Determine the argument type string first on its usage, then, 711290001Sglebius * when the option argument is required, base the type string on the 712290001Sglebius * argument type. 713181834Sroberto */ 714290001Sglebius if (od->fOptState & OPTST_ARG_OPTIONAL) { 715290001Sglebius pzArgType = argtp->pzOpt; 716181834Sroberto 717290001Sglebius } else switch (OPTST_GET_ARGTYPE(od->fOptState)) { 718290001Sglebius case OPARG_TYPE_NONE: pzArgType = argtp->pzNo; break; 719290001Sglebius case OPARG_TYPE_ENUMERATION: pzArgType = argtp->pzKey; break; 720290001Sglebius case OPARG_TYPE_FILE: pzArgType = argtp->pzFile; break; 721290001Sglebius case OPARG_TYPE_MEMBERSHIP: pzArgType = argtp->pzKeyL; break; 722290001Sglebius case OPARG_TYPE_BOOLEAN: pzArgType = argtp->pzBool; break; 723290001Sglebius case OPARG_TYPE_NUMERIC: pzArgType = argtp->pzNum; break; 724290001Sglebius case OPARG_TYPE_HIERARCHY: pzArgType = argtp->pzNest; break; 725290001Sglebius case OPARG_TYPE_STRING: pzArgType = argtp->pzStr; break; 726290001Sglebius case OPARG_TYPE_TIME: pzArgType = argtp->pzTime; break; 727290001Sglebius default: goto bogus_desc; 728181834Sroberto } 729290001Sglebius 730290001Sglebius pzArgType = SPN_WHITESPACE_CHARS(pzArgType); 731290001Sglebius if (*pzArgType == NUL) 732290001Sglebius snprintf(z, sizeof(z), "%s", od->pz_Name); 733290001Sglebius else 734290001Sglebius snprintf(z, sizeof(z), "%s=%s", od->pz_Name, pzArgType); 735290001Sglebius fprintf(option_usage_fp, usefmt, z, od->pzText); 736290001Sglebius 737290001Sglebius switch (OPTST_GET_ARGTYPE(od->fOptState)) { 738290001Sglebius case OPARG_TYPE_ENUMERATION: 739290001Sglebius case OPARG_TYPE_MEMBERSHIP: 740290001Sglebius displayEnum = (od->pOptProc != NULL) ? true : displayEnum; 741290001Sglebius } 742181834Sroberto } 743181834Sroberto 744290001Sglebius return; 745290001Sglebius 746290001Sglebius bogus_desc: 747290001Sglebius fprintf(stderr, zbad_od, opts->pzProgName, od->pz_Name); 748290001Sglebius ao_bug(zbad_arg_type_msg); 749290001Sglebius} 750290001Sglebius 751290001Sglebius/** 752290001Sglebius * Print the long options processed with "-W". These options will be the 753290001Sglebius * ones that do *not* have flag characters. 754290001Sglebius * 755290001Sglebius * @param opts the program option descriptor 756290001Sglebius * @param title the title for the options 757290001Sglebius */ 758290001Sglebiusstatic void 759290001Sglebiusprt_vendor_opts(tOptions * opts, char const * title) 760290001Sglebius{ 761290001Sglebius static unsigned int const not_vended_mask = 762290001Sglebius OPTST_NO_USAGE_MASK | OPTST_DOCUMENT; 763290001Sglebius 764290001Sglebius static char const vfmtfmt[] = "%%-%us %%s\n"; 765290001Sglebius char vfmt[sizeof(vfmtfmt)]; 766290001Sglebius 767181834Sroberto /* 768290001Sglebius * Only handle client specified options. The "vendor option" follows 769290001Sglebius * "presetOptCt", so we won't loop/recurse indefinitely. 770290001Sglebius */ 771290001Sglebius int ct = opts->presetOptCt; 772290001Sglebius tOptDesc * od = opts->pOptDesc; 773290001Sglebius fprintf(option_usage_fp, zTabout + tab_skip_ct, zVendOptsAre); 774290001Sglebius 775290001Sglebius { 776290001Sglebius size_t nmlen = 0; 777290001Sglebius do { 778290001Sglebius size_t l; 779290001Sglebius if ( ((od->fOptState & not_vended_mask) != 0) 780290001Sglebius || IS_GRAPHIC_CHAR(od->optValue)) 781290001Sglebius continue; 782290001Sglebius 783290001Sglebius l = strlen(od->pz_Name); 784290001Sglebius if (l > nmlen) nmlen = l; 785290001Sglebius } while (od++, (--ct > 0)); 786290001Sglebius 787290001Sglebius snprintf(vfmt, sizeof(vfmt), vfmtfmt, (unsigned int)nmlen + 4); 788290001Sglebius } 789290001Sglebius 790290001Sglebius if (tab_skip_ct > 0) 791290001Sglebius tab_skip_ct--; 792290001Sglebius 793290001Sglebius ct = opts->presetOptCt; 794290001Sglebius od = opts->pOptDesc; 795290001Sglebius 796290001Sglebius do { 797290001Sglebius if ( ((od->fOptState & not_vended_mask) != 0) 798290001Sglebius || IS_GRAPHIC_CHAR(od->optValue)) 799290001Sglebius continue; 800290001Sglebius 801290001Sglebius prt_one_vendor(opts, od, &argTypes, vfmt); 802290001Sglebius prt_extd_usage(opts, od, title); 803290001Sglebius 804290001Sglebius } while (od++, (--ct > 0)); 805290001Sglebius 806290001Sglebius /* no need to restore "tab_skip_ct" - options are done now */ 807290001Sglebius} 808290001Sglebius 809290001Sglebius/** 810290001Sglebius * Print extended usage. Usage/help was requested. 811290001Sglebius * 812290001Sglebius * @param opts the program option descriptor 813290001Sglebius * @param od the option descriptor 814290001Sglebius * @param title the title for the options 815290001Sglebius */ 816290001Sglebiusstatic void 817290001Sglebiusprt_extd_usage(tOptions * opts, tOptDesc * od, char const * title) 818290001Sglebius{ 819290001Sglebius if ( ((opts->fOptSet & OPTPROC_VENDOR_OPT) != 0) 820290001Sglebius && (od->optActualValue == VENDOR_OPTION_VALUE)) { 821290001Sglebius prt_vendor_opts(opts, title); 822290001Sglebius return; 823290001Sglebius } 824290001Sglebius 825290001Sglebius /* 826290001Sglebius * IF there are option conflicts or dependencies, 827290001Sglebius * THEN print them here. 828290001Sglebius */ 829290001Sglebius if ((od->pOptMust != NULL) || (od->pOptCant != NULL)) 830290001Sglebius prt_conflicts(opts, od); 831290001Sglebius 832290001Sglebius /* 833181834Sroberto * IF there is a disablement string 834181834Sroberto * THEN print the disablement info 835181834Sroberto */ 836290001Sglebius if (od->pz_DisableName != NULL ) 837290001Sglebius fprintf(option_usage_fp, zDis + tab_skip_ct, od->pz_DisableName); 838181834Sroberto 839181834Sroberto /* 840290001Sglebius * Check for argument types that have callbacks with magical properties 841181834Sroberto */ 842290001Sglebius switch (OPTST_GET_ARGTYPE(od->fOptState)) { 843290001Sglebius case OPARG_TYPE_NUMERIC: 844290001Sglebius /* 845290001Sglebius * IF the numeric option has a special callback, 846290001Sglebius * THEN call it, requesting the range or other special info 847290001Sglebius */ 848290001Sglebius if ( (od->pOptProc != NULL) 849290001Sglebius && (od->pOptProc != optionNumericVal) ) { 850290001Sglebius (*(od->pOptProc))(OPTPROC_EMIT_USAGE, od); 851290001Sglebius } 852290001Sglebius break; 853290001Sglebius 854290001Sglebius case OPARG_TYPE_FILE: 855290001Sglebius (*(od->pOptProc))(OPTPROC_EMIT_USAGE, od); 856290001Sglebius break; 857181834Sroberto } 858181834Sroberto 859181834Sroberto /* 860181834Sroberto * IF the option defaults to being enabled, 861181834Sroberto * THEN print that out 862181834Sroberto */ 863290001Sglebius if (od->fOptState & OPTST_INITENABLED) 864290001Sglebius fputs(zEnab + tab_skip_ct, option_usage_fp); 865181834Sroberto 866181834Sroberto /* 867181834Sroberto * IF the option is in an equivalence class 868181834Sroberto * AND not the designated lead 869181834Sroberto * THEN print equivalence and leave it at that. 870181834Sroberto */ 871290001Sglebius if ( (od->optEquivIndex != NO_EQUIVALENT) 872290001Sglebius && (od->optEquivIndex != od->optActualIndex ) ) { 873290001Sglebius fprintf(option_usage_fp, zalt_opt + tab_skip_ct, 874290001Sglebius opts->pOptDesc[ od->optEquivIndex ].pz_Name); 875181834Sroberto return; 876181834Sroberto } 877181834Sroberto 878181834Sroberto /* 879181834Sroberto * IF this particular option can NOT be preset 880181834Sroberto * AND some form of presetting IS allowed, 881181834Sroberto * AND it is not an auto-managed option (e.g. --help, et al.) 882181834Sroberto * THEN advise that this option may not be preset. 883181834Sroberto */ 884290001Sglebius if ( ((od->fOptState & OPTST_NO_INIT) != 0) 885290001Sglebius && ( (opts->papzHomeList != NULL) 886290001Sglebius || (opts->pzPROGNAME != NULL) 887181834Sroberto ) 888290001Sglebius && (od->optIndex < opts->presetOptCt) 889181834Sroberto ) 890181834Sroberto 891290001Sglebius fputs(zNoPreset + tab_skip_ct, option_usage_fp); 892181834Sroberto 893181834Sroberto /* 894181834Sroberto * Print the appearance requirements. 895181834Sroberto */ 896290001Sglebius if (OPTST_GET_ARGTYPE(od->fOptState) == OPARG_TYPE_MEMBERSHIP) 897290001Sglebius fputs(zMembers + tab_skip_ct, option_usage_fp); 898181834Sroberto 899290001Sglebius else switch (od->optMinCt) { 900181834Sroberto case 1: 901181834Sroberto case 0: 902290001Sglebius switch (od->optMaxCt) { 903290001Sglebius case 0: fputs(zPreset + tab_skip_ct, option_usage_fp); break; 904290001Sglebius case NOLIMIT: fputs(zNoLim + tab_skip_ct, option_usage_fp); break; 905181834Sroberto case 1: break; 906181834Sroberto /* 907181834Sroberto * IF the max is more than one but limited, print "UP TO" message 908181834Sroberto */ 909290001Sglebius default: 910290001Sglebius fprintf(option_usage_fp, zUpTo + tab_skip_ct, od->optMaxCt); break; 911181834Sroberto } 912181834Sroberto break; 913181834Sroberto 914181834Sroberto default: 915181834Sroberto /* 916181834Sroberto * More than one is required. Print the range. 917181834Sroberto */ 918290001Sglebius fprintf(option_usage_fp, zMust + tab_skip_ct, 919290001Sglebius od->optMinCt, od->optMaxCt); 920181834Sroberto } 921181834Sroberto 922290001Sglebius if ( NAMED_OPTS(opts) 923290001Sglebius && (opts->specOptIdx.default_opt == od->optIndex)) 924290001Sglebius fputs(zDefaultOpt + tab_skip_ct, option_usage_fp); 925181834Sroberto} 926181834Sroberto 927290001Sglebius/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 928290001Sglebius/** 929290001Sglebius * Figure out where all the initialization files might live. This requires 930290001Sglebius * translating some environment variables and testing to see if a name is a 931290001Sglebius * directory or a file. It's squishy, but important to tell users how to 932290001Sglebius * find these files. 933181834Sroberto * 934290001Sglebius * @param[in] papz search path 935290001Sglebius * @param[out] ini_file an output buffer of AG_PATH_MAX+1 bytes 936290001Sglebius * @param[in] path_nm the name of the file we're hunting for 937181834Sroberto */ 938181834Srobertostatic void 939290001Sglebiusprt_ini_list(char const * const * papz, char const * ini_file, 940290001Sglebius char const * path_nm) 941181834Sroberto{ 942290001Sglebius char pth_buf[AG_PATH_MAX+1]; 943181834Sroberto 944290001Sglebius fputs(zPresetIntro, option_usage_fp); 945181834Sroberto 946181834Sroberto for (;;) { 947290001Sglebius char const * path = *(papz++); 948290001Sglebius char const * nm_buf = pth_buf; 949181834Sroberto 950290001Sglebius if (path == NULL) 951181834Sroberto break; 952181834Sroberto 953290001Sglebius /* 954290001Sglebius * Ignore any invalid paths 955290001Sglebius */ 956290001Sglebius if (! optionMakePath(pth_buf, (int)sizeof(pth_buf), path, path_nm)) 957290001Sglebius nm_buf = path; 958181834Sroberto 959181834Sroberto /* 960290001Sglebius * Expand paths that are relative to the executable or installation 961290001Sglebius * directories. Leave alone paths that use environment variables. 962290001Sglebius */ 963290001Sglebius else if ((*path == '$') 964290001Sglebius && ((path[1] == '$') || (path[1] == '@'))) 965290001Sglebius path = nm_buf; 966290001Sglebius 967290001Sglebius /* 968181834Sroberto * Print the name of the "homerc" file. If the "rcfile" name is 969181834Sroberto * not empty, we may or may not print that, too... 970181834Sroberto */ 971290001Sglebius fprintf(option_usage_fp, zPathFmt, path); 972290001Sglebius if (*ini_file != NUL) { 973181834Sroberto struct stat sb; 974181834Sroberto 975181834Sroberto /* 976181834Sroberto * IF the "homerc" file is a directory, 977181834Sroberto * then append the "rcfile" name. 978181834Sroberto */ 979290001Sglebius if ((stat(nm_buf, &sb) == 0) && S_ISDIR(sb.st_mode)) { 980290001Sglebius fputc(DIRCH, option_usage_fp); 981290001Sglebius fputs(ini_file, option_usage_fp); 982181834Sroberto } 983181834Sroberto } 984181834Sroberto 985290001Sglebius fputc(NL, option_usage_fp); 986181834Sroberto } 987181834Sroberto} 988181834Sroberto 989290001Sglebius/** 990290001Sglebius * Print the usage line preamble text 991290001Sglebius * 992290001Sglebius * @param opts the program option descriptor 993290001Sglebius * @param od the option descriptor 994290001Sglebius * @param at names of the option argument types 995181834Sroberto */ 996181834Srobertostatic void 997290001Sglebiusprt_preamble(tOptions * opts, tOptDesc * od, arg_types_t * at) 998181834Sroberto{ 999181834Sroberto /* 1000181834Sroberto * Flag prefix: IF no flags at all, then omit it. If not printable 1001181834Sroberto * (not allowed for this option), then blank, else print it. 1002181834Sroberto * Follow it with a comma if we are doing GNU usage and long 1003181834Sroberto * opts are to be printed too. 1004181834Sroberto */ 1005290001Sglebius if ((opts->fOptSet & OPTPROC_SHORTOPT) == 0) 1006290001Sglebius fputs(at->pzSpc, option_usage_fp); 1007290001Sglebius 1008290001Sglebius else if (! IS_GRAPHIC_CHAR(od->optValue)) { 1009290001Sglebius if ( (opts->fOptSet & (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT)) 1010181834Sroberto == (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT)) 1011290001Sglebius fputc(' ', option_usage_fp); 1012290001Sglebius fputs(at->pzNoF, option_usage_fp); 1013290001Sglebius 1014181834Sroberto } else { 1015290001Sglebius fprintf(option_usage_fp, " -%c", od->optValue); 1016290001Sglebius if ( (opts->fOptSet & (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT)) 1017181834Sroberto == (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT)) 1018290001Sglebius fputs(", ", option_usage_fp); 1019181834Sroberto } 1020290001Sglebius} 1021181834Sroberto 1022290001Sglebius/** 1023290001Sglebius * Print the usage information for a single option. 1024290001Sglebius * 1025290001Sglebius * @param opts the program option descriptor 1026290001Sglebius * @param od the option descriptor 1027290001Sglebius * @param at names of the option argument types 1028290001Sglebius */ 1029290001Sglebiusstatic void 1030290001Sglebiusprt_one_usage(tOptions * opts, tOptDesc * od, arg_types_t * at) 1031290001Sglebius{ 1032290001Sglebius prt_preamble(opts, od, at); 1033290001Sglebius 1034181834Sroberto { 1035290001Sglebius char z[80]; 1036290001Sglebius char const * atyp; 1037290001Sglebius 1038181834Sroberto /* 1039181834Sroberto * Determine the argument type string first on its usage, then, 1040181834Sroberto * when the option argument is required, base the type string on the 1041181834Sroberto * argument type. 1042181834Sroberto */ 1043290001Sglebius if (od->fOptState & OPTST_ARG_OPTIONAL) { 1044290001Sglebius atyp = at->pzOpt; 1045181834Sroberto 1046290001Sglebius } else switch (OPTST_GET_ARGTYPE(od->fOptState)) { 1047290001Sglebius case OPARG_TYPE_NONE: atyp = at->pzNo; break; 1048290001Sglebius case OPARG_TYPE_ENUMERATION: atyp = at->pzKey; break; 1049290001Sglebius case OPARG_TYPE_FILE: atyp = at->pzFile; break; 1050290001Sglebius case OPARG_TYPE_MEMBERSHIP: atyp = at->pzKeyL; break; 1051290001Sglebius case OPARG_TYPE_BOOLEAN: atyp = at->pzBool; break; 1052290001Sglebius case OPARG_TYPE_NUMERIC: atyp = at->pzNum; break; 1053290001Sglebius case OPARG_TYPE_HIERARCHY: atyp = at->pzNest; break; 1054290001Sglebius case OPARG_TYPE_STRING: atyp = at->pzStr; break; 1055290001Sglebius case OPARG_TYPE_TIME: atyp = at->pzTime; break; 1056290001Sglebius default: goto bogus_desc; 1057181834Sroberto } 1058181834Sroberto 1059290001Sglebius#ifdef _WIN32 1060290001Sglebius if (at->pzOptFmt == zGnuOptFmt) 1061290001Sglebius snprintf(z, sizeof(z), "--%s%s", od->pz_Name, atyp); 1062290001Sglebius else if (at->pzOptFmt == zGnuOptFmt + 2) 1063290001Sglebius snprintf(z, sizeof(z), "%s%s", od->pz_Name, atyp); 1064290001Sglebius else 1065290001Sglebius#endif 1066290001Sglebius snprintf(z, sizeof(z), at->pzOptFmt, atyp, od->pz_Name, 1067290001Sglebius (od->optMinCt != 0) ? at->pzReq : at->pzOpt); 1068181834Sroberto 1069290001Sglebius fprintf(option_usage_fp, line_fmt_buf, z, od->pzText); 1070181834Sroberto 1071290001Sglebius switch (OPTST_GET_ARGTYPE(od->fOptState)) { 1072181834Sroberto case OPARG_TYPE_ENUMERATION: 1073181834Sroberto case OPARG_TYPE_MEMBERSHIP: 1074290001Sglebius displayEnum = (od->pOptProc != NULL) ? true : displayEnum; 1075181834Sroberto } 1076181834Sroberto } 1077290001Sglebius 1078181834Sroberto return; 1079181834Sroberto 1080181834Sroberto bogus_desc: 1081290001Sglebius fprintf(stderr, zbad_od, opts->pzProgName, od->pz_Name); 1082290001Sglebius option_exits(EX_SOFTWARE); 1083181834Sroberto} 1084181834Sroberto 1085290001Sglebius/** 1086181834Sroberto * Print out the usage information for just the options. 1087181834Sroberto */ 1088181834Srobertostatic void 1089290001Sglebiusprt_opt_usage(tOptions * opts, int ex_code, char const * title) 1090181834Sroberto{ 1091290001Sglebius int ct = opts->optCt; 1092290001Sglebius int optNo = 0; 1093290001Sglebius tOptDesc * od = opts->pOptDesc; 1094290001Sglebius int docCt = 0; 1095181834Sroberto 1096181834Sroberto do { 1097290001Sglebius /* 1098290001Sglebius * no usage --> disallowed on command line (OPTST_NO_COMMAND), or 1099290001Sglebius * deprecated -- strongly discouraged (OPTST_DEPRECATED), or 1100290001Sglebius * compiled out of current object code (OPTST_OMITTED) 1101290001Sglebius */ 1102290001Sglebius if ((od->fOptState & OPTST_NO_USAGE_MASK) != 0) { 1103290001Sglebius 1104290001Sglebius /* 1105290001Sglebius * IF this is a compiled-out option 1106290001Sglebius * *AND* usage was requested with "omitted-usage" 1107290001Sglebius * *AND* this is NOT abbreviated usage 1108290001Sglebius * THEN display this option. 1109290001Sglebius */ 1110290001Sglebius if ( (od->fOptState == (OPTST_OMITTED | OPTST_NO_INIT)) 1111290001Sglebius && (od->pz_Name != NULL) 1112290001Sglebius && (ex_code == EXIT_SUCCESS)) { 1113290001Sglebius 1114290001Sglebius char const * why_pz = 1115290001Sglebius (od->pzText == NULL) ? zDisabledWhy : od->pzText; 1116290001Sglebius prt_preamble(opts, od, &argTypes); 1117290001Sglebius fprintf(option_usage_fp, zDisabledOpt, od->pz_Name, why_pz); 1118290001Sglebius } 1119290001Sglebius 1120181834Sroberto continue; 1121290001Sglebius } 1122181834Sroberto 1123290001Sglebius if ((od->fOptState & OPTST_DOCUMENT) != 0) { 1124181834Sroberto if (ex_code == EXIT_SUCCESS) { 1125290001Sglebius fprintf(option_usage_fp, argTypes.pzBrk, od->pzText, 1126290001Sglebius title); 1127181834Sroberto docCt++; 1128181834Sroberto } 1129181834Sroberto 1130181834Sroberto continue; 1131181834Sroberto } 1132181834Sroberto 1133290001Sglebius /* Skip name only options when we have a vendor option */ 1134290001Sglebius if ( ((opts->fOptSet & OPTPROC_VENDOR_OPT) != 0) 1135290001Sglebius && (! IS_GRAPHIC_CHAR(od->optValue))) 1136290001Sglebius continue; 1137290001Sglebius 1138181834Sroberto /* 1139181834Sroberto * IF this is the first auto-opt maintained option 1140181834Sroberto * *AND* we are doing a full help 1141181834Sroberto * *AND* there are documentation options 1142181834Sroberto * *AND* the last one was not a doc option, 1143181834Sroberto * THEN document that the remaining options are not user opts 1144181834Sroberto */ 1145290001Sglebius if ((docCt > 0) && (ex_code == EXIT_SUCCESS)) { 1146290001Sglebius if (opts->presetOptCt == optNo) { 1147290001Sglebius if ((od[-1].fOptState & OPTST_DOCUMENT) == 0) 1148290001Sglebius fprintf(option_usage_fp, argTypes.pzBrk, zAuto, title); 1149181834Sroberto 1150290001Sglebius } else if ((ct == 1) && 1151290001Sglebius (opts->fOptSet & OPTPROC_VENDOR_OPT)) 1152290001Sglebius fprintf(option_usage_fp, argTypes.pzBrk, zVendIntro, title); 1153290001Sglebius } 1154181834Sroberto 1155290001Sglebius prt_one_usage(opts, od, &argTypes); 1156290001Sglebius 1157181834Sroberto /* 1158181834Sroberto * IF we were invoked because of the --help option, 1159181834Sroberto * THEN print all the extra info 1160181834Sroberto */ 1161181834Sroberto if (ex_code == EXIT_SUCCESS) 1162290001Sglebius prt_extd_usage(opts, od, title); 1163181834Sroberto 1164290001Sglebius } while (od++, optNo++, (--ct > 0)); 1165181834Sroberto 1166290001Sglebius fputc(NL, option_usage_fp); 1167181834Sroberto} 1168181834Sroberto 1169181834Sroberto 1170290001Sglebius/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 1171290001Sglebius/** 1172290001Sglebius * Print program details. 1173290001Sglebius * @param[in] opts the program option descriptor 1174181834Sroberto */ 1175181834Srobertostatic void 1176290001Sglebiusprt_prog_detail(tOptions * opts) 1177181834Sroberto{ 1178290001Sglebius bool need_intro = (opts->papzHomeList == NULL); 1179181834Sroberto 1180181834Sroberto /* 1181290001Sglebius * Display all the places we look for config files, if we have 1182290001Sglebius * a list of directories to search. 1183181834Sroberto */ 1184290001Sglebius if (! need_intro) 1185290001Sglebius prt_ini_list(opts->papzHomeList, opts->pzRcName, opts->pzProgPath); 1186181834Sroberto 1187181834Sroberto /* 1188181834Sroberto * Let the user know about environment variable settings 1189181834Sroberto */ 1190290001Sglebius if ((opts->fOptSet & OPTPROC_ENVIRON) != 0) { 1191290001Sglebius if (need_intro) 1192290001Sglebius fputs(zPresetIntro, option_usage_fp); 1193181834Sroberto 1194290001Sglebius fprintf(option_usage_fp, zExamineFmt, opts->pzPROGNAME); 1195181834Sroberto } 1196181834Sroberto 1197181834Sroberto /* 1198181834Sroberto * IF we found an enumeration, 1199181834Sroberto * THEN hunt for it again. Call the handler proc with a NULL 1200181834Sroberto * option struct pointer. That tells it to display the keywords. 1201181834Sroberto */ 1202181834Sroberto if (displayEnum) { 1203290001Sglebius int ct = opts->optCt; 1204181834Sroberto int optNo = 0; 1205290001Sglebius tOptDesc * od = opts->pOptDesc; 1206181834Sroberto 1207290001Sglebius fputc(NL, option_usage_fp); 1208290001Sglebius fflush(option_usage_fp); 1209181834Sroberto do { 1210290001Sglebius switch (OPTST_GET_ARGTYPE(od->fOptState)) { 1211181834Sroberto case OPARG_TYPE_ENUMERATION: 1212181834Sroberto case OPARG_TYPE_MEMBERSHIP: 1213290001Sglebius (*(od->pOptProc))(OPTPROC_EMIT_USAGE, od); 1214181834Sroberto } 1215290001Sglebius } while (od++, optNo++, (--ct > 0)); 1216181834Sroberto } 1217181834Sroberto 1218181834Sroberto /* 1219181834Sroberto * If there is a detail string, now is the time for that. 1220181834Sroberto */ 1221290001Sglebius if (opts->pzDetail != NULL) 1222290001Sglebius fputs(opts->pzDetail, option_usage_fp); 1223181834Sroberto} 1224181834Sroberto 1225181834Sroberto 1226181834Sroberto/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1227181834Sroberto * 1228181834Sroberto * OPTION LINE FORMATTING SETUP 1229181834Sroberto * 1230181834Sroberto * The "OptFmt" formats receive three arguments: 1231181834Sroberto * 1. the type of the option's argument 1232181834Sroberto * 2. the long name of the option 1233181834Sroberto * 3. "YES" or "no ", depending on whether or not the option must appear 1234181834Sroberto * on the command line. 1235181834Sroberto * These formats are used immediately after the option flag (if used) has 1236181834Sroberto * been printed. 1237181834Sroberto * 1238181834Sroberto * Set up the formatting for GNU-style output 1239181834Sroberto */ 1240181834Srobertostatic int 1241290001SglebiussetGnuOptFmts(tOptions * opts, char const ** ptxt) 1242181834Sroberto{ 1243290001Sglebius static char const zOneSpace[] = " "; 1244181834Sroberto int flen = 22; 1245290001Sglebius *ptxt = zNoRq_ShrtTtl; 1246181834Sroberto 1247181834Sroberto argTypes.pzStr = zGnuStrArg; 1248181834Sroberto argTypes.pzReq = zOneSpace; 1249181834Sroberto argTypes.pzNum = zGnuNumArg; 1250181834Sroberto argTypes.pzKey = zGnuKeyArg; 1251181834Sroberto argTypes.pzKeyL = zGnuKeyLArg; 1252290001Sglebius argTypes.pzTime = zGnuTimeArg; 1253290001Sglebius argTypes.pzFile = zGnuFileArg; 1254181834Sroberto argTypes.pzBool = zGnuBoolArg; 1255181834Sroberto argTypes.pzNest = zGnuNestArg; 1256181834Sroberto argTypes.pzOpt = zGnuOptArg; 1257181834Sroberto argTypes.pzNo = zOneSpace; 1258181834Sroberto argTypes.pzBrk = zGnuBreak; 1259181834Sroberto argTypes.pzNoF = zSixSpaces; 1260181834Sroberto argTypes.pzSpc = zThreeSpaces; 1261181834Sroberto 1262290001Sglebius switch (opts->fOptSet & OPTPROC_L_N_S) { 1263181834Sroberto case OPTPROC_L_N_S: argTypes.pzOptFmt = zGnuOptFmt; break; 1264181834Sroberto case OPTPROC_LONGOPT: argTypes.pzOptFmt = zGnuOptFmt; break; 1265181834Sroberto case 0: argTypes.pzOptFmt = zGnuOptFmt + 2; break; 1266181834Sroberto case OPTPROC_SHORTOPT: 1267181834Sroberto argTypes.pzOptFmt = zShrtGnuOptFmt; 1268181834Sroberto zGnuStrArg[0] = zGnuNumArg[0] = zGnuKeyArg[0] = zGnuBoolArg[0] = ' '; 1269181834Sroberto argTypes.pzOpt = " [arg]"; 1270181834Sroberto flen = 8; 1271181834Sroberto break; 1272181834Sroberto } 1273181834Sroberto 1274181834Sroberto return flen; 1275181834Sroberto} 1276181834Sroberto 1277181834Sroberto 1278181834Sroberto/* 1279181834Sroberto * Standard (AutoOpts normal) option line formatting 1280181834Sroberto */ 1281181834Srobertostatic int 1282290001SglebiussetStdOptFmts(tOptions * opts, char const ** ptxt) 1283181834Sroberto{ 1284181834Sroberto int flen = 0; 1285181834Sroberto 1286181834Sroberto argTypes.pzStr = zStdStrArg; 1287181834Sroberto argTypes.pzReq = zStdReqArg; 1288181834Sroberto argTypes.pzNum = zStdNumArg; 1289181834Sroberto argTypes.pzKey = zStdKeyArg; 1290181834Sroberto argTypes.pzKeyL = zStdKeyLArg; 1291290001Sglebius argTypes.pzTime = zStdTimeArg; 1292290001Sglebius argTypes.pzFile = zStdFileArg; 1293181834Sroberto argTypes.pzBool = zStdBoolArg; 1294181834Sroberto argTypes.pzNest = zStdNestArg; 1295181834Sroberto argTypes.pzOpt = zStdOptArg; 1296181834Sroberto argTypes.pzNo = zStdNoArg; 1297181834Sroberto argTypes.pzBrk = zStdBreak; 1298181834Sroberto argTypes.pzNoF = zFiveSpaces; 1299181834Sroberto argTypes.pzSpc = zTwoSpaces; 1300181834Sroberto 1301290001Sglebius switch (opts->fOptSet & (OPTPROC_NO_REQ_OPT | OPTPROC_SHORTOPT)) { 1302181834Sroberto case (OPTPROC_NO_REQ_OPT | OPTPROC_SHORTOPT): 1303290001Sglebius *ptxt = zNoRq_ShrtTtl; 1304181834Sroberto argTypes.pzOptFmt = zNrmOptFmt; 1305181834Sroberto flen = 19; 1306181834Sroberto break; 1307181834Sroberto 1308181834Sroberto case OPTPROC_NO_REQ_OPT: 1309290001Sglebius *ptxt = zNoRq_NoShrtTtl; 1310181834Sroberto argTypes.pzOptFmt = zNrmOptFmt; 1311181834Sroberto flen = 19; 1312181834Sroberto break; 1313181834Sroberto 1314181834Sroberto case OPTPROC_SHORTOPT: 1315290001Sglebius *ptxt = zReq_ShrtTtl; 1316181834Sroberto argTypes.pzOptFmt = zReqOptFmt; 1317181834Sroberto flen = 24; 1318181834Sroberto break; 1319181834Sroberto 1320181834Sroberto case 0: 1321290001Sglebius *ptxt = zReq_NoShrtTtl; 1322181834Sroberto argTypes.pzOptFmt = zReqOptFmt; 1323181834Sroberto flen = 24; 1324181834Sroberto } 1325181834Sroberto 1326181834Sroberto return flen; 1327181834Sroberto} 1328181834Sroberto 1329290001Sglebius/** @} 1330290001Sglebius * 1331181834Sroberto * Local Variables: 1332181834Sroberto * mode: C 1333181834Sroberto * c-file-style: "stroustrup" 1334181834Sroberto * indent-tabs-mode: nil 1335181834Sroberto * End: 1336181834Sroberto * end of autoopts/usage.c */ 1337