popthelp.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827
  1. /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
  2. /** \ingroup popt
  3. * \file popt/popthelp.c
  4. */
  5. /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
  6. file accompanying popt source distributions, available from
  7. ftp://ftp.rpm.org/pub/rpm/dist. */
  8. #include "system.h"
  9. /*#define POPT_WCHAR_HACK*/
  10. #ifdef POPT_WCHAR_HACK
  11. #include <wchar.h> /* for mbsrtowcs */
  12. /*@access mbstate_t @*/
  13. #endif
  14. #include "poptint.h"
  15. /*@access poptContext@*/
  16. /**
  17. * Display arguments.
  18. * @param con context
  19. * @param foo (unused)
  20. * @param key option(s)
  21. * @param arg (unused)
  22. * @param data (unused)
  23. */
  24. static void displayArgs(poptContext con,
  25. /*@unused@*/ UNUSED(enum poptCallbackReason foo),
  26. struct poptOption * key,
  27. /*@unused@*/ UNUSED(const char * arg), /*@unused@*/ UNUSED(void * data))
  28. /*@globals fileSystem@*/
  29. /*@modifies fileSystem@*/
  30. {
  31. if (key->shortName == '?')
  32. poptPrintHelp(con, stdout, 0);
  33. else
  34. poptPrintUsage(con, stdout, 0);
  35. exit(0);
  36. }
  37. #ifdef NOTYET
  38. /*@unchecked@*/
  39. static int show_option_defaults = 0;
  40. #endif
  41. /**
  42. * Empty table marker to enable displaying popt alias/exec options.
  43. */
  44. /*@observer@*/ /*@unchecked@*/
  45. struct poptOption poptAliasOptions[] = {
  46. POPT_TABLEEND
  47. };
  48. /**
  49. * Auto help table options.
  50. */
  51. /*@-castfcnptr@*/
  52. /*@observer@*/ /*@unchecked@*/
  53. struct poptOption poptHelpOptions[] = {
  54. { NULL, '\0', POPT_ARG_CALLBACK, (void *)&displayArgs, '\0', NULL, NULL },
  55. { "help", '?', 0, NULL, '?', N_("Show this help message"), NULL },
  56. { "usage", '\0', 0, NULL, 'u', N_("Display brief usage message"), NULL },
  57. POPT_TABLEEND
  58. } ;
  59. /*@observer@*/ /*@unchecked@*/
  60. static struct poptOption poptHelpOptions2[] = {
  61. /*@-readonlytrans@*/
  62. { NULL, '\0', POPT_ARG_INTL_DOMAIN, PACKAGE, 0, NULL, NULL},
  63. /*@=readonlytrans@*/
  64. { NULL, '\0', POPT_ARG_CALLBACK, (void *)&displayArgs, '\0', NULL, NULL },
  65. { "help", '?', 0, NULL, '?', N_("Show this help message"), NULL },
  66. { "usage", '\0', 0, NULL, 'u', N_("Display brief usage message"), NULL },
  67. #ifdef NOTYET
  68. { "defaults", '\0', POPT_ARG_NONE, &show_option_defaults, 0,
  69. N_("Display option defaults in message"), NULL },
  70. #endif
  71. POPT_TABLEEND
  72. } ;
  73. /*@observer@*/ /*@unchecked@*/
  74. struct poptOption * poptHelpOptionsI18N = poptHelpOptions2;
  75. /*@=castfcnptr@*/
  76. /**
  77. * @param table option(s)
  78. */
  79. /*@observer@*/ /*@null@*/ static const char *
  80. getTableTranslationDomain(/*@null@*/ const struct poptOption *table)
  81. /*@*/
  82. {
  83. const struct poptOption *opt;
  84. if (table != NULL)
  85. for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) {
  86. if (opt->argInfo == POPT_ARG_INTL_DOMAIN)
  87. return opt->arg;
  88. }
  89. return NULL;
  90. }
  91. /**
  92. * @param opt option(s)
  93. * @param translation_domain translation domain
  94. */
  95. /*@observer@*/ /*@null@*/ static const char *
  96. getArgDescrip(const struct poptOption * opt,
  97. /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */
  98. /*@null@*/ UNUSED(const char * translation_domain))
  99. /*@=paramuse@*/
  100. /*@*/
  101. {
  102. if (!(opt->argInfo & POPT_ARG_MASK)) return NULL;
  103. if (opt == (poptHelpOptions + 1) || opt == (poptHelpOptions + 2))
  104. if (opt->argDescrip) return POPT_(opt->argDescrip);
  105. if (opt->argDescrip) return D_(translation_domain, opt->argDescrip);
  106. switch (opt->argInfo & POPT_ARG_MASK) {
  107. /*case POPT_ARG_NONE: return POPT_("NONE");*/ /* impossible */
  108. #ifdef DYING
  109. case POPT_ARG_VAL: return POPT_("VAL");
  110. #else
  111. case POPT_ARG_VAL: return NULL;
  112. #endif
  113. case POPT_ARG_INT: return POPT_("INT");
  114. case POPT_ARG_LONG: return POPT_("LONG");
  115. case POPT_ARG_STRING: return POPT_("STRING");
  116. case POPT_ARG_FLOAT: return POPT_("FLOAT");
  117. case POPT_ARG_DOUBLE: return POPT_("DOUBLE");
  118. default: return POPT_("ARG");
  119. }
  120. }
  121. /**
  122. * Display default value for an option.
  123. * @param lineLength display positions remaining
  124. * @param opt option(s)
  125. * @param translation_domain translation domain
  126. * @return
  127. */
  128. static /*@only@*/ /*@null@*/ char *
  129. singleOptionDefaultValue(size_t lineLength,
  130. const struct poptOption * opt,
  131. /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */
  132. /*@null@*/ UNUSED(const char * translation_domain))
  133. /*@=paramuse@*/
  134. /*@*/
  135. {
  136. const char * defstr = D_(translation_domain, "default");
  137. size_t limit, bufsize = 4*lineLength + 1;
  138. char * le = malloc(bufsize);
  139. char * l = le;
  140. if (le == NULL) return NULL; /* XXX can't happen */
  141. /*@-boundswrite@*/
  142. *le++ = '(';
  143. le += strlcpy(le, defstr, bufsize - 3);
  144. *le++ = ':';
  145. *le++ = ' ';
  146. limit = bufsize - (le - l) - 1; /* -1 for closing paren */
  147. if (opt->arg) /* XXX programmer error */
  148. switch (opt->argInfo & POPT_ARG_MASK) {
  149. case POPT_ARG_VAL:
  150. case POPT_ARG_INT:
  151. { long aLong = *((int *)opt->arg);
  152. le += snprintf(le, limit, "%ld", aLong);
  153. } break;
  154. case POPT_ARG_LONG:
  155. { long aLong = *((long *)opt->arg);
  156. le += snprintf(le, limit, "%ld", aLong);
  157. } break;
  158. case POPT_ARG_FLOAT:
  159. { double aDouble = *((float *)opt->arg);
  160. le += snprintf(le, limit, "%g", aDouble);
  161. } break;
  162. case POPT_ARG_DOUBLE:
  163. { double aDouble = *((double *)opt->arg);
  164. le += snprintf(le, limit, "%g", aDouble);
  165. } break;
  166. case POPT_ARG_STRING:
  167. { const char * s = *(const char **)opt->arg;
  168. if (s == NULL) {
  169. le += strlcpy(le, "null", limit);
  170. } else {
  171. size_t len;
  172. limit -= 2; /* make room for quotes */
  173. *le++ = '"';
  174. len = strlcpy(le, s, limit);
  175. if (len >= limit) {
  176. le += limit - 3 - 1;
  177. *le++ = '.'; *le++ = '.'; *le++ = '.';
  178. } else
  179. le += len;
  180. *le++ = '"';
  181. }
  182. } break;
  183. case POPT_ARG_NONE:
  184. default:
  185. l = _free(l);
  186. return NULL;
  187. /*@notreached@*/ break;
  188. }
  189. *le++ = ')';
  190. *le = '\0';
  191. /*@=boundswrite@*/
  192. return l;
  193. }
  194. /**
  195. * Display help text for an option.
  196. * @param fp output file handle
  197. * @param maxLeftCol largest argument display width
  198. * @param opt option(s)
  199. * @param translation_domain translation domain
  200. */
  201. static void singleOptionHelp(FILE * fp, size_t maxLeftCol,
  202. const struct poptOption * opt,
  203. /*@null@*/ UNUSED(const char * translation_domain))
  204. /*@globals fileSystem @*/
  205. /*@modifies *fp, fileSystem @*/
  206. {
  207. size_t indentLength = maxLeftCol + 5;
  208. size_t lineLength = 79 - indentLength;
  209. const char * help = D_(translation_domain, opt->descrip);
  210. const char * argDescrip = getArgDescrip(opt, translation_domain);
  211. size_t helpLength;
  212. char * defs = NULL;
  213. char * left;
  214. size_t lelen, limit;
  215. size_t nb = maxLeftCol + 1;
  216. int displaypad = 0;
  217. /* Make sure there's more than enough room in target buffer. */
  218. if (opt->longName) nb += strlen(opt->longName);
  219. if (argDescrip) nb += strlen(argDescrip);
  220. /*@-boundswrite@*/
  221. left = malloc(nb);
  222. if (left == NULL) return; /* XXX can't happen */
  223. left[0] = '\0';
  224. left[maxLeftCol] = '\0';
  225. if (opt->longName && opt->shortName)
  226. snprintf(left, nb, "-%c, %s%s", opt->shortName,
  227. ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
  228. opt->longName);
  229. else if (opt->shortName != '\0')
  230. snprintf(left, nb, "-%c", opt->shortName);
  231. else if (opt->longName)
  232. snprintf(left, nb, "%s%s",
  233. ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
  234. opt->longName);
  235. if (!*left) goto out;
  236. if (argDescrip) {
  237. char * le = left + strlen(left);
  238. if (opt->argInfo & POPT_ARGFLAG_OPTIONAL)
  239. *le++ = '[';
  240. /* Choose type of output */
  241. /*@-branchstate@*/
  242. if (opt->argInfo & POPT_ARGFLAG_SHOW_DEFAULT) {
  243. defs = singleOptionDefaultValue(lineLength, opt, translation_domain);
  244. if (defs) {
  245. size_t bufsize = (help ? strlen(help) : 0) + sizeof " " + strlen(defs);
  246. char * t = malloc(bufsize);
  247. if (t) {
  248. snprintf(t, bufsize, "%s %s", help ? help : "", defs);
  249. defs = _free(defs);
  250. }
  251. defs = t;
  252. }
  253. }
  254. /*@=branchstate@*/
  255. if (opt->argDescrip == NULL) {
  256. switch (opt->argInfo & POPT_ARG_MASK) {
  257. case POPT_ARG_NONE:
  258. break;
  259. case POPT_ARG_VAL:
  260. #ifdef NOTNOW /* XXX pug ugly nerdy output */
  261. { long aLong = opt->val;
  262. int ops = (opt->argInfo & POPT_ARGFLAG_LOGICALOPS);
  263. int negate = (opt->argInfo & POPT_ARGFLAG_NOT);
  264. /* Don't bother displaying typical values */
  265. if (!ops && (aLong == 0L || aLong == 1L || aLong == -1L))
  266. break;
  267. *le++ = '[';
  268. switch (ops) {
  269. case POPT_ARGFLAG_OR:
  270. *le++ = '|';
  271. /*@innerbreak@*/ break;
  272. case POPT_ARGFLAG_AND:
  273. *le++ = '&';
  274. /*@innerbreak@*/ break;
  275. case POPT_ARGFLAG_XOR:
  276. *le++ = '^';
  277. /*@innerbreak@*/ break;
  278. default:
  279. /*@innerbreak@*/ break;
  280. }
  281. *le++ = (opt->longName != NULL ? '=' : ' ');
  282. if (negate) *le++ = '~';
  283. /*@-formatconst@*/
  284. limit = nb - (le - left);
  285. lelen = snprintf(le, limit, (ops ? "0x%lx" : "%ld"), aLong);
  286. le += lelen >= limit ? limit - 1 : lelen;
  287. /*@=formatconst@*/
  288. *le++ = ']';
  289. }
  290. #endif
  291. break;
  292. case POPT_ARG_INT:
  293. case POPT_ARG_LONG:
  294. case POPT_ARG_FLOAT:
  295. case POPT_ARG_DOUBLE:
  296. case POPT_ARG_STRING:
  297. *le++ = (opt->longName != NULL ? '=' : ' ');
  298. limit = nb - (le - left);
  299. lelen = strlcpy(le, argDescrip, limit);
  300. le += lelen >= limit ? limit - 1 : lelen;
  301. break;
  302. default:
  303. break;
  304. }
  305. } else {
  306. *le++ = '=';
  307. limit = nb - (le - left);
  308. lelen = strlcpy(le, argDescrip, limit);
  309. if (lelen >= limit)
  310. lelen = limit - 1;
  311. le += lelen;
  312. #ifdef POPT_WCHAR_HACK
  313. { const char * scopy = argDescrip;
  314. mbstate_t t;
  315. size_t n;
  316. memset ((void *)&t, '\0', sizeof (t)); /* In initial state. */
  317. /* Determine number of characters. */
  318. n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t);
  319. displaypad = (int) (lelen-n);
  320. }
  321. #endif
  322. }
  323. if (opt->argInfo & POPT_ARGFLAG_OPTIONAL)
  324. *le++ = ']';
  325. *le = '\0';
  326. }
  327. /*@=boundswrite@*/
  328. if (help)
  329. fprintf(fp," %-*s ", (int)maxLeftCol+displaypad, left);
  330. else {
  331. fprintf(fp," %s\n", left);
  332. goto out;
  333. }
  334. left = _free(left);
  335. /*@-branchstate@*/
  336. if (defs) {
  337. help = defs;
  338. defs = NULL;
  339. }
  340. /*@=branchstate@*/
  341. helpLength = strlen(help);
  342. /*@-boundsread@*/
  343. while (helpLength > lineLength) {
  344. const char * ch;
  345. char format[16];
  346. ch = help + lineLength - 1;
  347. while (ch > help && !isSpace(ch)) ch--;
  348. if (ch == help) break; /* give up */
  349. while (ch > (help + 1) && isSpace(ch)) ch--;
  350. ch++;
  351. snprintf(format, sizeof format, "%%.%ds\n%%%ds", (int) (ch - help), (int) indentLength);
  352. /*@-formatconst@*/
  353. fprintf(fp, format, help, " ");
  354. /*@=formatconst@*/
  355. help = ch;
  356. while (isSpace(help) && *help) help++;
  357. helpLength = strlen(help);
  358. }
  359. /*@=boundsread@*/
  360. if (helpLength) fprintf(fp, "%s\n", help);
  361. out:
  362. /*@-dependenttrans@*/
  363. defs = _free(defs);
  364. /*@=dependenttrans@*/
  365. left = _free(left);
  366. }
  367. /**
  368. * Find display width for longest argument string.
  369. * @param opt option(s)
  370. * @param translation_domain translation domain
  371. * @return display width
  372. */
  373. static size_t maxArgWidth(const struct poptOption * opt,
  374. /*@null@*/ UNUSED(const char * translation_domain))
  375. /*@*/
  376. {
  377. size_t max = 0;
  378. size_t len = 0;
  379. const char * s;
  380. if (opt != NULL)
  381. while (opt->longName || opt->shortName || opt->arg) {
  382. if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
  383. if (opt->arg) /* XXX program error */
  384. len = maxArgWidth(opt->arg, translation_domain);
  385. if (len > max) max = len;
  386. } else if (!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
  387. len = sizeof(" ")-1;
  388. if (opt->shortName != '\0') len += sizeof("-X")-1;
  389. if (opt->shortName != '\0' && opt->longName) len += sizeof(", ")-1;
  390. if (opt->longName) {
  391. len += ((opt->argInfo & POPT_ARGFLAG_ONEDASH)
  392. ? sizeof("-")-1 : sizeof("--")-1);
  393. len += strlen(opt->longName);
  394. }
  395. s = getArgDescrip(opt, translation_domain);
  396. #ifdef POPT_WCHAR_HACK
  397. /* XXX Calculate no. of display characters. */
  398. if (s) {
  399. const char * scopy = s;
  400. mbstate_t t;
  401. size_t n;
  402. /*@-boundswrite@*/
  403. memset ((void *)&t, '\0', sizeof (t)); /* In initial state. */
  404. /*@=boundswrite@*/
  405. /* Determine number of characters. */
  406. n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t);
  407. len += sizeof("=")-1 + n;
  408. }
  409. #else
  410. if (s)
  411. len += sizeof("=")-1 + strlen(s);
  412. #endif
  413. if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) len += sizeof("[]")-1;
  414. if (len > max) max = len;
  415. }
  416. opt++;
  417. }
  418. return max;
  419. }
  420. /**
  421. * Display popt alias and exec help.
  422. * @param fp output file handle
  423. * @param items alias/exec array
  424. * @param nitems no. of alias/exec entries
  425. * @param left largest argument display width
  426. * @param translation_domain translation domain
  427. */
  428. static void itemHelp(FILE * fp,
  429. /*@null@*/ poptItem items, int nitems, size_t left,
  430. /*@null@*/ UNUSED(const char * translation_domain))
  431. /*@globals fileSystem @*/
  432. /*@modifies *fp, fileSystem @*/
  433. {
  434. poptItem item;
  435. int i;
  436. if (items != NULL)
  437. for (i = 0, item = items; i < nitems; i++, item++) {
  438. const struct poptOption * opt;
  439. opt = &item->option;
  440. if ((opt->longName || opt->shortName) &&
  441. !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
  442. singleOptionHelp(fp, left, opt, translation_domain);
  443. }
  444. }
  445. /**
  446. * Display help text for a table of options.
  447. * @param con context
  448. * @param fp output file handle
  449. * @param table option(s)
  450. * @param left largest argument display width
  451. * @param translation_domain translation domain
  452. */
  453. static void singleTableHelp(poptContext con, FILE * fp,
  454. /*@null@*/ const struct poptOption * table, size_t left,
  455. /*@null@*/ UNUSED(const char * translation_domain))
  456. /*@globals fileSystem @*/
  457. /*@modifies *fp, fileSystem @*/
  458. {
  459. const struct poptOption * opt;
  460. const char *sub_transdom;
  461. if (table == poptAliasOptions) {
  462. itemHelp(fp, con->aliases, con->numAliases, left, NULL);
  463. itemHelp(fp, con->execs, con->numExecs, left, NULL);
  464. return;
  465. }
  466. if (table != NULL)
  467. for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) {
  468. if ((opt->longName || opt->shortName) &&
  469. !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
  470. singleOptionHelp(fp, left, opt, translation_domain);
  471. }
  472. if (table != NULL)
  473. for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) {
  474. if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_INCLUDE_TABLE)
  475. continue;
  476. sub_transdom = getTableTranslationDomain(opt->arg);
  477. if (sub_transdom == NULL)
  478. sub_transdom = translation_domain;
  479. if (opt->descrip)
  480. fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip));
  481. singleTableHelp(con, fp, opt->arg, left, sub_transdom);
  482. }
  483. }
  484. /**
  485. * @param con context
  486. * @param fp output file handle
  487. */
  488. static int showHelpIntro(poptContext con, FILE * fp)
  489. /*@globals fileSystem @*/
  490. /*@modifies *fp, fileSystem @*/
  491. {
  492. int len = 6;
  493. const char * fn;
  494. fprintf(fp, POPT_("Usage:"));
  495. if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) {
  496. /*@-boundsread@*/
  497. /*@-nullderef -type@*/ /* LCL: wazzup? */
  498. fn = con->optionStack->argv[0];
  499. /*@=nullderef =type@*/
  500. /*@=boundsread@*/
  501. if (fn == NULL) return len;
  502. if (strchr(fn, '/')) fn = strrchr(fn, '/') + 1;
  503. fprintf(fp, " %s", fn);
  504. len += strlen(fn) + 1;
  505. }
  506. return len;
  507. }
  508. void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags))
  509. {
  510. size_t leftColWidth;
  511. (void) showHelpIntro(con, fp);
  512. if (con->otherHelp)
  513. fprintf(fp, " %s\n", con->otherHelp);
  514. else
  515. fprintf(fp, " %s\n", POPT_("[OPTION...]"));
  516. leftColWidth = maxArgWidth(con->options, NULL);
  517. singleTableHelp(con, fp, con->options, leftColWidth, NULL);
  518. }
  519. /**
  520. * Display usage text for an option.
  521. * @param fp output file handle
  522. * @param cursor current display position
  523. * @param opt option(s)
  524. * @param translation_domain translation domain
  525. */
  526. static size_t singleOptionUsage(FILE * fp, size_t cursor,
  527. const struct poptOption * opt,
  528. /*@null@*/ const char *translation_domain)
  529. /*@globals fileSystem @*/
  530. /*@modifies *fp, fileSystem @*/
  531. {
  532. size_t len = 4;
  533. char shortStr[2] = { '\0', '\0' };
  534. const char * item = shortStr;
  535. const char * argDescrip = getArgDescrip(opt, translation_domain);
  536. if (opt->shortName != '\0' && opt->longName != NULL) {
  537. len += 2;
  538. if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++;
  539. len += strlen(opt->longName);
  540. } else if (opt->shortName != '\0') {
  541. len++;
  542. shortStr[0] = opt->shortName;
  543. shortStr[1] = '\0';
  544. } else if (opt->longName) {
  545. len += strlen(opt->longName);
  546. if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++;
  547. item = opt->longName;
  548. }
  549. if (len == 4) return cursor;
  550. #ifdef POPT_WCHAR_HACK
  551. /* XXX Calculate no. of display characters. */
  552. if (argDescrip) {
  553. const char * scopy = argDescrip;
  554. mbstate_t t;
  555. size_t n;
  556. /*@-boundswrite@*/
  557. memset ((void *)&t, '\0', sizeof (t)); /* In initial state. */
  558. /*@=boundswrite@*/
  559. /* Determine number of characters. */
  560. n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t);
  561. len += sizeof("=")-1 + n;
  562. }
  563. #else
  564. if (argDescrip)
  565. len += sizeof("=")-1 + strlen(argDescrip);
  566. #endif
  567. if ((cursor + len) > 79) {
  568. fprintf(fp, "\n ");
  569. cursor = 7;
  570. }
  571. if (opt->longName && opt->shortName) {
  572. fprintf(fp, " [-%c|-%s%s%s%s]",
  573. opt->shortName, ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "" : "-"),
  574. opt->longName,
  575. (argDescrip ? " " : ""),
  576. (argDescrip ? argDescrip : ""));
  577. } else {
  578. fprintf(fp, " [-%s%s%s%s]",
  579. ((opt->shortName || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) ? "" : "-"),
  580. item,
  581. (argDescrip ? (opt->shortName != '\0' ? " " : "=") : ""),
  582. (argDescrip ? argDescrip : ""));
  583. }
  584. return cursor + len + 1;
  585. }
  586. /**
  587. * Display popt alias and exec usage.
  588. * @param fp output file handle
  589. * @param cursor current display position
  590. * @param item alias/exec array
  591. * @param nitems no. of ara/exec entries
  592. * @param translation_domain translation domain
  593. */
  594. static size_t itemUsage(FILE * fp, size_t cursor,
  595. /*@null@*/ poptItem item, int nitems,
  596. /*@null@*/ UNUSED(const char * translation_domain))
  597. /*@globals fileSystem @*/
  598. /*@modifies *fp, fileSystem @*/
  599. {
  600. int i;
  601. /*@-branchstate@*/ /* FIX: W2DO? */
  602. if (item != NULL)
  603. for (i = 0; i < nitems; i++, item++) {
  604. const struct poptOption * opt;
  605. opt = &item->option;
  606. if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) {
  607. translation_domain = (const char *)opt->arg;
  608. } else if ((opt->longName || opt->shortName) &&
  609. !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
  610. cursor = singleOptionUsage(fp, cursor, opt, translation_domain);
  611. }
  612. }
  613. /*@=branchstate@*/
  614. return cursor;
  615. }
  616. /**
  617. * Keep track of option tables already processed.
  618. */
  619. typedef struct poptDone_s {
  620. int nopts;
  621. int maxopts;
  622. const void ** opts;
  623. } * poptDone;
  624. /**
  625. * Display usage text for a table of options.
  626. * @param con context
  627. * @param fp output file handle
  628. * @param cursor current display position
  629. * @param opt option(s)
  630. * @param translation_domain translation domain
  631. * @param done tables already processed
  632. * @return
  633. */
  634. static size_t singleTableUsage(poptContext con, FILE * fp, size_t cursor,
  635. /*@null@*/ const struct poptOption * opt,
  636. /*@null@*/ UNUSED(const char * translation_domain),
  637. /*@null@*/ poptDone done)
  638. /*@globals fileSystem @*/
  639. /*@modifies *fp, done, fileSystem @*/
  640. {
  641. /*@-branchstate@*/ /* FIX: W2DO? */
  642. if (opt != NULL)
  643. for (; (opt->longName || opt->shortName || opt->arg) ; opt++) {
  644. if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) {
  645. translation_domain = (const char *)opt->arg;
  646. } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
  647. if (done) {
  648. int i = 0;
  649. for (i = 0; i < done->nopts; i++) {
  650. /*@-boundsread@*/
  651. const void * that = done->opts[i];
  652. /*@=boundsread@*/
  653. if (that == NULL || that != opt->arg)
  654. /*@innercontinue@*/ continue;
  655. /*@innerbreak@*/ break;
  656. }
  657. /* Skip if this table has already been processed. */
  658. if (opt->arg == NULL || i < done->nopts)
  659. continue;
  660. /*@-boundswrite@*/
  661. if (done->nopts < done->maxopts)
  662. done->opts[done->nopts++] = (const void *) opt->arg;
  663. /*@=boundswrite@*/
  664. }
  665. cursor = singleTableUsage(con, fp, cursor, opt->arg,
  666. translation_domain, done);
  667. } else if ((opt->longName || opt->shortName) &&
  668. !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
  669. cursor = singleOptionUsage(fp, cursor, opt, translation_domain);
  670. }
  671. }
  672. /*@=branchstate@*/
  673. return cursor;
  674. }
  675. /**
  676. * Return concatenated short options for display.
  677. * @todo Sub-tables should be recursed.
  678. * @param opt option(s)
  679. * @param fp output file handle
  680. * @retval str concatenation of short options
  681. * @return length of display string
  682. */
  683. static int showShortOptions(const struct poptOption * opt, FILE * fp,
  684. /*@null@*/ char * str)
  685. /*@globals fileSystem @*/
  686. /*@modifies *str, *fp, fileSystem @*/
  687. /*@requires maxRead(str) >= 0 @*/
  688. {
  689. /* bufsize larger then the ascii set, lazy alloca on top level call. */
  690. char * s = (str != NULL ? str : memset(alloca(300), 0, 300));
  691. int len = 0;
  692. if (s == NULL)
  693. return 0;
  694. /*@-boundswrite@*/
  695. if (opt != NULL)
  696. for (; (opt->longName || opt->shortName || opt->arg); opt++) {
  697. if (opt->shortName && !(opt->argInfo & POPT_ARG_MASK))
  698. s[strlen(s)] = opt->shortName;
  699. else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE)
  700. if (opt->arg) /* XXX program error */
  701. len = showShortOptions(opt->arg, fp, s);
  702. }
  703. /*@=boundswrite@*/
  704. /* On return to top level, print the short options, return print length. */
  705. if (s == str && *s != '\0') {
  706. fprintf(fp, " [-%s]", s);
  707. len = strlen(s) + sizeof(" [-]")-1;
  708. }
  709. return len;
  710. }
  711. void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags))
  712. {
  713. poptDone done = memset(alloca(sizeof(*done)), 0, sizeof(*done));
  714. size_t cursor;
  715. done->nopts = 0;
  716. done->maxopts = 64;
  717. cursor = done->maxopts * sizeof(*done->opts);
  718. /*@-boundswrite@*/
  719. done->opts = memset(alloca(cursor), 0, cursor);
  720. /*@-keeptrans@*/
  721. done->opts[done->nopts++] = (const void *) con->options;
  722. /*@=keeptrans@*/
  723. /*@=boundswrite@*/
  724. cursor = showHelpIntro(con, fp);
  725. cursor += showShortOptions(con->options, fp, NULL);
  726. cursor = singleTableUsage(con, fp, cursor, con->options, NULL, done);
  727. cursor = itemUsage(fp, cursor, con->aliases, con->numAliases, NULL);
  728. cursor = itemUsage(fp, cursor, con->execs, con->numExecs, NULL);
  729. if (con->otherHelp) {
  730. cursor += strlen(con->otherHelp) + 1;
  731. if (cursor > 79) fprintf(fp, "\n ");
  732. fprintf(fp, " %s", con->otherHelp);
  733. }
  734. fprintf(fp, "\n");
  735. }
  736. void poptSetOtherOptionHelp(poptContext con, const char * text)
  737. {
  738. con->otherHelp = _free(con->otherHelp);
  739. con->otherHelp = xstrdup(text);
  740. }