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