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