usage.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. /*
  2. * usage.c $Id: usage.c,v 4.7 2005/03/13 19:51:59 bkorb Exp $
  3. * Time-stamp: "2005-02-20 13:47:52 bkorb"
  4. *
  5. * This module implements the default usage procedure for
  6. * Automated Options. It may be overridden, of course.
  7. */
  8. /*
  9. * Automated Options copyright 1992-2005 Bruce Korb
  10. *
  11. * Automated Options is free software.
  12. * You may redistribute it and/or modify it under the terms of the
  13. * GNU General Public License, as published by the Free Software
  14. * Foundation; either version 2, or (at your option) any later version.
  15. *
  16. * Automated Options is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with Automated Options. See the file "COPYING". If not,
  23. * write to: The Free Software Foundation, Inc.,
  24. * 59 Temple Place - Suite 330,
  25. * Boston, MA 02111-1307, USA.
  26. *
  27. * As a special exception, Bruce Korb gives permission for additional
  28. * uses of the text contained in his release of AutoOpts.
  29. *
  30. * The exception is that, if you link the AutoOpts library with other
  31. * files to produce an executable, this does not by itself cause the
  32. * resulting executable to be covered by the GNU General Public License.
  33. * Your use of that executable is in no way restricted on account of
  34. * linking the AutoOpts library code into it.
  35. *
  36. * This exception does not however invalidate any other reasons why
  37. * the executable file might be covered by the GNU General Public License.
  38. *
  39. * This exception applies only to the code released by Bruce Korb under
  40. * the name AutoOpts. If you copy code from other sources under the
  41. * General Public License into a copy of AutoOpts, as the General Public
  42. * License permits, the exception does not apply to the code that you add
  43. * in this way. To avoid misleading anyone as to the status of such
  44. * modified files, you must delete this exception notice from them.
  45. *
  46. * If you write modifications of your own for AutoOpts, it is your choice
  47. * whether to permit this exception to apply to your modifications.
  48. * If you do not wish that, delete this exception notice.
  49. */
  50. #define OPTPROC_L_N_S (OPTPROC_LONGOPT | OPTPROC_SHORTOPT)
  51. #ifndef tSC
  52. # define tSC static char
  53. #endif
  54. static arg_types_t argTypes;
  55. FILE* option_usage_fp = NULL;
  56. static char zOptFmtLine[ 16 ];
  57. static ag_bool displayEnum;
  58. /* = = = START-STATIC-FORWARD = = = */
  59. /* static forward declarations maintained by :mkfwd */
  60. static void
  61. printProgramDetails( tOptions* pOptions );
  62. static void
  63. printExtendedUsage(
  64. tOptions* pOptions,
  65. tOptDesc* pOD,
  66. arg_types_t* pAT );
  67. static void
  68. printBareUsage(
  69. tOptions* pOptions,
  70. tOptDesc* pOD,
  71. arg_types_t* pAT );
  72. static void
  73. setStdOptFmts( tOptions* pOpts, tCC** ppT );
  74. static void
  75. setGnuOptFmts( tOptions* pOpts, tCC** ppT );
  76. static void
  77. printInitList(
  78. tCC** papz,
  79. ag_bool* pInitIntro,
  80. tCC* pzRc,
  81. tCC* pzPN );
  82. /* = = = END-STATIC-FORWARD = = = */
  83. /*=export_func optionUsage
  84. * private:
  85. *
  86. * what: Print usage text
  87. * arg: + tOptions* + pOpts + program options descriptor +
  88. * arg: + int + exitCode + exit code for calling exit(3) +
  89. *
  90. * doc:
  91. * This routine will print usage in both GNU-standard and AutoOpts-expanded
  92. * formats. The descriptor specifies the default, but AUTOOPTS_USAGE will
  93. * over-ride this, providing the value of it is set to either "gnu" or
  94. * "autoopts". This routine will @strong{not} return.
  95. =*/
  96. void
  97. optionUsage(
  98. tOptions* pOptions,
  99. int exitCode )
  100. {
  101. tCC* pOptTitle;
  102. displayEnum = AG_FALSE;
  103. /*
  104. * Paged usage will preset option_usage_fp to an output file.
  105. * If it hasn't already been set, then set it to standard output
  106. * on successful exit (help was requested), otherwise error out.
  107. */
  108. if (option_usage_fp == NULL)
  109. option_usage_fp = (exitCode != EXIT_SUCCESS) ? stderr : stdout;
  110. fprintf( option_usage_fp, pOptions->pzUsageTitle, pOptions->pzProgName );
  111. do {
  112. char* pz = getenv( "AUTOOPTS_USAGE" );
  113. if (pz == NULL) break;
  114. if (streqvcmp( pz, "gnu" ) == 0) {
  115. pOptions->fOptSet |= OPTPROC_GNUUSAGE;
  116. break;
  117. }
  118. if (streqvcmp( pz, "autoopts" ) == 0) {
  119. pOptions->fOptSet &= ~OPTPROC_GNUUSAGE;
  120. break;
  121. }
  122. } while (0);
  123. /*
  124. * Determine which header and which option formatting strings to use
  125. */
  126. if ((pOptions->fOptSet & OPTPROC_GNUUSAGE) != 0) {
  127. setGnuOptFmts( pOptions, &pOptTitle );
  128. fputc( '\n', option_usage_fp );
  129. }
  130. else {
  131. setStdOptFmts( pOptions, &pOptTitle );
  132. /*
  133. * When we exit with EXIT_SUCCESS and the first option is a doc option,
  134. * we do *NOT* want to emit the column headers. Otherwise, we do.
  135. */
  136. if ( (exitCode != EXIT_SUCCESS)
  137. || ((pOptions->pOptDesc->fOptState & OPTST_DOCUMENT) == 0) )
  138. fputs( pOptTitle, option_usage_fp );
  139. }
  140. {
  141. int ct = pOptions->optCt;
  142. int optNo = 0;
  143. tOptDesc* pOD = pOptions->pOptDesc;
  144. int docCt = 0;
  145. do {
  146. if ((pOD->fOptState & OPTST_OMITTED) != 0)
  147. continue;
  148. if ((pOD->fOptState & OPTST_DOCUMENT) != 0) {
  149. if (exitCode == EXIT_SUCCESS) {
  150. fprintf(option_usage_fp, argTypes.pzBrk, pOD->pzText,
  151. pOptTitle);
  152. docCt++;
  153. }
  154. continue;
  155. }
  156. /*
  157. * IF this is the first auto-opt maintained option
  158. * *AND* we are doing a full help
  159. * *AND* there are documentation options
  160. * *AND* the last one was not a doc option,
  161. * THEN document that the remaining options are not user opts
  162. */
  163. if ( (pOptions->presetOptCt == optNo)
  164. && (exitCode == EXIT_SUCCESS)
  165. && (docCt > 0)
  166. && ((pOD[-1].fOptState & OPTST_DOCUMENT) == 0) )
  167. fprintf( option_usage_fp, argTypes.pzBrk, zAuto, pOptTitle );
  168. printBareUsage( pOptions, pOD, &argTypes );
  169. /*
  170. * IF we were invoked because of the --help option,
  171. * THEN print all the extra info
  172. */
  173. if (exitCode == EXIT_SUCCESS)
  174. printExtendedUsage( pOptions, pOD, &argTypes );
  175. } while (pOD++, optNo++, (--ct > 0));
  176. }
  177. fputc( '\n', option_usage_fp );
  178. /*
  179. * Describe the mechanics of denoting the options
  180. */
  181. switch (pOptions->fOptSet & OPTPROC_L_N_S) {
  182. case OPTPROC_L_N_S: fputs( zFlagOkay, option_usage_fp ); break;
  183. case OPTPROC_SHORTOPT: break;
  184. case OPTPROC_LONGOPT: fputs( zNoFlags, option_usage_fp ); break;
  185. case 0: fputs( zOptsOnly, option_usage_fp ); break;
  186. }
  187. if ((pOptions->fOptSet & OPTPROC_NUM_OPT) != 0) {
  188. fputs( zNumberOpt, option_usage_fp );
  189. }
  190. if ((pOptions->fOptSet & OPTPROC_REORDER) != 0) {
  191. fputs( zReorder, option_usage_fp );
  192. }
  193. if (pOptions->pzExplain != NULL)
  194. fputs( pOptions->pzExplain, option_usage_fp );
  195. /*
  196. * IF the user is asking for help (thus exiting with SUCCESS),
  197. * THEN see what additional information we can provide.
  198. */
  199. if (exitCode == EXIT_SUCCESS)
  200. printProgramDetails( pOptions );
  201. if (pOptions->pzBugAddr != NULL)
  202. fprintf( option_usage_fp, zPlsSendBugs, pOptions->pzBugAddr );
  203. fflush( option_usage_fp );
  204. exit( exitCode );
  205. }
  206. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  207. *
  208. * PROGRAM DETAILS
  209. */
  210. static void
  211. printProgramDetails( tOptions* pOptions )
  212. {
  213. ag_bool initIntro = AG_TRUE;
  214. /*
  215. * Display all the places we look for config files
  216. */
  217. printInitList( pOptions->papzHomeList, &initIntro,
  218. pOptions->pzRcName, pOptions->pzProgPath );
  219. /*
  220. * Let the user know about environment variable settings
  221. */
  222. if ((pOptions->fOptSet & OPTPROC_ENVIRON) != 0) {
  223. if (initIntro)
  224. fputs( zPresetIntro, option_usage_fp );
  225. fprintf( option_usage_fp, zExamineFmt, pOptions->pzPROGNAME );
  226. }
  227. /*
  228. * IF we found an enumeration,
  229. * THEN hunt for it again. Call the handler proc with a NULL
  230. * option struct pointer. That tells it to display the keywords.
  231. */
  232. if (displayEnum) {
  233. int ct = pOptions->optCt;
  234. int optNo = 0;
  235. tOptDesc* pOD = pOptions->pOptDesc;
  236. fputc( '\n', option_usage_fp );
  237. fflush( option_usage_fp );
  238. do {
  239. switch (OPTST_GET_ARGTYPE(pOD->fOptState)) {
  240. case OPARG_TYPE_ENUMERATION:
  241. case OPARG_TYPE_MEMBERSHIP:
  242. (*(pOD->pOptProc))( NULL, pOD );
  243. }
  244. } while (pOD++, optNo++, (--ct > 0));
  245. }
  246. /*
  247. * If there is a detail string, now is the time for that.
  248. */
  249. if (pOptions->pzDetail != NULL)
  250. fputs( pOptions->pzDetail, option_usage_fp );
  251. }
  252. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  253. *
  254. * PER OPTION TYPE USAGE INFORMATION
  255. */
  256. static void
  257. printExtendedUsage(
  258. tOptions* pOptions,
  259. tOptDesc* pOD,
  260. arg_types_t* pAT )
  261. {
  262. /*
  263. * IF there are option conflicts or dependencies,
  264. * THEN print them here.
  265. */
  266. if ( (pOD->pOptMust != NULL)
  267. || (pOD->pOptCant != NULL) ) {
  268. fputs( zTabHyp, option_usage_fp );
  269. /*
  270. * DEPENDENCIES:
  271. */
  272. if (pOD->pOptMust != NULL) {
  273. const int* pOptNo = pOD->pOptMust;
  274. fputs( zReqThese, option_usage_fp );
  275. for (;;) {
  276. fprintf( option_usage_fp, zTabout, pOptions->pOptDesc[
  277. *pOptNo ].pz_Name );
  278. if (*++pOptNo == NO_EQUIVALENT)
  279. break;
  280. }
  281. if (pOD->pOptCant != NULL)
  282. fputs( zTabHypAnd, option_usage_fp );
  283. }
  284. /*
  285. * CONFLICTS:
  286. */
  287. if (pOD->pOptCant != NULL) {
  288. const int* pOptNo = pOD->pOptCant;
  289. fputs( zProhib, option_usage_fp );
  290. for (;;) {
  291. fprintf( option_usage_fp, zTabout, pOptions->pOptDesc[
  292. *pOptNo ].pz_Name );
  293. if (*++pOptNo == NO_EQUIVALENT)
  294. break;
  295. }
  296. }
  297. }
  298. /*
  299. * IF there is a disablement string
  300. * THEN print the disablement info
  301. */
  302. if (pOD->pz_DisableName != NULL )
  303. fprintf( option_usage_fp, zDis, pOD->pz_DisableName );
  304. /*
  305. * IF the numeric option has a special callback,
  306. * THEN call it, requesting the range or other special info
  307. */
  308. if ( (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_NUMERIC)
  309. && (pOD->pOptProc != NULL)
  310. && (pOD->pOptProc != optionNumericVal) ) {
  311. (*(pOD->pOptProc))( pOptions, NULL );
  312. }
  313. /*
  314. * IF the option defaults to being enabled,
  315. * THEN print that out
  316. */
  317. if (pOD->fOptState & OPTST_INITENABLED)
  318. fputs( zEnab, option_usage_fp );
  319. /*
  320. * IF the option is in an equivalence class
  321. * AND not the designated lead
  322. * THEN print equivalence and leave it at that.
  323. */
  324. if ( (pOD->optEquivIndex != NO_EQUIVALENT)
  325. && (pOD->optEquivIndex != pOD->optActualIndex ) ) {
  326. fprintf( option_usage_fp, zAlt,
  327. pOptions->pOptDesc[ pOD->optEquivIndex ].pz_Name );
  328. return;
  329. }
  330. /*
  331. * IF this particular option can NOT be preset
  332. * AND some form of presetting IS allowed,
  333. * THEN advise that this option may not be preset.
  334. */
  335. if ( ((pOD->fOptState & OPTST_NO_INIT) != 0)
  336. && ( (pOptions->papzHomeList != NULL)
  337. || (pOptions->pzPROGNAME != NULL)
  338. ) )
  339. fputs( zNoPreset, option_usage_fp );
  340. /*
  341. * Print the appearance requirements.
  342. */
  343. if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_MEMBERSHIP)
  344. fputs( zMembers, option_usage_fp );
  345. else switch (pOD->optMinCt) {
  346. case 1:
  347. case 0:
  348. switch (pOD->optMaxCt) {
  349. case 0: fputs( zPreset, option_usage_fp ); break;
  350. case NOLIMIT: fputs( zNoLim, option_usage_fp ); break;
  351. case 1: break;
  352. /*
  353. * IF the max is more than one but limited, print "UP TO" message
  354. */
  355. default: fprintf( option_usage_fp, zUpTo, pOD->optMaxCt ); break;
  356. }
  357. break;
  358. default:
  359. /*
  360. * More than one is required. Print the range.
  361. */
  362. fprintf( option_usage_fp, zMust, pOD->optMinCt, pOD->optMaxCt );
  363. }
  364. if ( NAMED_OPTS( pOptions )
  365. && (pOptions->specOptIdx.default_opt == pOD->optIndex))
  366. fputs( zDefaultOpt, option_usage_fp );
  367. }
  368. static void
  369. printBareUsage(
  370. tOptions* pOptions,
  371. tOptDesc* pOD,
  372. arg_types_t* pAT )
  373. {
  374. /*
  375. * Flag prefix: IF no flags at all, then omit it. If not printable
  376. * (not allowed for this option), then blank, else print it.
  377. * Follow it with a comma if we are doing GNU usage and long
  378. * opts are to be printed too.
  379. */
  380. if ((pOptions->fOptSet & OPTPROC_SHORTOPT) == 0)
  381. fputs( pAT->pzSpc, option_usage_fp );
  382. else if (! isgraph( pOD->optValue)) {
  383. if ( (pOptions->fOptSet & (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT))
  384. == (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT))
  385. fputc( ' ', option_usage_fp );
  386. fputs( pAT->pzNoF, option_usage_fp );
  387. } else {
  388. fprintf( option_usage_fp, " -%c", pOD->optValue );
  389. if ( (pOptions->fOptSet & (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT))
  390. == (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT))
  391. fputs( ", ", option_usage_fp );
  392. }
  393. {
  394. char z[ 80 ];
  395. tCC* pzArgType;
  396. /*
  397. * Determine the argument type string first on its usage, then,
  398. * when the option argument is required, base the type string on the
  399. * argument type.
  400. */
  401. if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_NONE) {
  402. pzArgType = pAT->pzNo;
  403. } else if (pOD->fOptState & OPTST_ARG_OPTIONAL) {
  404. pzArgType = pAT->pzOpt;
  405. } else switch (OPTST_GET_ARGTYPE(pOD->fOptState)) {
  406. case OPARG_TYPE_ENUMERATION: pzArgType = pAT->pzKey; break;
  407. case OPARG_TYPE_MEMBERSHIP: pzArgType = pAT->pzKeyL; break;
  408. case OPARG_TYPE_BOOLEAN: pzArgType = pAT->pzBool; break;
  409. case OPARG_TYPE_NUMERIC: pzArgType = pAT->pzNum; break;
  410. case OPARG_TYPE_HIERARCHY: pzArgType = pAT->pzNest; break;
  411. case OPARG_TYPE_STRING: pzArgType = pAT->pzStr; break;
  412. default: goto bogus_desc; break;
  413. }
  414. snprintf( z, sizeof(z), pAT->pzOptFmt, pzArgType, pOD->pz_Name,
  415. (pOD->optMinCt != 0) ? pAT->pzReq : pAT->pzOpt );
  416. fprintf( option_usage_fp, zOptFmtLine, z, pOD->pzText );
  417. switch (OPTST_GET_ARGTYPE(pOD->fOptState)) {
  418. case OPARG_TYPE_ENUMERATION:
  419. case OPARG_TYPE_MEMBERSHIP:
  420. displayEnum |= (pOD->pOptProc != NULL) ? AG_TRUE : AG_FALSE;
  421. }
  422. }
  423. return;
  424. bogus_desc:
  425. fprintf( stderr, zInvalOptDesc, pOD->pz_Name );
  426. exit( EXIT_FAILURE );
  427. }
  428. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  429. *
  430. * OPTION LINE FORMATTING SETUP
  431. *
  432. * The "OptFmt" formats receive three arguments:
  433. * 1. the type of the option's argument
  434. * 2. the long name of the option
  435. * 3. "YES" or "no ", depending on whether or not the option must appear
  436. * on the command line.
  437. * These formats are used immediately after the option flag (if used) has
  438. * been printed.
  439. */
  440. static void
  441. setStdOptFmts( tOptions* pOpts, tCC** ppT )
  442. {
  443. int flen = 0;
  444. argTypes.pzStr = zStdStrArg;
  445. argTypes.pzReq = zStdReqArg;
  446. argTypes.pzNum = zStdNumArg;
  447. argTypes.pzKey = zStdKeyArg;
  448. argTypes.pzKeyL = zStdKeyLArg;
  449. argTypes.pzBool = zStdBoolArg;
  450. argTypes.pzNest = zStdNestArg;
  451. argTypes.pzOpt = zStdOptArg;
  452. argTypes.pzNo = zStdNoArg;
  453. argTypes.pzBrk = zStdBreak;
  454. argTypes.pzNoF = zFiveSpaces;
  455. argTypes.pzSpc = zTwoSpaces;
  456. switch (pOpts->fOptSet & (OPTPROC_NO_REQ_OPT | OPTPROC_SHORTOPT)) {
  457. case (OPTPROC_NO_REQ_OPT | OPTPROC_SHORTOPT):
  458. *ppT = zNoRq_ShrtTtl;
  459. argTypes.pzOptFmt = zNrmOptFmt;
  460. flen = 19;
  461. break;
  462. case OPTPROC_NO_REQ_OPT:
  463. *ppT = zNoRq_NoShrtTtl;
  464. argTypes.pzOptFmt = zNrmOptFmt;
  465. flen = 19;
  466. break;
  467. case OPTPROC_SHORTOPT:
  468. *ppT = zReq_ShrtTtl;
  469. argTypes.pzOptFmt = zReqOptFmt;
  470. flen = 24;
  471. break;
  472. case 0:
  473. *ppT = zReq_NoShrtTtl;
  474. argTypes.pzOptFmt = zReqOptFmt;
  475. flen = 24;
  476. }
  477. sprintf( zOptFmtLine, zFmtFmt, flen );
  478. }
  479. static void
  480. setGnuOptFmts( tOptions* pOpts, tCC** ppT )
  481. {
  482. int flen = 22;
  483. *ppT = zNoRq_ShrtTtl;
  484. argTypes.pzStr = zGnuStrArg;
  485. argTypes.pzReq = zOneSpace;
  486. argTypes.pzNum = zGnuNumArg;
  487. argTypes.pzKey = zGnuKeyArg;
  488. argTypes.pzKeyL = zGnuKeyLArg;
  489. argTypes.pzBool = zGnuBoolArg;
  490. argTypes.pzNest = zGnuNestArg;
  491. argTypes.pzOpt = zGnuOptArg;
  492. argTypes.pzNo = zOneSpace;
  493. argTypes.pzBrk = zGnuBreak;
  494. argTypes.pzNoF = zSixSpaces;
  495. argTypes.pzSpc = zThreeSpaces;
  496. switch (pOpts->fOptSet & OPTPROC_L_N_S) {
  497. case OPTPROC_L_N_S: argTypes.pzOptFmt = zGnuOptFmt; break;
  498. case OPTPROC_LONGOPT: argTypes.pzOptFmt = zGnuOptFmt; break;
  499. case 0: argTypes.pzOptFmt = zGnuOptFmt + 2; break;
  500. case OPTPROC_SHORTOPT:
  501. argTypes.pzOptFmt = zShrtGnuOptFmt;
  502. zGnuStrArg[0] = zGnuNumArg[0] = zGnuKeyArg[0] = zGnuBoolArg[0] = ' ';
  503. argTypes.pzOpt = " [arg]";
  504. flen = 8;
  505. break;
  506. }
  507. sprintf( zOptFmtLine, zFmtFmt, flen );
  508. }
  509. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  510. *
  511. * Figure out where all the initialization files might live.
  512. * This requires translating some environment variables and
  513. * testing to see if a name is a directory or a file. It's
  514. * squishy, but important to tell users how to find these files.
  515. */
  516. static void
  517. printInitList(
  518. tCC** papz,
  519. ag_bool* pInitIntro,
  520. tCC* pzRc,
  521. tCC* pzPN )
  522. {
  523. char zPath[ MAXPATHLEN+1 ];
  524. if (papz == NULL)
  525. return;
  526. fputs( zPresetIntro, option_usage_fp );
  527. *pInitIntro = AG_FALSE;
  528. for (;;) {
  529. const char* pzPath = *(papz++);
  530. if (pzPath == NULL)
  531. break;
  532. if (optionMakePath( zPath, sizeof( zPath ), pzPath, pzPN ))
  533. pzPath = zPath;
  534. /*
  535. * Print the name of the "homerc" file. If the "rcfile" name is
  536. * not empty, we may or may not print that, too...
  537. */
  538. fprintf( option_usage_fp, zPathFmt, pzPath );
  539. if (*pzRc != NUL) {
  540. struct stat sb;
  541. /*
  542. * IF the "homerc" file is a directory,
  543. * then append the "rcfile" name.
  544. */
  545. if ( (stat( pzPath, &sb ) == 0)
  546. && S_ISDIR( sb.st_mode ) ) {
  547. fputc( '/', option_usage_fp );
  548. fputs( pzRc, option_usage_fp );
  549. }
  550. }
  551. fputc( '\n', option_usage_fp );
  552. }
  553. }
  554. /*
  555. * Local Variables:
  556. * mode: C
  557. * c-file-style: "stroustrup"
  558. * tab-width: 4
  559. * indent-tabs-mode: nil
  560. * End:
  561. * end of autoopts/usage.c */