1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
5 * \file popt/popthelp.c
8 /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
9 file accompanying popt source distributions, available from
10 ftp://ftp.rpm.org/pub/rpm/dist. */
19 * @param key option(s)
21 * @param data (unused)
23 static void displayArgs(poptContext con
,
24 /*@unused@*/ enum poptCallbackReason foo
,
25 struct poptOption
* key
,
26 /*@unused@*/ const char * arg
, /*@unused@*/ void * data
)
27 /*@globals fileSystem@*/
28 /*@modifies fileSystem@*/
30 if (key
->shortName
== '?')
31 poptPrintHelp(con
, stdout
, 0);
33 poptPrintUsage(con
, stdout
, 0);
39 static int show_option_defaults
= 0;
43 * Empty table marker to enable displaying popt alias/exec options.
45 /*@observer@*/ /*@unchecked@*/
46 struct poptOption poptAliasOptions
[] = {
51 * Auto help table options.
54 /*@observer@*/ /*@unchecked@*/
55 struct poptOption poptHelpOptions
[] = {
56 { NULL
, '\0', POPT_ARG_CALLBACK
, (void *)&displayArgs
, '\0', NULL
, NULL
},
57 { "help", '?', 0, NULL
, '?', N_("Show this help message"), NULL
},
58 { "usage", '\0', 0, NULL
, 'u', N_("Display brief usage message"), NULL
},
60 { "defaults", '\0', POPT_ARG_NONE
, &show_option_defaults
, 0,
61 N_("Display option defaults in message"), NULL
},
68 * @param table option(s)
70 /*@observer@*/ /*@null@*/ static const char *
71 getTableTranslationDomain(/*@null@*/ const struct poptOption
*table
)
74 const struct poptOption
*opt
;
77 for (opt
= table
; opt
->longName
|| opt
->shortName
|| opt
->arg
; opt
++) {
78 if (opt
->argInfo
== POPT_ARG_INTL_DOMAIN
)
79 return (char *)opt
->arg
;
85 * @param opt option(s)
86 * @param translation_domain translation domain
88 /*@observer@*/ /*@null@*/ static const char *
89 getArgDescrip(const struct poptOption
* opt
,
90 /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */
91 /*@null@*/ const char * translation_domain
)
95 if (!(opt
->argInfo
& POPT_ARG_MASK
)) return NULL
;
97 if (opt
== (poptHelpOptions
+ 1) || opt
== (poptHelpOptions
+ 2))
98 if (opt
->argDescrip
) return POPT_(opt
->argDescrip
);
100 if (opt
->argDescrip
) return D_(translation_domain
, opt
->argDescrip
);
102 switch (opt
->argInfo
& POPT_ARG_MASK
) {
103 case POPT_ARG_NONE
: return POPT_("NONE");
105 case POPT_ARG_VAL
: return POPT_("VAL");
107 case POPT_ARG_VAL
: return NULL
;
109 case POPT_ARG_INT
: return POPT_("INT");
110 case POPT_ARG_LONG
: return POPT_("LONG");
111 case POPT_ARG_STRING
: return POPT_("STRING");
112 case POPT_ARG_FLOAT
: return POPT_("FLOAT");
113 case POPT_ARG_DOUBLE
: return POPT_("DOUBLE");
114 default: return POPT_("ARG");
119 * Display default value for an option.
121 * @param opt option(s)
122 * @param translation_domain translation domain
125 static /*@only@*/ /*@null@*/ char *
126 singleOptionDefaultValue(int lineLength
,
127 const struct poptOption
* opt
,
128 /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */
129 /*@null@*/ const char * translation_domain
)
133 const char * defstr
= D_(translation_domain
, "default");
134 char * le
= (char *)malloc(4*lineLength
+ 1);
137 if (le
== NULL
) return NULL
; /* XXX can't happen */
141 strcpy(le
, defstr
); le
+= strlen(le
);
144 if (opt
->arg
) /* XXX programmer error */
145 switch (opt
->argInfo
& POPT_ARG_MASK
) {
148 { long aLong
= *((int *)opt
->arg
);
149 le
+= sprintf(le
, "%ld", aLong
);
152 { long aLong
= *((long *)opt
->arg
);
153 le
+= sprintf(le
, "%ld", aLong
);
156 { double aDouble
= *((float *)opt
->arg
);
157 le
+= sprintf(le
, "%g", aDouble
);
159 case POPT_ARG_DOUBLE
:
160 { double aDouble
= *((double *)opt
->arg
);
161 le
+= sprintf(le
, "%g", aDouble
);
163 case POPT_ARG_STRING
:
164 { const char * s
= *(const char **)opt
->arg
;
166 strcpy(le
, "null"); le
+= strlen(le
);
168 size_t slen
= 4*lineLength
- (le
- l
) - sizeof("\"...\")");
170 strncpy(le
, s
, slen
); le
[slen
] = '\0'; le
+= strlen(le
);
171 if (slen
< strlen(s
)) {
172 strcpy(le
, "..."); le
+= strlen(le
);
179 l
= (char *)_free(l
);
181 /*@notreached@*/ break;
191 * Display help text for an option.
192 * @param fp output file handle
194 * @param opt option(s)
195 * @param translation_domain translation domain
197 static void singleOptionHelp(FILE * fp
, int maxLeftCol
,
198 const struct poptOption
* opt
,
199 /*@null@*/ const char * translation_domain
)
200 /*@globals fileSystem @*/
201 /*@modifies *fp, fileSystem @*/
203 int indentLength
= maxLeftCol
+ 5;
204 int lineLength
= 79 - indentLength
;
205 const char * help
= D_(translation_domain
, opt
->descrip
);
206 const char * argDescrip
= getArgDescrip(opt
, translation_domain
);
210 int nb
= maxLeftCol
+ 1;
212 /* Make sure there's more than enough room in target buffer. */
213 if (opt
->longName
) nb
+= strlen(opt
->longName
);
214 if (argDescrip
) nb
+= strlen(argDescrip
);
217 left
= (char *)malloc(nb
);
218 if (left
== NULL
) return; /* XXX can't happen */
220 left
[maxLeftCol
] = '\0';
222 if (opt
->longName
&& opt
->shortName
)
223 sprintf(left
, "-%c, %s%s", opt
->shortName
,
224 ((opt
->argInfo
& POPT_ARGFLAG_ONEDASH
) ? "-" : "--"),
226 else if (opt
->shortName
!= '\0')
227 sprintf(left
, "-%c", opt
->shortName
);
228 else if (opt
->longName
)
229 sprintf(left
, "%s%s",
230 ((opt
->argInfo
& POPT_ARGFLAG_ONEDASH
) ? "-" : "--"),
232 if (!*left
) goto out
;
235 char * le
= left
+ strlen(left
);
237 if (opt
->argInfo
& POPT_ARGFLAG_OPTIONAL
)
240 /* Choose type of output */
242 if (opt
->argInfo
& POPT_ARGFLAG_SHOW_DEFAULT
) {
243 defs
= singleOptionDefaultValue(lineLength
, opt
, translation_domain
);
245 char * t
= (char *)malloc((help
? strlen(help
) : 0) +
246 strlen(defs
) + sizeof(" "));
257 defs
= (char *)_free(defs
);
263 if (opt
->argDescrip
== NULL
) {
264 switch (opt
->argInfo
& POPT_ARG_MASK
) {
268 #ifdef NOTNOW /* XXX pug ugly nerdy output */
269 { long aLong
= opt
->val
;
270 int ops
= (opt
->argInfo
& POPT_ARGFLAG_LOGICALOPS
);
271 int negate
= (opt
->argInfo
& POPT_ARGFLAG_NOT
);
273 /* Don't bother displaying typical values */
274 if (!ops
&& (aLong
== 0L || aLong
== 1L || aLong
== -1L))
278 case POPT_ARGFLAG_OR
:
280 /*@innerbreak@*/ break;
281 case POPT_ARGFLAG_AND
:
283 /*@innerbreak@*/ break;
284 case POPT_ARGFLAG_XOR
:
286 /*@innerbreak@*/ break;
288 /*@innerbreak@*/ break;
291 if (negate
) *le
++ = '~';
293 le
+= sprintf(le
, (ops
? "0x%lx" : "%ld"), aLong
);
302 case POPT_ARG_DOUBLE
:
303 case POPT_ARG_STRING
:
305 strcpy(le
, argDescrip
); le
+= strlen(le
);
312 strcpy(le
, argDescrip
); le
+= strlen(le
);
314 if (opt
->argInfo
& POPT_ARGFLAG_OPTIONAL
)
321 fprintf(fp
," %-*s ", maxLeftCol
, left
);
323 fprintf(fp
," %s\n", left
);
327 left
= (char *)_free(left
);
332 helpLength
= strlen(help
);
334 while (helpLength
> lineLength
) {
338 ch
= help
+ lineLength
- 1;
339 while (ch
> help
&& !isspace(*ch
)) ch
--;
340 if (ch
== help
) break; /* give up */
341 while (ch
> (help
+ 1) && isspace(*ch
)) ch
--;
344 sprintf(format
, "%%.%ds\n%%%ds", (int) (ch
- help
), indentLength
);
346 fprintf(fp
, format
, help
, " ");
349 while (isspace(*help
) && *help
) help
++;
350 helpLength
= strlen(help
);
354 if (helpLength
) fprintf(fp
, "%s\n", help
);
357 /*@-dependenttrans@*/
358 defs
= (char *)_free(defs
);
359 /*@=dependenttrans@*/
360 left
= (char *)_free(left
);
364 * @param opt option(s)
365 * @param translation_domain translation domain
367 static int maxArgWidth(const struct poptOption
* opt
,
368 /*@null@*/ const char * translation_domain
)
376 while (opt
->longName
|| opt
->shortName
|| opt
->arg
) {
377 if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_INCLUDE_TABLE
) {
378 if (opt
->arg
) /* XXX program error */
379 len
= maxArgWidth((const struct poptOption
*)opt
->arg
, translation_domain
);
380 if (len
> max
) max
= len
;
381 } else if (!(opt
->argInfo
& POPT_ARGFLAG_DOC_HIDDEN
)) {
383 if (opt
->shortName
!= '\0') len
+= sizeof("-X")-1;
384 if (opt
->shortName
!= '\0' && opt
->longName
) len
+= sizeof(", ")-1;
386 len
+= ((opt
->argInfo
& POPT_ARGFLAG_ONEDASH
)
387 ? sizeof("-")-1 : sizeof("--")-1);
388 len
+= strlen(opt
->longName
);
391 s
= getArgDescrip(opt
, translation_domain
);
393 len
+= sizeof("=")-1 + strlen(s
);
394 if (opt
->argInfo
& POPT_ARGFLAG_OPTIONAL
) len
+= sizeof("[]")-1;
395 if (len
> max
) max
= len
;
405 * Display popt alias and exec help.
406 * @param fp output file handle
407 * @param items alias/exec array
408 * @param nitems no. of alias/exec entries
410 * @param translation_domain translation domain
412 static void itemHelp(FILE * fp
,
413 /*@null@*/ poptItem items
, int nitems
, int left
,
414 /*@null@*/ const char * translation_domain
)
415 /*@globals fileSystem @*/
416 /*@modifies *fp, fileSystem @*/
422 for (i
= 0, item
= items
; i
< nitems
; i
++, item
++) {
423 const struct poptOption
* opt
;
425 if ((opt
->longName
|| opt
->shortName
) &&
426 !(opt
->argInfo
& POPT_ARGFLAG_DOC_HIDDEN
))
427 singleOptionHelp(fp
, left
, opt
, translation_domain
);
432 * Display help text for a table of options.
434 * @param fp output file handle
435 * @param table option(s)
437 * @param translation_domain translation domain
439 static void singleTableHelp(poptContext con
, FILE * fp
,
440 /*@null@*/ const struct poptOption
* table
, int left
,
441 /*@null@*/ const char * translation_domain
)
442 /*@globals fileSystem @*/
443 /*@modifies *fp, fileSystem @*/
445 const struct poptOption
* opt
;
446 const char *sub_transdom
;
448 if (table
== poptAliasOptions
) {
449 itemHelp(fp
, con
->aliases
, con
->numAliases
, left
, NULL
);
450 itemHelp(fp
, con
->execs
, con
->numExecs
, left
, NULL
);
455 for (opt
= table
; (opt
->longName
|| opt
->shortName
|| opt
->arg
); opt
++) {
456 if ((opt
->longName
|| opt
->shortName
) &&
457 !(opt
->argInfo
& POPT_ARGFLAG_DOC_HIDDEN
))
458 singleOptionHelp(fp
, left
, opt
, translation_domain
);
462 for (opt
= table
; (opt
->longName
|| opt
->shortName
|| opt
->arg
); opt
++) {
463 if ((opt
->argInfo
& POPT_ARG_MASK
) != POPT_ARG_INCLUDE_TABLE
)
465 sub_transdom
= getTableTranslationDomain(
466 (const struct poptOption
*)opt
->arg
);
467 if (sub_transdom
== NULL
)
468 sub_transdom
= translation_domain
;
471 fprintf(fp
, "\n%s\n", D_(sub_transdom
, opt
->descrip
));
473 singleTableHelp(con
, fp
, (const struct poptOption
*)opt
->arg
, left
, sub_transdom
);
479 * @param fp output file handle
481 static int showHelpIntro(poptContext con
, FILE * fp
)
482 /*@globals fileSystem @*/
483 /*@modifies *fp, fileSystem @*/
488 fprintf(fp
, POPT_("Usage:"));
489 if (!(con
->flags
& POPT_CONTEXT_KEEP_FIRST
)) {
491 /*@-nullderef@*/ /* LCL: wazzup? */
492 fn
= con
->optionStack
->argv
[0];
495 if (fn
== NULL
) return len
;
496 if (strchr(fn
, '/')) fn
= strrchr(fn
, '/') + 1;
497 fprintf(fp
, " %s", fn
);
498 len
+= strlen(fn
) + 1;
504 void poptPrintHelp(poptContext con
, FILE * fp
, /*@unused@*/ int flags
)
508 (void) showHelpIntro(con
, fp
);
510 fprintf(fp
, " %s\n", con
->otherHelp
);
512 fprintf(fp
, " %s\n", POPT_("[OPTION...]"));
514 leftColWidth
= maxArgWidth(con
->options
, NULL
);
515 singleTableHelp(con
, fp
, con
->options
, leftColWidth
, NULL
);
519 * @param fp output file handle
521 * @param opt option(s)
522 * @param translation_domain translation domain
524 static int singleOptionUsage(FILE * fp
, int cursor
,
525 const struct poptOption
* opt
,
526 /*@null@*/ const char *translation_domain
)
527 /*@globals fileSystem @*/
528 /*@modifies *fp, fileSystem @*/
531 char shortStr
[2] = { '\0', '\0' };
532 const char * item
= shortStr
;
533 const char * argDescrip
= getArgDescrip(opt
, translation_domain
);
535 if (opt
->shortName
!= '\0' && opt
->longName
!= NULL
) {
537 if (!(opt
->argInfo
& POPT_ARGFLAG_ONEDASH
)) len
++;
538 len
+= strlen(opt
->longName
);
539 } else if (opt
->shortName
!= '\0') {
541 shortStr
[0] = opt
->shortName
;
543 } else if (opt
->longName
) {
544 len
+= strlen(opt
->longName
);
545 if (!(opt
->argInfo
& POPT_ARGFLAG_ONEDASH
)) len
++;
546 item
= opt
->longName
;
549 if (len
== 4) return cursor
;
552 len
+= strlen(argDescrip
) + 1;
554 if ((cursor
+ len
) > 79) {
559 if (opt
->longName
&& opt
->shortName
) {
560 fprintf(fp
, " [-%c|-%s%s%s%s]",
561 opt
->shortName
, ((opt
->argInfo
& POPT_ARGFLAG_ONEDASH
) ? "" : "-"),
563 (argDescrip
? " " : ""),
564 (argDescrip
? argDescrip
: ""));
566 fprintf(fp
, " [-%s%s%s%s]",
567 ((opt
->shortName
|| (opt
->argInfo
& POPT_ARGFLAG_ONEDASH
)) ? "" : "-"),
569 (argDescrip
? (opt
->shortName
!= '\0' ? " " : "=") : ""),
570 (argDescrip
? argDescrip
: ""));
573 return cursor
+ len
+ 1;
577 * Display popt alias and exec usage.
578 * @param fp output file handle
580 * @param item alias/exec array
581 * @param nitems no. of ara/exec entries
582 * @param translation_domain translation domain
584 static int itemUsage(FILE * fp
, int cursor
, poptItem item
, int nitems
,
585 /*@null@*/ const char * translation_domain
)
586 /*@globals fileSystem @*/
587 /*@modifies *fp, fileSystem @*/
591 /*@-branchstate@*/ /* FIX: W2DO? */
593 for (i
= 0; i
< nitems
; i
++, item
++) {
594 const struct poptOption
* opt
;
596 if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_INTL_DOMAIN
) {
597 translation_domain
= (const char *)opt
->arg
;
598 } else if ((opt
->longName
|| opt
->shortName
) &&
599 !(opt
->argInfo
& POPT_ARGFLAG_DOC_HIDDEN
)) {
600 cursor
= singleOptionUsage(fp
, cursor
, opt
, translation_domain
);
609 * Keep track of option tables already processed.
611 typedef struct poptDone_s
{
618 * Display usage text for a table of options.
620 * @param fp output file handle
622 * @param opt option(s)
623 * @param translation_domain translation domain
624 * @param done tables already processed
627 static int singleTableUsage(poptContext con
, FILE * fp
, int cursor
,
628 /*@null@*/ const struct poptOption
* opt
,
629 /*@null@*/ const char * translation_domain
,
630 /*@null@*/ poptDone done
)
631 /*@globals fileSystem @*/
632 /*@modifies *fp, done, fileSystem @*/
634 /*@-branchstate@*/ /* FIX: W2DO? */
636 for (; (opt
->longName
|| opt
->shortName
|| opt
->arg
) ; opt
++) {
637 if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_INTL_DOMAIN
) {
638 translation_domain
= (const char *)opt
->arg
;
639 } else if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_INCLUDE_TABLE
) {
642 for (i
= 0; i
< done
->nopts
; i
++) {
644 const void * that
= done
->opts
[i
];
646 if (that
== NULL
|| that
!= opt
->arg
)
647 /*@innercontinue@*/ continue;
648 /*@innerbreak@*/ break;
650 /* Skip if this table has already been processed. */
651 if (opt
->arg
== NULL
|| i
< done
->nopts
)
654 if (done
->nopts
< done
->maxopts
)
655 done
->opts
[done
->nopts
++] = (const void *) opt
->arg
;
658 cursor
= singleTableUsage(con
, fp
, cursor
, (const struct poptOption
*)opt
->arg
,
659 translation_domain
, done
);
660 } else if ((opt
->longName
|| opt
->shortName
) &&
661 !(opt
->argInfo
& POPT_ARGFLAG_DOC_HIDDEN
)) {
662 cursor
= singleOptionUsage(fp
, cursor
, opt
, translation_domain
);
671 * Return concatenated short options for display.
672 * @todo Sub-tables should be recursed.
673 * @param opt option(s)
674 * @param fp output file handle
675 * @retval str concatenation of short options
676 * @return length of display string
678 static int showShortOptions(const struct poptOption
* opt
, FILE * fp
,
679 /*@null@*/ char * str
)
680 /*@globals fileSystem @*/
681 /*@modifies *str, *fp, fileSystem @*/
682 /*@requires maxRead(str) >= 0 @*/
684 /* bufsize larger then the ascii set, lazy alloca on top level call. */
685 char * s
= (str
!= NULL
? str
: (char *)memset(alloca(300), 0, 300));
690 for (; (opt
->longName
|| opt
->shortName
|| opt
->arg
); opt
++) {
691 if (opt
->shortName
&& !(opt
->argInfo
& POPT_ARG_MASK
))
692 s
[strlen(s
)] = opt
->shortName
;
693 else if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_INCLUDE_TABLE
)
694 if (opt
->arg
) /* XXX program error */
695 len
= showShortOptions(
696 (const struct poptOption
*)opt
->arg
, fp
, s
);
700 /* On return to top level, print the short options, return print length. */
701 if (s
== str
&& *s
!= '\0') {
702 fprintf(fp
, " [-%s]", s
);
703 len
= strlen(s
) + sizeof(" [-]")-1;
708 void poptPrintUsage(poptContext con
, FILE * fp
, /*@unused@*/ int flags
)
710 poptDone done
= (poptDone
)memset(alloca(sizeof(*done
)), 0, sizeof(*done
));
715 cursor
= done
->maxopts
* sizeof(*done
->opts
);
717 done
->opts
= (const void **)memset(alloca(cursor
), 0, cursor
);
718 done
->opts
[done
->nopts
++] = (const void *) con
->options
;
721 cursor
= showHelpIntro(con
, fp
);
722 cursor
+= showShortOptions(con
->options
, fp
, NULL
);
723 cursor
= singleTableUsage(con
, fp
, cursor
, con
->options
, NULL
, done
);
724 cursor
= itemUsage(fp
, cursor
, con
->aliases
, con
->numAliases
, NULL
);
725 cursor
= itemUsage(fp
, cursor
, con
->execs
, con
->numExecs
, NULL
);
727 if (con
->otherHelp
) {
728 cursor
+= strlen(con
->otherHelp
) + 1;
729 if (cursor
> 79) fprintf(fp
, "\n ");
730 fprintf(fp
, " %s", con
->otherHelp
);
736 void poptSetOtherOptionHelp(poptContext con
, const char * text
)
738 con
->otherHelp
= (const char *)_free(con
->otherHelp
);
739 con
->otherHelp
= xstrdup(text
);