usage.c 37 KB

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