popt
1.14
|
00001 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */ 00002 00007 /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING 00008 file accompanying popt source distributions, available from 00009 ftp://ftp.rpm.org/pub/rpm/dist. */ 00010 00011 #include "system.h" 00012 00013 #define POPT_USE_TIOCGWINSZ 00014 #ifdef POPT_USE_TIOCGWINSZ 00015 #include <sys/ioctl.h> 00016 #endif 00017 00018 #define POPT_WCHAR_HACK 00019 #ifdef POPT_WCHAR_HACK 00020 #include <wchar.h> /* for mbsrtowcs */ 00021 /*@access mbstate_t @*/ 00022 #endif 00023 #include "poptint.h" 00024 00025 /*@access poptContext@*/ 00026 00035 /*@exits@*/ 00036 static void displayArgs(poptContext con, 00037 /*@unused@*/ UNUSED(enum poptCallbackReason foo), 00038 struct poptOption * key, 00039 /*@unused@*/ UNUSED(const char * arg), 00040 /*@unused@*/ UNUSED(void * data)) 00041 /*@globals fileSystem@*/ 00042 /*@modifies fileSystem@*/ 00043 { 00044 if (key->shortName == '?') 00045 poptPrintHelp(con, stdout, 0); 00046 else 00047 poptPrintUsage(con, stdout, 0); 00048 00049 #if !defined(__LCLINT__) /* XXX keep both splint & valgrind happy */ 00050 con = poptFreeContext(con); 00051 #endif 00052 exit(0); 00053 } 00054 00055 #ifdef NOTYET 00056 /*@unchecked@*/ 00057 static int show_option_defaults = 0; 00058 #endif 00059 00063 /*@observer@*/ /*@unchecked@*/ 00064 struct poptOption poptAliasOptions[] = { 00065 POPT_TABLEEND 00066 }; 00067 00071 /*@-castfcnptr@*/ 00072 /*@observer@*/ /*@unchecked@*/ 00073 struct poptOption poptHelpOptions[] = { 00074 { NULL, '\0', POPT_ARG_CALLBACK, (void *)displayArgs, 0, NULL, NULL }, 00075 { "help", '?', 0, NULL, (int)'?', N_("Show this help message"), NULL }, 00076 { "usage", '\0', 0, NULL, (int)'u', N_("Display brief usage message"), NULL }, 00077 POPT_TABLEEND 00078 } ; 00079 00080 /*@observer@*/ /*@unchecked@*/ 00081 static struct poptOption poptHelpOptions2[] = { 00082 /*@-readonlytrans@*/ 00083 { NULL, '\0', POPT_ARG_INTL_DOMAIN, PACKAGE, 0, NULL, NULL}, 00084 /*@=readonlytrans@*/ 00085 { NULL, '\0', POPT_ARG_CALLBACK, (void *)displayArgs, 0, NULL, NULL }, 00086 { "help", '?', 0, NULL, (int)'?', N_("Show this help message"), NULL }, 00087 { "usage", '\0', 0, NULL, (int)'u', N_("Display brief usage message"), NULL }, 00088 #ifdef NOTYET 00089 { "defaults", '\0', POPT_ARG_NONE, &show_option_defaults, 0, 00090 N_("Display option defaults in message"), NULL }, 00091 #endif 00092 { "", '\0', 0, NULL, 0, N_("Terminate options"), NULL }, 00093 POPT_TABLEEND 00094 } ; 00095 00096 /*@observer@*/ /*@unchecked@*/ 00097 struct poptOption * poptHelpOptionsI18N = poptHelpOptions2; 00098 /*@=castfcnptr@*/ 00099 00100 #define _POPTHELP_MAXLINE ((size_t)79) 00101 00102 typedef struct columns_s { 00103 size_t cur; 00104 size_t max; 00105 } * columns_t; 00106 00112 static size_t maxColumnWidth(FILE *fp) 00113 /*@*/ 00114 { 00115 size_t maxcols = _POPTHELP_MAXLINE; 00116 #if defined(TIOCGWINSZ) 00117 struct winsize ws; 00118 int fdno = fileno(fp ? fp : stdout); 00119 00120 memset(&ws, 0, sizeof(ws)); 00121 if (fdno >= 0 && !ioctl(fdno, (unsigned long)TIOCGWINSZ, &ws)) { 00122 size_t ws_col = (size_t)ws.ws_col; 00123 if (ws_col > maxcols && ws_col < (size_t)256) 00124 maxcols = ws_col - 1; 00125 } 00126 #endif 00127 return maxcols; 00128 } 00129 00135 static inline size_t stringDisplayWidth(const char *s) 00136 /*@*/ 00137 { 00138 size_t n = strlen(s); 00139 #ifdef POPT_WCHAR_HACK 00140 mbstate_t t; 00141 00142 memset ((void *)&t, 0, sizeof (t)); /* In initial state. */ 00143 /* Determine number of display characters. */ 00144 n = mbsrtowcs (NULL, &s, n, &t); 00145 #else 00146 n = 0; 00147 for (; *s; s = POPT_next_char(s)); 00148 n++; 00149 #endif 00150 00151 return n; 00152 } 00153 00157 /*@observer@*/ /*@null@*/ static const char * 00158 getTableTranslationDomain(/*@null@*/ const struct poptOption *opt) 00159 /*@*/ 00160 { 00161 if (opt != NULL) 00162 for (; opt->longName || opt->shortName || opt->arg; opt++) { 00163 if (opt->argInfo == POPT_ARG_INTL_DOMAIN) 00164 return opt->arg; 00165 } 00166 return NULL; 00167 } 00168 00173 /*@observer@*/ /*@null@*/ static const char * 00174 getArgDescrip(const struct poptOption * opt, 00175 /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */ 00176 /*@null@*/ const char * translation_domain) 00177 /*@=paramuse@*/ 00178 /*@*/ 00179 { 00180 if (!poptArgType(opt)) return NULL; 00181 00182 if (poptArgType(opt) == POPT_ARG_MAINCALL) 00183 return opt->argDescrip; 00184 if (poptArgType(opt) == POPT_ARG_ARGV) 00185 return opt->argDescrip; 00186 00187 if (opt->argDescrip) { 00188 /* Some strings need popt library, not application, i18n domain. */ 00189 if (opt == (poptHelpOptions + 1) 00190 || opt == (poptHelpOptions + 2) 00191 || !strcmp(opt->argDescrip, N_("Help options:")) 00192 || !strcmp(opt->argDescrip, N_("Options implemented via popt alias/exec:"))) 00193 return POPT_(opt->argDescrip); 00194 00195 /* Use the application i18n domain. */ 00196 return D_(translation_domain, opt->argDescrip); 00197 } 00198 00199 switch (poptArgType(opt)) { 00200 case POPT_ARG_NONE: return POPT_("NONE"); 00201 #ifdef DYING 00202 case POPT_ARG_VAL: return POPT_("VAL"); 00203 #else 00204 case POPT_ARG_VAL: return NULL; 00205 #endif 00206 case POPT_ARG_INT: return POPT_("INT"); 00207 case POPT_ARG_LONG: return POPT_("LONG"); 00208 case POPT_ARG_LONGLONG: return POPT_("LONGLONG"); 00209 case POPT_ARG_STRING: return POPT_("STRING"); 00210 case POPT_ARG_FLOAT: return POPT_("FLOAT"); 00211 case POPT_ARG_DOUBLE: return POPT_("DOUBLE"); 00212 case POPT_ARG_MAINCALL: return NULL; 00213 case POPT_ARG_ARGV: return NULL; 00214 default: return POPT_("ARG"); 00215 } 00216 } 00217 00225 static /*@only@*/ /*@null@*/ char * 00226 singleOptionDefaultValue(size_t lineLength, 00227 const struct poptOption * opt, 00228 /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */ 00229 /*@null@*/ const char * translation_domain) 00230 /*@=paramuse@*/ 00231 /*@*/ 00232 { 00233 const char * defstr = D_(translation_domain, "default"); 00234 char * le = malloc(4*lineLength + 1); 00235 char * l = le; 00236 00237 if (le == NULL) return NULL; /* XXX can't happen */ 00238 *le = '\0'; 00239 *le++ = '('; 00240 le = stpcpy(le, defstr); 00241 *le++ = ':'; 00242 *le++ = ' '; 00243 if (opt->arg) { /* XXX programmer error */ 00244 poptArg arg = { .ptr = opt->arg }; 00245 switch (poptArgType(opt)) { 00246 case POPT_ARG_VAL: 00247 case POPT_ARG_INT: 00248 le += sprintf(le, "%d", arg.intp[0]); 00249 break; 00250 case POPT_ARG_LONG: 00251 le += sprintf(le, "%ld", arg.longp[0]); 00252 break; 00253 case POPT_ARG_LONGLONG: 00254 le += sprintf(le, "%lld", arg.longlongp[0]); 00255 break; 00256 case POPT_ARG_FLOAT: 00257 { double aDouble = (double) arg.floatp[0]; 00258 le += sprintf(le, "%g", aDouble); 00259 } break; 00260 case POPT_ARG_DOUBLE: 00261 le += sprintf(le, "%g", arg.doublep[0]); 00262 break; 00263 case POPT_ARG_MAINCALL: 00264 le += sprintf(le, "%p", opt->arg); 00265 break; 00266 case POPT_ARG_ARGV: 00267 le += sprintf(le, "%p", opt->arg); 00268 break; 00269 case POPT_ARG_STRING: 00270 { const char * s = arg.argv[0]; 00271 if (s == NULL) 00272 le = stpcpy(le, "null"); 00273 else { 00274 size_t limit = 4*lineLength - (le - l) - sizeof("\"\")"); 00275 size_t slen; 00276 *le++ = '"'; 00277 strncpy(le, s, limit); le[limit] = '\0'; le += (slen = strlen(le)); 00278 if (slen == limit && s[limit]) 00279 le[-1] = le[-2] = le[-3] = '.'; 00280 *le++ = '"'; 00281 } 00282 } break; 00283 case POPT_ARG_NONE: 00284 default: 00285 l = _free(l); 00286 return NULL; 00287 /*@notreached@*/ break; 00288 } 00289 } 00290 *le++ = ')'; 00291 *le = '\0'; 00292 00293 return l; 00294 } 00295 00303 static void singleOptionHelp(FILE * fp, columns_t columns, 00304 const struct poptOption * opt, 00305 /*@null@*/ const char * translation_domain) 00306 /*@globals fileSystem @*/ 00307 /*@modifies fp, fileSystem @*/ 00308 { 00309 size_t maxLeftCol = columns->cur; 00310 size_t indentLength = maxLeftCol + 5; 00311 size_t lineLength = columns->max - indentLength; 00312 const char * help = D_(translation_domain, opt->descrip); 00313 const char * argDescrip = getArgDescrip(opt, translation_domain); 00314 /* Display shortName iff printable non-space. */ 00315 int prtshort = (int)(isprint((int)opt->shortName) && opt->shortName != ' '); 00316 size_t helpLength; 00317 char * defs = NULL; 00318 char * left; 00319 size_t nb = maxLeftCol + 1; 00320 int displaypad = 0; 00321 int xx; 00322 00323 /* Make sure there's more than enough room in target buffer. */ 00324 if (opt->longName) nb += strlen(opt->longName); 00325 if (argDescrip) nb += strlen(argDescrip); 00326 00327 left = malloc(nb); 00328 if (left == NULL) return; /* XXX can't happen */ 00329 left[0] = '\0'; 00330 left[maxLeftCol] = '\0'; 00331 00332 #define prtlong (opt->longName != NULL) /* XXX splint needs a clue */ 00333 if (!(prtshort || prtlong)) 00334 goto out; 00335 if (prtshort && prtlong) { 00336 char *dash = F_ISSET(opt, ONEDASH) ? "-" : "--"; 00337 left[0] = '-'; 00338 left[1] = opt->shortName; 00339 (void) stpcpy(stpcpy(stpcpy(left+2, ", "), dash), opt->longName); 00340 } else if (prtshort) { 00341 left[0] = '-'; 00342 left[1] = opt->shortName; 00343 left[2] = '\0'; 00344 } else if (prtlong) { 00345 /* XXX --long always padded for alignment with/without "-X, ". */ 00346 char *dash = poptArgType(opt) == POPT_ARG_MAINCALL ? "" 00347 : (F_ISSET(opt, ONEDASH) ? "-" : "--"); 00348 (void) stpcpy(stpcpy(stpcpy(left, " "), dash), opt->longName); 00349 } 00350 #undef prtlong 00351 00352 if (argDescrip) { 00353 char * le = left + strlen(left); 00354 00355 if (F_ISSET(opt, OPTIONAL)) 00356 *le++ = '['; 00357 00358 /* Choose type of output */ 00359 if (F_ISSET(opt, SHOW_DEFAULT)) { 00360 defs = singleOptionDefaultValue(lineLength, opt, translation_domain); 00361 if (defs) { 00362 char * t = malloc((help ? strlen(help) : 0) + 00363 strlen(defs) + sizeof(" ")); 00364 if (t) { 00365 char * te = t; 00366 if (help) 00367 te = stpcpy(te, help); 00368 *te++ = ' '; 00369 strcpy(te, defs); 00370 defs = _free(defs); 00371 } 00372 defs = t; 00373 } 00374 } 00375 00376 if (opt->argDescrip == NULL) { 00377 switch (poptArgType(opt)) { 00378 case POPT_ARG_NONE: 00379 break; 00380 case POPT_ARG_VAL: 00381 #ifdef NOTNOW /* XXX pug ugly nerdy output */ 00382 { long aLong = opt->val; 00383 int ops = F_ISSET(opt, LOGICALOPS); 00384 int negate = F_ISSET(opt, NOT); 00385 00386 /* Don't bother displaying typical values */ 00387 if (!ops && (aLong == 0L || aLong == 1L || aLong == -1L)) 00388 break; 00389 *le++ = '['; 00390 switch (ops) { 00391 case POPT_ARGFLAG_OR: 00392 *le++ = '|'; 00393 /*@innerbreak@*/ break; 00394 case POPT_ARGFLAG_AND: 00395 *le++ = '&'; 00396 /*@innerbreak@*/ break; 00397 case POPT_ARGFLAG_XOR: 00398 *le++ = '^'; 00399 /*@innerbreak@*/ break; 00400 default: 00401 /*@innerbreak@*/ break; 00402 } 00403 *le++ = (opt->longName != NULL ? '=' : ' '); 00404 if (negate) *le++ = '~'; 00405 /*@-formatconst@*/ 00406 le += sprintf(le, (ops ? "0x%lx" : "%ld"), aLong); 00407 /*@=formatconst@*/ 00408 *le++ = ']'; 00409 } 00410 #endif 00411 break; 00412 case POPT_ARG_INT: 00413 case POPT_ARG_LONG: 00414 case POPT_ARG_LONGLONG: 00415 case POPT_ARG_FLOAT: 00416 case POPT_ARG_DOUBLE: 00417 case POPT_ARG_STRING: 00418 *le++ = (opt->longName != NULL ? '=' : ' '); 00419 le = stpcpy(le, argDescrip); 00420 break; 00421 default: 00422 break; 00423 } 00424 } else { 00425 char *leo; 00426 00427 /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */ 00428 if (!strchr(" =(", argDescrip[0])) 00429 *le++ = ((poptArgType(opt) == POPT_ARG_MAINCALL) ? ' ' : 00430 (poptArgType(opt) == POPT_ARG_ARGV) ? ' ' : '='); 00431 le = stpcpy(leo = le, argDescrip); 00432 00433 /* Adjust for (possible) wide characters. */ 00434 displaypad = (int)((le - leo) - stringDisplayWidth(argDescrip)); 00435 } 00436 if (F_ISSET(opt, OPTIONAL)) 00437 *le++ = ']'; 00438 *le = '\0'; 00439 } 00440 00441 if (help) 00442 xx = POPT_fprintf(fp," %-*s ", (int)(maxLeftCol+displaypad), left); 00443 else { 00444 xx = POPT_fprintf(fp," %s\n", left); 00445 goto out; 00446 } 00447 00448 left = _free(left); 00449 if (defs) 00450 help = defs; 00451 00452 helpLength = strlen(help); 00453 while (helpLength > lineLength) { 00454 const char * ch; 00455 char format[16]; 00456 00457 ch = help + lineLength - 1; 00458 while (ch > help && !_isspaceptr(ch)) 00459 ch = POPT_prev_char(ch); 00460 if (ch == help) break; /* give up */ 00461 while (ch > (help + 1) && _isspaceptr(ch)) 00462 ch = POPT_prev_char (ch); 00463 ch = POPT_next_char(ch); 00464 00465 /* 00466 * XXX strdup is necessary to add NUL terminator so that an unknown 00467 * no. of (possible) multi-byte characters can be displayed. 00468 */ 00469 { char * fmthelp = xstrdup(help); 00470 if (fmthelp) { 00471 fmthelp[ch - help] = '\0'; 00472 sprintf(format, "%%s\n%%%ds", (int) indentLength); 00473 /*@-formatconst@*/ 00474 xx = POPT_fprintf(fp, format, fmthelp, " "); 00475 /*@=formatconst@*/ 00476 free(fmthelp); 00477 } 00478 } 00479 00480 help = ch; 00481 while (_isspaceptr(help) && *help) 00482 help = POPT_next_char(help); 00483 helpLength = strlen(help); 00484 } 00485 00486 if (helpLength) fprintf(fp, "%s\n", help); 00487 help = NULL; 00488 00489 out: 00490 /*@-dependenttrans@*/ 00491 defs = _free(defs); 00492 /*@=dependenttrans@*/ 00493 left = _free(left); 00494 } 00495 00502 static size_t maxArgWidth(const struct poptOption * opt, 00503 /*@null@*/ const char * translation_domain) 00504 /*@*/ 00505 { 00506 size_t max = 0; 00507 size_t len = 0; 00508 const char * argDescrip; 00509 00510 if (opt != NULL) 00511 while (opt->longName || opt->shortName || opt->arg) { 00512 if (poptArgType(opt) == POPT_ARG_INCLUDE_TABLE) { 00513 if (opt->arg) /* XXX program error */ 00514 len = maxArgWidth(opt->arg, translation_domain); 00515 if (len > max) max = len; 00516 } else if (!F_ISSET(opt, DOC_HIDDEN)) { 00517 len = sizeof(" ")-1; 00518 /* XXX --long always padded for alignment with/without "-X, ". */ 00519 len += sizeof("-X, ")-1; 00520 if (opt->longName) { 00521 len += (F_ISSET(opt, ONEDASH) ? sizeof("-") : sizeof("--")) - 1; 00522 len += strlen(opt->longName); 00523 } 00524 00525 argDescrip = getArgDescrip(opt, translation_domain); 00526 00527 if (argDescrip) { 00528 00529 /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */ 00530 if (!strchr(" =(", argDescrip[0])) len += sizeof("=")-1; 00531 00532 /* Adjust for (possible) wide characters. */ 00533 len += stringDisplayWidth(argDescrip); 00534 } 00535 00536 if (F_ISSET(opt, OPTIONAL)) len += sizeof("[]")-1; 00537 if (len > max) max = len; 00538 } 00539 opt++; 00540 } 00541 00542 return max; 00543 } 00544 00553 static void itemHelp(FILE * fp, 00554 /*@null@*/ poptItem items, int nitems, 00555 columns_t columns, 00556 /*@null@*/ const char * translation_domain) 00557 /*@globals fileSystem @*/ 00558 /*@modifies fp, fileSystem @*/ 00559 { 00560 poptItem item; 00561 int i; 00562 00563 if (items != NULL) 00564 for (i = 0, item = items; i < nitems; i++, item++) { 00565 const struct poptOption * opt; 00566 opt = &item->option; 00567 if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN)) 00568 singleOptionHelp(fp, columns, opt, translation_domain); 00569 } 00570 } 00571 00580 static void singleTableHelp(poptContext con, FILE * fp, 00581 /*@null@*/ const struct poptOption * table, 00582 columns_t columns, 00583 /*@null@*/ const char * translation_domain) 00584 /*@globals fileSystem @*/ 00585 /*@modifies fp, columns->cur, fileSystem @*/ 00586 { 00587 const struct poptOption * opt; 00588 const char *sub_transdom; 00589 int xx; 00590 00591 if (con == NULL) return; 00592 00593 if (table == poptAliasOptions) { 00594 itemHelp(fp, con->aliases, con->numAliases, columns, NULL); 00595 itemHelp(fp, con->execs, con->numExecs, columns, NULL); 00596 return; 00597 } 00598 00599 if (table != NULL) 00600 for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) { 00601 if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN)) 00602 singleOptionHelp(fp, columns, opt, translation_domain); 00603 } 00604 00605 if (table != NULL) 00606 for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) { 00607 if (poptArgType(opt) != POPT_ARG_INCLUDE_TABLE) 00608 continue; 00609 sub_transdom = getTableTranslationDomain(opt->arg); 00610 if (sub_transdom == NULL) 00611 sub_transdom = translation_domain; 00612 00613 /* If no popt aliases/execs, skip poptAliasOption processing. */ 00614 if (opt->arg == poptAliasOptions && !(con->numAliases || con->numExecs)) 00615 continue; 00616 if (opt->descrip) 00617 xx = POPT_fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip)); 00618 00619 singleTableHelp(con, fp, opt->arg, columns, sub_transdom); 00620 } 00621 } 00622 00627 static size_t showHelpIntro(poptContext con, FILE * fp) 00628 /*@globals fileSystem @*/ 00629 /*@modifies fp, fileSystem @*/ 00630 { 00631 size_t len = (size_t)6; 00632 const char * fn; 00633 int xx; 00634 00635 xx = POPT_fprintf(fp, POPT_("Usage:")); 00636 if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) { 00637 /*@-type@*/ /* LCL: wazzup? */ 00638 fn = con->optionStack ? con->optionStack->argv[0] : NULL; 00639 /*@=type@*/ 00640 if (fn == NULL) return len; 00641 if (strchr(fn, '/')) fn = strrchr(fn, '/') + 1; 00642 /* XXX POPT_fprintf not needed for argv[0] display. */ 00643 fprintf(fp, " %s", fn); 00644 len += strlen(fn) + 1; 00645 } 00646 00647 return len; 00648 } 00649 00650 void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags)) 00651 { 00652 columns_t columns = calloc((size_t)1, sizeof(*columns)); 00653 int xx; 00654 00655 if (con == NULL) return; 00656 00657 (void) showHelpIntro(con, fp); 00658 if (con->otherHelp) 00659 xx = POPT_fprintf(fp, " %s\n", con->otherHelp); 00660 else 00661 xx = POPT_fprintf(fp, " %s\n", POPT_("[OPTION...]")); 00662 00663 if (columns) { 00664 columns->cur = maxArgWidth(con->options, NULL); 00665 columns->max = maxColumnWidth(fp); 00666 singleTableHelp(con, fp, con->options, columns, NULL); 00667 free(columns); 00668 } 00669 } 00670 00678 static size_t singleOptionUsage(FILE * fp, columns_t columns, 00679 const struct poptOption * opt, 00680 /*@null@*/ const char *translation_domain) 00681 /*@globals fileSystem @*/ 00682 /*@modifies fp, columns->cur, fileSystem @*/ 00683 { 00684 size_t len = sizeof(" []")-1; 00685 const char * argDescrip = getArgDescrip(opt, translation_domain); 00686 /* Display shortName iff printable non-space. */ 00687 int prtshort = (int)(isprint((int)opt->shortName) && opt->shortName != ' '); 00688 00689 #define prtlong (opt->longName != NULL) /* XXX splint needs a clue */ 00690 if (!(prtshort || prtlong)) 00691 return columns->cur; 00692 00693 len = sizeof(" []")-1; 00694 if (prtshort) 00695 len += sizeof("-c")-1; 00696 if (prtlong) { 00697 if (prtshort) len += sizeof("|")-1; 00698 len += (F_ISSET(opt, ONEDASH) ? sizeof("-") : sizeof("--")) - 1; 00699 len += strlen(opt->longName); 00700 } 00701 00702 if (argDescrip) { 00703 00704 /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */ 00705 if (!strchr(" =(", argDescrip[0])) len += sizeof("=")-1; 00706 00707 /* Adjust for (possible) wide characters. */ 00708 len += stringDisplayWidth(argDescrip); 00709 } 00710 00711 if ((columns->cur + len) > columns->max) { 00712 fprintf(fp, "\n "); 00713 columns->cur = (size_t)7; 00714 } 00715 00716 fprintf(fp, " ["); 00717 if (prtshort) 00718 fprintf(fp, "-%c", opt->shortName); 00719 if (prtlong) 00720 fprintf(fp, "%s%s%s", 00721 (prtshort ? "|" : ""), 00722 (F_ISSET(opt, ONEDASH) ? "-" : "--"), 00723 opt->longName); 00724 #undef prtlong 00725 00726 if (argDescrip) { 00727 /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */ 00728 if (!strchr(" =(", argDescrip[0])) fprintf(fp, "="); 00729 fprintf(fp, "%s", argDescrip); 00730 } 00731 fprintf(fp, "]"); 00732 00733 return columns->cur + len + 1; 00734 } 00735 00744 static size_t itemUsage(FILE * fp, columns_t columns, 00745 /*@null@*/ poptItem item, int nitems, 00746 /*@null@*/ const char * translation_domain) 00747 /*@globals fileSystem @*/ 00748 /*@modifies fp, columns->cur, fileSystem @*/ 00749 { 00750 int i; 00751 00752 if (item != NULL) 00753 for (i = 0; i < nitems; i++, item++) { 00754 const struct poptOption * opt; 00755 opt = &item->option; 00756 if (poptArgType(opt) == POPT_ARG_INTL_DOMAIN) { 00757 translation_domain = (const char *)opt->arg; 00758 } else 00759 if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN)) { 00760 columns->cur = singleOptionUsage(fp, columns, opt, translation_domain); 00761 } 00762 } 00763 00764 return columns->cur; 00765 } 00766 00770 typedef struct poptDone_s { 00771 int nopts; 00772 int maxopts; 00773 /*@null@*/ 00774 const void ** opts; 00775 } * poptDone; 00776 00787 static size_t singleTableUsage(poptContext con, FILE * fp, columns_t columns, 00788 /*@null@*/ const struct poptOption * opt, 00789 /*@null@*/ const char * translation_domain, 00790 /*@null@*/ poptDone done) 00791 /*@globals fileSystem @*/ 00792 /*@modifies fp, columns->cur, done, fileSystem @*/ 00793 { 00794 if (con != NULL && opt != NULL) 00795 for (; (opt->longName || opt->shortName || opt->arg) ; opt++) { 00796 if (poptArgType(opt) == POPT_ARG_INTL_DOMAIN) { 00797 translation_domain = (const char *)opt->arg; 00798 } else 00799 if (poptArgType(opt) == POPT_ARG_INCLUDE_TABLE) { 00800 if (done) { 00801 int i = 0; 00802 if (done->opts != NULL) 00803 for (i = 0; i < done->nopts; i++) { 00804 const void * that = done->opts[i]; 00805 if (that == NULL || that != opt->arg) 00806 /*@innercontinue@*/ continue; 00807 /*@innerbreak@*/ break; 00808 } 00809 /* Skip if this table has already been processed. */ 00810 if (opt->arg == NULL || i < done->nopts) 00811 continue; 00812 if (done->opts != NULL && done->nopts < done->maxopts) 00813 done->opts[done->nopts++] = (const void *) opt->arg; 00814 } 00815 columns->cur = singleTableUsage(con, fp, columns, opt->arg, 00816 translation_domain, done); 00817 } else 00818 if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN)) { 00819 columns->cur = singleOptionUsage(fp, columns, opt, translation_domain); 00820 } 00821 } 00822 00823 return columns->cur; 00824 } 00825 00834 static size_t showShortOptions(const struct poptOption * opt, FILE * fp, 00835 /*@null@*/ char * str) 00836 /*@globals fileSystem @*/ 00837 /*@modifies str, *fp, fileSystem @*/ 00838 /*@requires maxRead(str) >= 0 @*/ 00839 { 00840 /* bufsize larger then the ascii set, lazy allocation on top level call. */ 00841 size_t nb = (size_t)300; 00842 char * s = (str != NULL ? str : calloc((size_t)1, nb)); 00843 size_t len = (size_t)0; 00844 00845 if (s == NULL) 00846 return 0; 00847 00848 if (opt != NULL) 00849 for (; (opt->longName || opt->shortName || opt->arg); opt++) { 00850 if (!F_ISSET(opt, DOC_HIDDEN) && opt->shortName && !poptArgType(opt)) 00851 { 00852 /* Display shortName iff unique printable non-space. */ 00853 if (!strchr(s, opt->shortName) && isprint((int)opt->shortName) 00854 && opt->shortName != ' ') 00855 s[strlen(s)] = opt->shortName; 00856 } else if (poptArgType(opt) == POPT_ARG_INCLUDE_TABLE) 00857 if (opt->arg) /* XXX program error */ 00858 len = showShortOptions(opt->arg, fp, s); 00859 } 00860 00861 /* On return to top level, print the short options, return print length. */ 00862 if (s != str && *s != '\0') { 00863 fprintf(fp, " [-%s]", s); 00864 len = strlen(s) + sizeof(" [-]")-1; 00865 } 00866 /*@-temptrans@*/ /* LCL: local s, not str arg, is being freed. */ 00867 if (s != str) 00868 free(s); 00869 /*@=temptrans@*/ 00870 return len; 00871 } 00872 00873 void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags)) 00874 { 00875 columns_t columns = calloc((size_t)1, sizeof(*columns)); 00876 struct poptDone_s done_buf; 00877 poptDone done = &done_buf; 00878 00879 if (con == NULL) return; 00880 00881 memset(done, 0, sizeof(*done)); 00882 done->nopts = 0; 00883 done->maxopts = 64; 00884 if (columns) { 00885 columns->cur = done->maxopts * sizeof(*done->opts); 00886 columns->max = maxColumnWidth(fp); 00887 done->opts = calloc((size_t)1, columns->cur); 00888 /*@-keeptrans@*/ 00889 if (done->opts != NULL) 00890 done->opts[done->nopts++] = (const void *) con->options; 00891 /*@=keeptrans@*/ 00892 00893 columns->cur = showHelpIntro(con, fp); 00894 columns->cur += showShortOptions(con->options, fp, NULL); 00895 columns->cur = singleTableUsage(con, fp, columns, con->options, NULL, done); 00896 columns->cur = itemUsage(fp, columns, con->aliases, con->numAliases, NULL); 00897 columns->cur = itemUsage(fp, columns, con->execs, con->numExecs, NULL); 00898 00899 if (con->otherHelp) { 00900 columns->cur += strlen(con->otherHelp) + 1; 00901 if (columns->cur > columns->max) fprintf(fp, "\n "); 00902 fprintf(fp, " %s", con->otherHelp); 00903 } 00904 00905 fprintf(fp, "\n"); 00906 if (done->opts != NULL) 00907 free(done->opts); 00908 free(columns); 00909 } 00910 } 00911 00912 void poptSetOtherOptionHelp(poptContext con, const char * text) 00913 { 00914 if (con == NULL) return; 00915 00916 con->otherHelp = _free(con->otherHelp); 00917 con->otherHelp = xstrdup(text); 00918 }