1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
5 * \file popt/popthelp.c
8 /* (C) 1998-2000 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. */
17 * @param key option(s)
19 static void displayArgs(poptContext con
,
20 /*@unused@*/ UNUSED(enum poptCallbackReason foo
),
21 struct poptOption
* key
,
22 /*@unused@*/ UNUSED(const char * arg
), /*@unused@*/ UNUSED(void * data
))
23 /*@globals fileSystem@*/
24 /*@modifies fileSystem@*/
26 if (key
->shortName
== '?')
27 poptPrintHelp(con
, stdout
, 0);
29 poptPrintUsage(con
, stdout
, 0);
35 static int show_option_defaults
= 0;
39 * Empty table marker to enable displaying popt alias/exec options.
41 /*@observer@*/ /*@unchecked@*/
42 struct poptOption poptAliasOptions
[] = {
47 * Auto help table options.
50 /*@observer@*/ /*@unchecked@*/
51 struct poptOption poptHelpOptions
[] = {
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
},
56 { "defaults", '\0', POPT_ARG_NONE
, &show_option_defaults
, 0,
57 N_("Display option defaults in message"), NULL
},
64 * @param table option(s)
66 /*@observer@*/ /*@null@*/ static const char *
67 getTableTranslationDomain(/*@null@*/ const struct poptOption
*table
)
70 const struct poptOption
*opt
;
73 for (opt
= table
; opt
->longName
|| opt
->shortName
|| opt
->arg
; opt
++) {
74 if (opt
->argInfo
== POPT_ARG_INTL_DOMAIN
)
81 * @param opt option(s)
82 * @param translation_domain translation domain
84 /*@observer@*/ /*@null@*/ static const char *
85 getArgDescrip(const struct poptOption
* opt
,
86 /*@-paramuse@*/ /* FIX: wazzup? */
87 /*@null@*/ UNUSED(const char * translation_domain
))
91 if (!(opt
->argInfo
& POPT_ARG_MASK
)) return NULL
;
93 if (opt
== (poptHelpOptions
+ 1) || opt
== (poptHelpOptions
+ 2))
94 if (opt
->argDescrip
) return POPT_(opt
->argDescrip
);
96 if (opt
->argDescrip
) return D_(translation_domain
, opt
->argDescrip
);
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");
111 * @param opt option(s)
112 * @param translation_domain translation domain
114 static /*@only@*/ /*@null@*/ char *
115 singleOptionDefaultValue(int lineLength
,
116 const struct poptOption
* opt
,
117 /*@-paramuse@*/ /* FIX: i18n macros disable with lclint */
118 /*@null@*/ UNUSED(const char * translation_domain
))
122 const char * defstr
= D_(translation_domain
, "default");
123 char * le
= malloc(4*lineLength
+ 1);
126 if (le
== NULL
) return NULL
; /* XXX can't happen */
129 strcpy(le
, defstr
); le
+= strlen(le
);
132 if (opt
->arg
) /* XXX programmer error */
133 switch (opt
->argInfo
& POPT_ARG_MASK
) {
136 { long aLong
= *((int *)opt
->arg
);
137 sprintf(le
, "%ld", aLong
);
141 { long aLong
= *((long *)opt
->arg
);
142 sprintf(le
, "%ld", aLong
);
146 { double aDouble
= *((float *)opt
->arg
);
147 sprintf(le
, "%g", aDouble
);
150 case POPT_ARG_DOUBLE
:
151 { double aDouble
= *((double *)opt
->arg
);
152 sprintf(le
, "%g", aDouble
);
155 case POPT_ARG_STRING
:
156 { const char * s
= *(const char **)opt
->arg
;
158 strcpy(le
, "null"); le
+= strlen(le
);
160 size_t slen
= 4*lineLength
- (le
- l
) - sizeof("\"...\")");
162 strncpy(le
, s
, slen
); le
[slen
] = '\0'; le
+= strlen(le
);
163 if (slen
< strlen(s
)) {
164 strcpy(le
, "..."); le
+= strlen(le
);
173 /*@notreached@*/ break;
182 * @param fp output file handle
183 * @param opt option(s)
184 * @param translation_domain translation domain
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 @*/
192 int indentLength
= maxLeftCol
+ 5;
193 int lineLength
= 79 - indentLength
;
194 const unsigned char * help
= D_(translation_domain
, opt
->descrip
);
195 const char * argDescrip
= getArgDescrip(opt
, translation_domain
);
197 unsigned char * defs
= NULL
;
198 unsigned char * left
;
199 int nb
= maxLeftCol
+ 1;
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
);
206 if (left
== NULL
) return; /* XXX can't happen */
208 left
[maxLeftCol
] = '\0';
210 if (opt
->longName
&& opt
->shortName
)
211 sprintf(left
, "-%c, %s%s", opt
->shortName
,
212 ((opt
->argInfo
& POPT_ARGFLAG_ONEDASH
) ? "-" : "--"),
214 else if (opt
->shortName
!= '\0')
215 sprintf(left
, "-%c", opt
->shortName
);
216 else if (opt
->longName
)
217 sprintf(left
, "%s%s",
218 ((opt
->argInfo
& POPT_ARGFLAG_ONEDASH
) ? "-" : "--"),
220 if (!*left
) goto out
;
222 char * le
= left
+ strlen(left
);
224 if (opt
->argInfo
& POPT_ARGFLAG_OPTIONAL
)
227 /* Choose type of output */
229 if (opt
->argInfo
& POPT_ARGFLAG_SHOW_DEFAULT
) {
230 defs
= singleOptionDefaultValue(lineLength
, opt
, translation_domain
);
232 char * t
= malloc((help
? strlen(help
) : 0) +
233 strlen(defs
) + sizeof(" "));
238 strcpy(te
, help
); te
+= strlen(te
);
249 if (opt
->argDescrip
== NULL
) {
250 switch (opt
->argInfo
& POPT_ARG_MASK
) {
254 { long aLong
= opt
->val
;
255 int ops
= (opt
->argInfo
& POPT_ARGFLAG_LOGICALOPS
);
256 int negate
= (opt
->argInfo
& POPT_ARGFLAG_NOT
);
258 /* Don't bother displaying typical values */
259 if (!ops
&& (aLong
== 0L || aLong
== 1L || aLong
== -1L))
263 case POPT_ARGFLAG_OR
:
265 /*@innerbreak@*/ break;
266 case POPT_ARGFLAG_AND
:
268 /*@innerbreak@*/ break;
269 case POPT_ARGFLAG_XOR
:
271 /*@innerbreak@*/ break;
273 /*@innerbreak@*/ break;
276 if (negate
) *le
++ = '~';
278 sprintf(le
, (ops
? "0x%lx" : "%ld"), aLong
);
286 case POPT_ARG_DOUBLE
:
287 case POPT_ARG_STRING
:
289 strcpy(le
, argDescrip
); le
+= strlen(le
);
296 strcpy(le
, argDescrip
); le
+= strlen(le
);
298 if (opt
->argInfo
& POPT_ARGFLAG_OPTIONAL
)
304 fprintf(fp
," %-*s ", maxLeftCol
, left
);
306 fprintf(fp
," %s\n", left
);
312 help
= defs
; defs
= NULL
;
315 helpLength
= strlen(help
);
316 while (helpLength
> lineLength
) {
317 const unsigned char * ch
;
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
--;
326 sprintf(format
, "%%.%ds\n%%%ds", (int) (ch
- help
), indentLength
);
328 fprintf(fp
, format
, help
, " ");
331 while (isspace(*help
) && *help
) help
++;
332 helpLength
= strlen(help
);
335 if (helpLength
) fprintf(fp
, "%s\n", help
);
338 /*@-dependenttrans@*/
340 /*@=dependenttrans@*/
345 * @param opt option(s)
346 * @param translation_domain translation domain
348 static int maxArgWidth(const struct poptOption
* opt
,
349 /*@null@*/ const char * translation_domain
)
357 while (opt
->longName
|| opt
->shortName
|| opt
->arg
) {
358 if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_INCLUDE_TABLE
) {
359 if (opt
->arg
) /* XXX program error */
360 len
= maxArgWidth(opt
->arg
, translation_domain
);
361 if (len
> max
) max
= len
;
362 } else if (!(opt
->argInfo
& POPT_ARGFLAG_DOC_HIDDEN
)) {
364 if (opt
->shortName
!= '\0') len
+= sizeof("-X")-1;
365 if (opt
->shortName
!= '\0' && opt
->longName
) len
+= sizeof(", ")-1;
367 len
+= ((opt
->argInfo
& POPT_ARGFLAG_ONEDASH
)
368 ? sizeof("-")-1 : sizeof("--")-1);
369 len
+= strlen(opt
->longName
);
372 s
= getArgDescrip(opt
, translation_domain
);
374 len
+= sizeof("=")-1 + strlen(s
);
375 if (opt
->argInfo
& POPT_ARGFLAG_OPTIONAL
) len
+= sizeof("[]")-1;
376 if (len
> max
) max
= len
;
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
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 @*/
402 for (i
= 0, item
= items
; i
< nitems
; i
++, item
++) {
403 const struct poptOption
* opt
;
405 if ((opt
->longName
|| opt
->shortName
) &&
406 !(opt
->argInfo
& POPT_ARGFLAG_DOC_HIDDEN
))
407 singleOptionHelp(fp
, left
, opt
, translation_domain
);
412 * @param fp output file handle
413 * @param table option(s)
414 * @param translation_domain translation domain
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 @*/
422 const struct poptOption
* opt
;
423 const char *sub_transdom
;
425 if (table
== poptAliasOptions
) {
426 itemHelp(fp
, con
->aliases
, con
->numAliases
, left
, NULL
);
427 itemHelp(fp
, con
->execs
, con
->numExecs
, left
, NULL
);
432 for (opt
= table
; (opt
->longName
|| opt
->shortName
|| opt
->arg
); opt
++) {
433 if ((opt
->longName
|| opt
->shortName
) &&
434 !(opt
->argInfo
& POPT_ARGFLAG_DOC_HIDDEN
))
435 singleOptionHelp(fp
, left
, opt
, translation_domain
);
439 for (opt
= table
; (opt
->longName
|| opt
->shortName
|| opt
->arg
); opt
++) {
440 if ((opt
->argInfo
& POPT_ARG_MASK
) != POPT_ARG_INCLUDE_TABLE
)
442 sub_transdom
= getTableTranslationDomain(opt
->arg
);
443 if (sub_transdom
== NULL
)
444 sub_transdom
= translation_domain
;
447 fprintf(fp
, "\n%s\n", D_(sub_transdom
, opt
->descrip
));
449 singleTableHelp(con
, fp
, opt
->arg
, left
, sub_transdom
);
455 * @param fp output file handle
457 static int showHelpIntro(poptContext con
, FILE * fp
)
458 /*@globals fileSystem @*/
459 /*@modifies *fp, fileSystem @*/
464 fprintf(fp
, POPT_("Usage:"));
465 if (!(con
->flags
& POPT_CONTEXT_KEEP_FIRST
)) {
466 /*@-nullderef@*/ /* LCL: wazzup? */
467 fn
= con
->optionStack
->argv
[0];
469 if (fn
== NULL
) return len
;
470 if (strchr(fn
, '/')) fn
= strrchr(fn
, '/') + 1;
471 fprintf(fp
, " %s", fn
);
472 len
+= strlen(fn
) + 1;
478 void poptPrintHelp(poptContext con
, FILE * fp
, /*@unused@*/ UNUSED(int flags
))
482 (void) showHelpIntro(con
, fp
);
484 fprintf(fp
, " %s\n", con
->otherHelp
);
486 fprintf(fp
, " %s\n", POPT_("[OPTION...]"));
488 leftColWidth
= maxArgWidth(con
->options
, NULL
);
489 singleTableHelp(con
, fp
, con
->options
, leftColWidth
, NULL
);
493 * @param fp output file handle
494 * @param opt option(s)
495 * @param translation_domain translation domain
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 @*/
504 char shortStr
[2] = { '\0', '\0' };
505 const char * item
= shortStr
;
506 const char * argDescrip
= getArgDescrip(opt
, translation_domain
);
508 if (opt
->shortName
!= '\0' ) {
509 if (!(opt
->argInfo
& POPT_ARG_MASK
))
510 return cursor
; /* we did these already */
512 shortStr
[0] = opt
->shortName
;
514 } else if (opt
->longName
) {
515 len
+= 1 + strlen(opt
->longName
);
516 item
= opt
->longName
;
519 if (len
== 3) return cursor
;
522 len
+= strlen(argDescrip
) + 1;
524 if ((cursor
+ len
) > 79) {
529 fprintf(fp
, " [-%s%s%s%s]",
530 ((opt
->shortName
|| (opt
->argInfo
& POPT_ARGFLAG_ONEDASH
)) ? "" : "-"),
532 (argDescrip
? (opt
->shortName
!= '\0' ? " " : "=") : ""),
533 (argDescrip
? argDescrip
: ""));
535 return cursor
+ len
+ 1;
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
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 @*/
552 /*@-branchstate@*/ /* FIX: W2DO? */
554 for (i
= 0; i
< nitems
; i
++, item
++) {
555 const struct poptOption
* opt
;
557 if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_INTL_DOMAIN
) {
558 translation_domain
= (const char *)opt
->arg
;
559 } else if ((opt
->longName
|| opt
->shortName
) &&
560 !(opt
->argInfo
& POPT_ARGFLAG_DOC_HIDDEN
)) {
561 cursor
= singleOptionUsage(fp
, cursor
, opt
, translation_domain
);
570 * @param fp output file handle
571 * @param opt option(s)
572 * @param translation_domain translation domain
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 @*/
580 /*@-branchstate@*/ /* FIX: W2DO? */
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
,
589 } else if ((opt
->longName
|| opt
->shortName
) &&
590 !(opt
->argInfo
& POPT_ARGFLAG_DOC_HIDDEN
)) {
591 cursor
= singleOptionUsage(fp
, cursor
, opt
, translation_domain
);
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
606 static int showShortOptions(const struct poptOption
* opt
, FILE * fp
,
607 /*@null@*/ char * str
)
608 /*@globals fileSystem @*/
609 /*@modifies *str, *fp, fileSystem @*/
611 char * s
= alloca(300); /* larger then the ascii set */
614 /*@-branchstate@*/ /* FIX: W2DO? */
616 memset(s
, 0, sizeof(s
));
622 for (; (opt
->longName
|| opt
->shortName
|| opt
->arg
); opt
++) {
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
)
626 if (opt
->arg
) /* XXX program error */
627 (void) showShortOptions(opt
->arg
, fp
, str
);
630 if (s
!= str
|| *s
!= '\0')
633 fprintf(fp
, " [-%s]", s
);
634 return strlen(s
) + 4;
637 void poptPrintUsage(poptContext con
, FILE * fp
, /*@unused@*/ UNUSED(int flags
))
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
);
647 if (con
->otherHelp
) {
648 cursor
+= strlen(con
->otherHelp
) + 1;
649 if (cursor
> 79) fprintf(fp
, "\n ");
650 fprintf(fp
, " %s", con
->otherHelp
);
656 void poptSetOtherOptionHelp(poptContext con
, const char * text
)
658 con
->otherHelp
= _free(con
->otherHelp
);
659 con
->otherHelp
= xstrdup(text
);