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); | |
f58677d1 DD |
137 | sprintf(le, "%ld", aLong); |
138 | le += strlen(le); | |
cc248aae WD |
139 | } break; |
140 | case POPT_ARG_LONG: | |
141 | { long aLong = *((long *)opt->arg); | |
f58677d1 DD |
142 | sprintf(le, "%ld", aLong); |
143 | le += strlen(le); | |
cc248aae WD |
144 | } break; |
145 | case POPT_ARG_FLOAT: | |
146 | { double aDouble = *((float *)opt->arg); | |
f58677d1 DD |
147 | sprintf(le, "%g", aDouble); |
148 | le += strlen(le); | |
cc248aae WD |
149 | } break; |
150 | case POPT_ARG_DOUBLE: | |
151 | { double aDouble = *((double *)opt->arg); | |
f58677d1 DD |
152 | sprintf(le, "%g", aDouble); |
153 | le += strlen(le); | |
cc248aae WD |
154 | } break; |
155 | case POPT_ARG_STRING: | |
156 | { const char * s = *(const char **)opt->arg; | |
157 | if (s == NULL) { | |
158 | strcpy(le, "null"); le += strlen(le); | |
159 | } else { | |
160 | size_t slen = 4*lineLength - (le - l) - sizeof("\"...\")"); | |
161 | *le++ = '"'; | |
162 | strncpy(le, s, slen); le[slen] = '\0'; le += strlen(le); | |
163 | if (slen < strlen(s)) { | |
164 | strcpy(le, "..."); le += strlen(le); | |
165 | } | |
166 | *le++ = '"'; | |
167 | } | |
168 | } break; | |
169 | case POPT_ARG_NONE: | |
170 | default: | |
171 | l = _free(l); | |
172 | return NULL; | |
173 | /*@notreached@*/ break; | |
174 | } | |
175 | *le++ = ')'; | |
176 | *le = '\0'; | |
177 | ||
178 | return l; | |
62402cb1 MP |
179 | } |
180 | ||
cc248aae WD |
181 | /** |
182 | * @param fp output file handle | |
183 | * @param opt option(s) | |
184 | * @param translation_domain translation domain | |
185 | */ | |
186 | static void singleOptionHelp(FILE * fp, int maxLeftCol, | |
187 | const struct poptOption * opt, | |
188 | /*@null@*/ const char * translation_domain) | |
189 | /*@globals fileSystem @*/ | |
190 | /*@modifies *fp, fileSystem @*/ | |
191 | { | |
62402cb1 MP |
192 | int indentLength = maxLeftCol + 5; |
193 | int lineLength = 79 - indentLength; | |
b348deae | 194 | const char * help = D_(translation_domain, opt->descrip); |
cc248aae | 195 | const char * argDescrip = getArgDescrip(opt, translation_domain); |
62402cb1 | 196 | int helpLength; |
cc248aae | 197 | char * defs = NULL; |
b348deae | 198 | char * left; |
cc248aae WD |
199 | int nb = maxLeftCol + 1; |
200 | ||
201 | /* Make sure there's more than enough room in target buffer. */ | |
202 | if (opt->longName) nb += strlen(opt->longName); | |
203 | if (argDescrip) nb += strlen(argDescrip); | |
62402cb1 | 204 | |
cc248aae WD |
205 | left = malloc(nb); |
206 | if (left == NULL) return; /* XXX can't happen */ | |
207 | left[0] = '\0'; | |
208 | left[maxLeftCol] = '\0'; | |
b348deae | 209 | |
62402cb1 | 210 | if (opt->longName && opt->shortName) |
cc248aae WD |
211 | sprintf(left, "-%c, %s%s", opt->shortName, |
212 | ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"), | |
213 | opt->longName); | |
214 | else if (opt->shortName != '\0') | |
62402cb1 MP |
215 | sprintf(left, "-%c", opt->shortName); |
216 | else if (opt->longName) | |
cc248aae WD |
217 | sprintf(left, "%s%s", |
218 | ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"), | |
219 | opt->longName); | |
220 | if (!*left) goto out; | |
62402cb1 | 221 | if (argDescrip) { |
cc248aae WD |
222 | char * le = left + strlen(left); |
223 | ||
224 | if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) | |
225 | *le++ = '['; | |
226 | ||
227 | /* Choose type of output */ | |
228 | /*@-branchstate@*/ | |
229 | if (opt->argInfo & POPT_ARGFLAG_SHOW_DEFAULT) { | |
230 | defs = singleOptionDefaultValue(lineLength, opt, translation_domain); | |
231 | if (defs) { | |
232 | char * t = malloc((help ? strlen(help) : 0) + | |
233 | strlen(defs) + sizeof(" ")); | |
234 | if (t) { | |
235 | char * te = t; | |
236 | *te = '\0'; | |
237 | if (help) { | |
238 | strcpy(te, help); te += strlen(te); | |
239 | } | |
240 | *te++ = ' '; | |
241 | strcpy(te, defs); | |
242 | defs = _free(defs); | |
243 | } | |
244 | defs = t; | |
245 | } | |
246 | } | |
247 | /*@=branchstate@*/ | |
248 | ||
249 | if (opt->argDescrip == NULL) { | |
250 | switch (opt->argInfo & POPT_ARG_MASK) { | |
251 | case POPT_ARG_NONE: | |
252 | break; | |
253 | case POPT_ARG_VAL: | |
254 | { long aLong = opt->val; | |
255 | int ops = (opt->argInfo & POPT_ARGFLAG_LOGICALOPS); | |
256 | int negate = (opt->argInfo & POPT_ARGFLAG_NOT); | |
257 | ||
258 | /* Don't bother displaying typical values */ | |
259 | if (!ops && (aLong == 0L || aLong == 1L || aLong == -1L)) | |
260 | break; | |
261 | *le++ = '['; | |
262 | switch (ops) { | |
263 | case POPT_ARGFLAG_OR: | |
264 | *le++ = '|'; | |
265 | /*@innerbreak@*/ break; | |
266 | case POPT_ARGFLAG_AND: | |
267 | *le++ = '&'; | |
268 | /*@innerbreak@*/ break; | |
269 | case POPT_ARGFLAG_XOR: | |
270 | *le++ = '^'; | |
271 | /*@innerbreak@*/ break; | |
272 | default: | |
273 | /*@innerbreak@*/ break; | |
274 | } | |
275 | *le++ = '='; | |
276 | if (negate) *le++ = '~'; | |
277 | /*@-formatconst@*/ | |
f58677d1 DD |
278 | sprintf(le, (ops ? "0x%lx" : "%ld"), aLong); |
279 | le += strlen(le); | |
cc248aae WD |
280 | /*@=formatconst@*/ |
281 | *le++ = ']'; | |
282 | } break; | |
283 | case POPT_ARG_INT: | |
284 | case POPT_ARG_LONG: | |
285 | case POPT_ARG_FLOAT: | |
286 | case POPT_ARG_DOUBLE: | |
287 | case POPT_ARG_STRING: | |
288 | *le++ = '='; | |
289 | strcpy(le, argDescrip); le += strlen(le); | |
290 | break; | |
291 | default: | |
292 | break; | |
293 | } | |
294 | } else { | |
295 | *le++ = '='; | |
296 | strcpy(le, argDescrip); le += strlen(le); | |
297 | } | |
298 | if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) | |
299 | *le++ = ']'; | |
300 | *le = '\0'; | |
62402cb1 MP |
301 | } |
302 | ||
303 | if (help) | |
cc248aae | 304 | fprintf(fp," %-*s ", maxLeftCol, left); |
62402cb1 | 305 | else { |
cc248aae | 306 | fprintf(fp," %s\n", left); |
b348deae | 307 | goto out; |
62402cb1 MP |
308 | } |
309 | ||
cc248aae WD |
310 | left = _free(left); |
311 | if (defs) { | |
312 | help = defs; defs = NULL; | |
313 | } | |
314 | ||
62402cb1 MP |
315 | helpLength = strlen(help); |
316 | while (helpLength > lineLength) { | |
cc248aae WD |
317 | const char * ch; |
318 | char format[10]; | |
319 | ||
62402cb1 MP |
320 | ch = help + lineLength - 1; |
321 | while (ch > help && !isspace(*ch)) ch--; | |
322 | if (ch == help) break; /* give up */ | |
323 | while (ch > (help + 1) && isspace(*ch)) ch--; | |
324 | ch++; | |
325 | ||
326 | sprintf(format, "%%.%ds\n%%%ds", (int) (ch - help), indentLength); | |
cc248aae WD |
327 | /*@-formatconst@*/ |
328 | fprintf(fp, format, help, " "); | |
329 | /*@=formatconst@*/ | |
62402cb1 MP |
330 | help = ch; |
331 | while (isspace(*help) && *help) help++; | |
332 | helpLength = strlen(help); | |
333 | } | |
334 | ||
cc248aae | 335 | if (helpLength) fprintf(fp, "%s\n", help); |
b348deae MP |
336 | |
337 | out: | |
cc248aae WD |
338 | /*@-dependenttrans@*/ |
339 | defs = _free(defs); | |
340 | /*@=dependenttrans@*/ | |
341 | left = _free(left); | |
62402cb1 MP |
342 | } |
343 | ||
cc248aae WD |
344 | /** |
345 | * @param opt option(s) | |
346 | * @param translation_domain translation domain | |
347 | */ | |
b348deae | 348 | static int maxArgWidth(const struct poptOption * opt, |
cc248aae WD |
349 | /*@null@*/ const char * translation_domain) |
350 | /*@*/ | |
351 | { | |
62402cb1 | 352 | int max = 0; |
cc248aae | 353 | int len = 0; |
62402cb1 MP |
354 | const char * s; |
355 | ||
cc248aae | 356 | if (opt != NULL) |
62402cb1 MP |
357 | while (opt->longName || opt->shortName || opt->arg) { |
358 | if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { | |
cc248aae WD |
359 | if (opt->arg) /* XXX program error */ |
360 | len = maxArgWidth(opt->arg, translation_domain); | |
361 | if (len > max) max = len; | |
62402cb1 | 362 | } else if (!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) { |
cc248aae WD |
363 | len = sizeof(" ")-1; |
364 | if (opt->shortName != '\0') len += sizeof("-X")-1; | |
365 | if (opt->shortName != '\0' && opt->longName) len += sizeof(", ")-1; | |
62402cb1 | 366 | if (opt->longName) { |
cc248aae WD |
367 | len += ((opt->argInfo & POPT_ARGFLAG_ONEDASH) |
368 | ? sizeof("-")-1 : sizeof("--")-1); | |
369 | len += strlen(opt->longName); | |
62402cb1 MP |
370 | } |
371 | ||
b348deae | 372 | s = getArgDescrip(opt, translation_domain); |
62402cb1 | 373 | if (s) |
cc248aae WD |
374 | len += sizeof("=")-1 + strlen(s); |
375 | if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) len += sizeof("[]")-1; | |
376 | if (len > max) max = len; | |
62402cb1 MP |
377 | } |
378 | ||
379 | opt++; | |
380 | } | |
381 | ||
382 | return max; | |
383 | } | |
384 | ||
cc248aae WD |
385 | /** |
386 | * Display popt alias and exec help. | |
387 | * @param fp output file handle | |
388 | * @param items alias/exec array | |
389 | * @param nitems no. of alias/exec entries | |
390 | * @param translation_domain translation domain | |
391 | */ | |
392 | static void itemHelp(FILE * fp, | |
393 | /*@null@*/ poptItem items, int nitems, int left, | |
394 | /*@null@*/ const char * translation_domain) | |
395 | /*@globals fileSystem @*/ | |
396 | /*@modifies *fp, fileSystem @*/ | |
397 | { | |
398 | poptItem item; | |
399 | int i; | |
400 | ||
401 | if (items != NULL) | |
402 | for (i = 0, item = items; i < nitems; i++, item++) { | |
403 | const struct poptOption * opt; | |
404 | opt = &item->option; | |
405 | if ((opt->longName || opt->shortName) && | |
406 | !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) | |
407 | singleOptionHelp(fp, left, opt, translation_domain); | |
408 | } | |
409 | } | |
410 | ||
411 | /** | |
412 | * @param fp output file handle | |
413 | * @param table option(s) | |
414 | * @param translation_domain translation domain | |
415 | */ | |
416 | static void singleTableHelp(poptContext con, FILE * fp, | |
417 | /*@null@*/ const struct poptOption * table, int left, | |
418 | /*@null@*/ const char * translation_domain) | |
419 | /*@globals fileSystem @*/ | |
420 | /*@modifies *fp, fileSystem @*/ | |
421 | { | |
62402cb1 | 422 | const struct poptOption * opt; |
b348deae | 423 | const char *sub_transdom; |
62402cb1 | 424 | |
cc248aae WD |
425 | if (table == poptAliasOptions) { |
426 | itemHelp(fp, con->aliases, con->numAliases, left, NULL); | |
427 | itemHelp(fp, con->execs, con->numExecs, left, NULL); | |
428 | return; | |
429 | } | |
430 | ||
431 | if (table != NULL) | |
432 | for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) { | |
62402cb1 MP |
433 | if ((opt->longName || opt->shortName) && |
434 | !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) | |
cc248aae | 435 | singleOptionHelp(fp, left, opt, translation_domain); |
62402cb1 MP |
436 | } |
437 | ||
cc248aae WD |
438 | if (table != NULL) |
439 | for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) { | |
440 | if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_INCLUDE_TABLE) | |
441 | continue; | |
442 | sub_transdom = getTableTranslationDomain(opt->arg); | |
443 | if (sub_transdom == NULL) | |
444 | sub_transdom = translation_domain; | |
b348deae | 445 | |
cc248aae WD |
446 | if (opt->descrip) |
447 | fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip)); | |
b348deae | 448 | |
cc248aae | 449 | singleTableHelp(con, fp, opt->arg, left, sub_transdom); |
62402cb1 MP |
450 | } |
451 | } | |
452 | ||
cc248aae WD |
453 | /** |
454 | * @param con context | |
455 | * @param fp output file handle | |
456 | */ | |
457 | static int showHelpIntro(poptContext con, FILE * fp) | |
458 | /*@globals fileSystem @*/ | |
459 | /*@modifies *fp, fileSystem @*/ | |
460 | { | |
62402cb1 | 461 | int len = 6; |
b348deae | 462 | const char * fn; |
62402cb1 | 463 | |
cc248aae | 464 | fprintf(fp, POPT_("Usage:")); |
62402cb1 | 465 | if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) { |
cc248aae | 466 | /*@-nullderef@*/ /* LCL: wazzup? */ |
62402cb1 | 467 | fn = con->optionStack->argv[0]; |
cc248aae WD |
468 | /*@=nullderef@*/ |
469 | if (fn == NULL) return len; | |
470 | if (strchr(fn, '/')) fn = strrchr(fn, '/') + 1; | |
471 | fprintf(fp, " %s", fn); | |
62402cb1 MP |
472 | len += strlen(fn) + 1; |
473 | } | |
474 | ||
475 | return len; | |
476 | } | |
477 | ||
cc248aae WD |
478 | void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ int flags) |
479 | { | |
62402cb1 MP |
480 | int leftColWidth; |
481 | ||
cc248aae | 482 | (void) showHelpIntro(con, fp); |
62402cb1 | 483 | if (con->otherHelp) |
cc248aae | 484 | fprintf(fp, " %s\n", con->otherHelp); |
62402cb1 | 485 | else |
cc248aae | 486 | fprintf(fp, " %s\n", POPT_("[OPTION...]")); |
62402cb1 | 487 | |
b348deae | 488 | leftColWidth = maxArgWidth(con->options, NULL); |
cc248aae | 489 | singleTableHelp(con, fp, con->options, leftColWidth, NULL); |
62402cb1 MP |
490 | } |
491 | ||
cc248aae WD |
492 | /** |
493 | * @param fp output file handle | |
494 | * @param opt option(s) | |
495 | * @param translation_domain translation domain | |
496 | */ | |
497 | static int singleOptionUsage(FILE * fp, int cursor, | |
498 | const struct poptOption * opt, | |
499 | /*@null@*/ const char *translation_domain) | |
500 | /*@globals fileSystem @*/ | |
501 | /*@modifies *fp, fileSystem @*/ | |
502 | { | |
62402cb1 | 503 | int len = 3; |
b348deae | 504 | char shortStr[2] = { '\0', '\0' }; |
62402cb1 | 505 | const char * item = shortStr; |
b348deae | 506 | const char * argDescrip = getArgDescrip(opt, translation_domain); |
62402cb1 | 507 | |
cc248aae | 508 | if (opt->shortName!= '\0' ) { |
62402cb1 MP |
509 | if (!(opt->argInfo & POPT_ARG_MASK)) |
510 | return cursor; /* we did these already */ | |
511 | len++; | |
cc248aae | 512 | shortStr[0] = opt->shortName; |
62402cb1 MP |
513 | shortStr[1] = '\0'; |
514 | } else if (opt->longName) { | |
515 | len += 1 + strlen(opt->longName); | |
516 | item = opt->longName; | |
517 | } | |
518 | ||
519 | if (len == 3) return cursor; | |
520 | ||
521 | if (argDescrip) | |
522 | len += strlen(argDescrip) + 1; | |
523 | ||
524 | if ((cursor + len) > 79) { | |
cc248aae | 525 | fprintf(fp, "\n "); |
62402cb1 MP |
526 | cursor = 7; |
527 | } | |
528 | ||
cc248aae WD |
529 | fprintf(fp, " [-%s%s%s%s]", |
530 | ((opt->shortName || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) ? "" : "-"), | |
531 | item, | |
532 | (argDescrip ? (opt->shortName != '\0' ? " " : "=") : ""), | |
533 | (argDescrip ? argDescrip : "")); | |
62402cb1 MP |
534 | |
535 | return cursor + len + 1; | |
536 | } | |
537 | ||
cc248aae WD |
538 | /** |
539 | * Display popt alias and exec usage. | |
540 | * @param fp output file handle | |
541 | * @param item alias/exec array | |
542 | * @param nitems no. of ara/exec entries | |
543 | * @param translation_domain translation domain | |
544 | */ | |
545 | static int itemUsage(FILE * fp, int cursor, poptItem item, int nitems, | |
546 | /*@null@*/ const char * translation_domain) | |
547 | /*@globals fileSystem @*/ | |
548 | /*@modifies *fp, fileSystem @*/ | |
549 | { | |
550 | int i; | |
551 | ||
552 | /*@-branchstate@*/ /* FIX: W2DO? */ | |
553 | if (item != NULL) | |
554 | for (i = 0; i < nitems; i++, item++) { | |
555 | const struct poptOption * opt; | |
556 | opt = &item->option; | |
557 | if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) { | |
b348deae | 558 | translation_domain = (const char *)opt->arg; |
cc248aae WD |
559 | } else if ((opt->longName || opt->shortName) && |
560 | !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) { | |
561 | cursor = singleOptionUsage(fp, cursor, opt, translation_domain); | |
562 | } | |
563 | } | |
564 | /*@=branchstate@*/ | |
b348deae | 565 | |
cc248aae WD |
566 | return cursor; |
567 | } | |
568 | ||
569 | /** | |
570 | * @param fp output file handle | |
571 | * @param opt option(s) | |
572 | * @param translation_domain translation domain | |
573 | */ | |
574 | static int singleTableUsage(poptContext con, FILE * fp, | |
575 | int cursor, const struct poptOption * opt, | |
576 | /*@null@*/ const char * translation_domain) | |
577 | /*@globals fileSystem @*/ | |
578 | /*@modifies *fp, fileSystem @*/ | |
579 | { | |
580 | /*@-branchstate@*/ /* FIX: W2DO? */ | |
581 | if (opt != NULL) | |
582 | for (; (opt->longName || opt->shortName || opt->arg) ; opt++) { | |
583 | if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) { | |
584 | translation_domain = (const char *)opt->arg; | |
585 | } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { | |
586 | if (opt->arg) /* XXX program error */ | |
587 | cursor = singleTableUsage(con, fp, cursor, opt->arg, | |
588 | translation_domain); | |
589 | } else if ((opt->longName || opt->shortName) && | |
590 | !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) { | |
591 | cursor = singleOptionUsage(fp, cursor, opt, translation_domain); | |
592 | } | |
62402cb1 | 593 | } |
cc248aae | 594 | /*@=branchstate@*/ |
62402cb1 MP |
595 | |
596 | return cursor; | |
597 | } | |
598 | ||
cc248aae WD |
599 | /** |
600 | * Return concatenated short options for display. | |
601 | * @param opt option(s) | |
602 | * @param fp output file handle | |
603 | * @retval str concatenation of short options | |
604 | * @return length of display string | |
605 | */ | |
606 | static int showShortOptions(const struct poptOption * opt, FILE * fp, | |
607 | /*@null@*/ char * str) | |
608 | /*@globals fileSystem @*/ | |
609 | /*@modifies *str, *fp, fileSystem @*/ | |
610 | { | |
611 | char * s = alloca(300); /* larger then the ascii set */ | |
62402cb1 | 612 | |
b348deae | 613 | s[0] = '\0'; |
cc248aae | 614 | /*@-branchstate@*/ /* FIX: W2DO? */ |
b348deae MP |
615 | if (str == NULL) { |
616 | memset(s, 0, sizeof(s)); | |
62402cb1 | 617 | str = s; |
62402cb1 | 618 | } |
cc248aae | 619 | /*@=branchstate@*/ |
62402cb1 | 620 | |
cc248aae WD |
621 | if (opt != NULL) |
622 | for (; (opt->longName || opt->shortName || opt->arg); opt++) { | |
62402cb1 MP |
623 | if (opt->shortName && !(opt->argInfo & POPT_ARG_MASK)) |
624 | str[strlen(str)] = opt->shortName; | |
625 | else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) | |
cc248aae WD |
626 | if (opt->arg) /* XXX program error */ |
627 | (void) showShortOptions(opt->arg, fp, str); | |
62402cb1 MP |
628 | } |
629 | ||
cc248aae | 630 | if (s != str || *s != '\0') |
62402cb1 MP |
631 | return 0; |
632 | ||
cc248aae | 633 | fprintf(fp, " [-%s]", s); |
62402cb1 MP |
634 | return strlen(s) + 4; |
635 | } | |
636 | ||
cc248aae WD |
637 | void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ int flags) |
638 | { | |
62402cb1 MP |
639 | int cursor; |
640 | ||
cc248aae WD |
641 | cursor = showHelpIntro(con, fp); |
642 | cursor += showShortOptions(con->options, fp, NULL); | |
643 | (void) singleTableUsage(con, fp, cursor, con->options, NULL); | |
644 | (void) itemUsage(fp, cursor, con->aliases, con->numAliases, NULL); | |
645 | (void) itemUsage(fp, cursor, con->execs, con->numExecs, NULL); | |
62402cb1 MP |
646 | |
647 | if (con->otherHelp) { | |
648 | cursor += strlen(con->otherHelp) + 1; | |
cc248aae WD |
649 | if (cursor > 79) fprintf(fp, "\n "); |
650 | fprintf(fp, " %s", con->otherHelp); | |
62402cb1 MP |
651 | } |
652 | ||
cc248aae | 653 | fprintf(fp, "\n"); |
62402cb1 MP |
654 | } |
655 | ||
cc248aae WD |
656 | void poptSetOtherOptionHelp(poptContext con, const char * text) |
657 | { | |
658 | con->otherHelp = _free(con->otherHelp); | |
b348deae | 659 | con->otherHelp = xstrdup(text); |
62402cb1 | 660 | } |
cc248aae | 661 | /*@=type@*/ |