popt
1.16
|
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_SHORT: return POPT_("SHORT"); 00208 case POPT_ARG_LONG: return POPT_("LONG"); 00209 case POPT_ARG_LONGLONG: return POPT_("LONGLONG"); 00210 case POPT_ARG_STRING: return POPT_("STRING"); 00211 case POPT_ARG_FLOAT: return POPT_("FLOAT"); 00212 case POPT_ARG_DOUBLE: return POPT_("DOUBLE"); 00213 case POPT_ARG_MAINCALL: return NULL; 00214 case POPT_ARG_ARGV: return NULL; 00215 default: return POPT_("ARG"); 00216 } 00217 } 00218 00226 static /*@only@*/ /*@null@*/ char * 00227 singleOptionDefaultValue(size_t lineLength, 00228 const struct poptOption * opt, 00229 /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */ 00230 /*@null@*/ const char * translation_domain) 00231 /*@=paramuse@*/ 00232 /*@*/ 00233 { 00234 const char * defstr = D_(translation_domain, "default"); 00235 char * le = malloc(4*lineLength + 1); 00236 char * l = le; 00237 00238 if (le == NULL) return NULL; /* XXX can't happen */ 00239 *le = '\0'; 00240 *le++ = '('; 00241 le = stpcpy(le, defstr); 00242 *le++ = ':'; 00243 *le++ = ' '; 00244 if (opt->arg) { /* XXX programmer error */ 00245 poptArg arg = { .ptr = opt->arg }; 00246 switch (poptArgType(opt)) { 00247 case POPT_ARG_VAL: 00248 case POPT_ARG_INT: 00249 le += sprintf(le, "%d", arg.intp[0]); 00250 break; 00251 case POPT_ARG_SHORT: 00252 le += sprintf(le, "%hd", arg.shortp[0]); 00253 break; 00254 case POPT_ARG_LONG: 00255 le += sprintf(le, "%ld", arg.longp[0]); 00256 break; 00257 case POPT_ARG_LONGLONG: 00258 le += sprintf(le, "%lld", arg.longlongp[0]); 00259 break; 00260 case POPT_ARG_FLOAT: 00261 { double aDouble = (double) arg.floatp[0]; 00262 le += sprintf(le, "%g", aDouble); 00263 } break; 00264 case POPT_ARG_DOUBLE: 00265 le += sprintf(le, "%g", arg.doublep[0]); 00266 break; 00267 case POPT_ARG_MAINCALL: 00268 le += sprintf(le, "%p", opt->arg); 00269 break; 00270 case POPT_ARG_ARGV: 00271 le += sprintf(le, "%p", opt->arg); 00272 break; 00273 case POPT_ARG_STRING: 00274 { const char * s = arg.argv[0]; 00275 if (s == NULL) 00276 le = stpcpy(le, "null"); 00277 else { 00278 size_t limit = 4*lineLength - (le - l) - sizeof("\"\")"); 00279 size_t slen; 00280 *le++ = '"'; 00281 strncpy(le, s, limit); le[limit] = '\0'; le += (slen = strlen(le)); 00282 if (slen == limit && s[limit]) 00283 le[-1] = le[-2] = le[-3] = '.'; 00284 *le++ = '"'; 00285 } 00286 } break; 00287 case POPT_ARG_NONE: 00288 default: 00289 l = _free(l); 00290 return NULL; 00291 /*@notreached@*/ break; 00292 } 00293 } 00294 *le++ = ')'; 00295 *le = '\0'; 00296 00297 return l; 00298 } 00299 00307 static void singleOptionHelp(FILE * fp, columns_t columns, 00308 const struct poptOption * opt, 00309 /*@null@*/ const char * translation_domain) 00310 /*@globals fileSystem @*/ 00311 /*@modifies fp, fileSystem @*/ 00312 { 00313 size_t maxLeftCol = columns->cur; 00314 size_t indentLength = maxLeftCol + 5; 00315 size_t lineLength = columns->max - indentLength; 00316 const char * help = D_(translation_domain, opt->descrip); 00317 const char * argDescrip = getArgDescrip(opt, translation_domain); 00318 /* Display shortName iff printable non-space. */ 00319 int prtshort = (int)(isprint((int)opt->shortName) && opt->shortName != ' '); 00320 size_t helpLength; 00321 char * defs = NULL; 00322 char * left; 00323 size_t nb = maxLeftCol + 1; 00324 int displaypad = 0; 00325 int xx; 00326 00327 /* Make sure there's more than enough room in target buffer. */ 00328 if (opt->longName) nb += strlen(opt->longName); 00329 if (F_ISSET(opt, TOGGLE)) nb += sizeof("[no]") - 1; 00330 if (argDescrip) nb += strlen(argDescrip); 00331 00332 left = malloc(nb); 00333 if (left == NULL) return; /* XXX can't happen */ 00334 left[0] = '\0'; 00335 left[maxLeftCol] = '\0'; 00336 00337 #define prtlong (opt->longName != NULL) /* XXX splint needs a clue */ 00338 if (!(prtshort || prtlong)) 00339 goto out; 00340 if (prtshort && prtlong) { 00341 char *dash = F_ISSET(opt, ONEDASH) ? "-" : "--"; 00342 left[0] = '-'; 00343 left[1] = opt->shortName; 00344 (void) stpcpy(stpcpy(stpcpy(left+2, ", "), dash), opt->longName); 00345 } else if (prtshort) { 00346 left[0] = '-'; 00347 left[1] = opt->shortName; 00348 left[2] = '\0'; 00349 } else if (prtlong) { 00350 /* XXX --long always padded for alignment with/without "-X, ". */ 00351 char *dash = poptArgType(opt) == POPT_ARG_MAINCALL ? "" 00352 : (F_ISSET(opt, ONEDASH) ? "-" : "--"); 00353 const char *longName = opt->longName; 00354 const char *toggle; 00355 if (F_ISSET(opt, TOGGLE)) { 00356 toggle = "[no]"; 00357 if (longName[0] == 'n' && longName[1] == 'o') { 00358 longName += sizeof("no") - 1; 00359 if (longName[0] == '-') 00360 longName++; 00361 } 00362 } else 00363 toggle = ""; 00364 (void) stpcpy(stpcpy(stpcpy(stpcpy(left, " "), dash), toggle), longName); 00365 } 00366 #undef prtlong 00367 00368 if (argDescrip) { 00369 char * le = left + strlen(left); 00370 00371 if (F_ISSET(opt, OPTIONAL)) 00372 *le++ = '['; 00373 00374 /* Choose type of output */ 00375 if (F_ISSET(opt, SHOW_DEFAULT)) { 00376 defs = singleOptionDefaultValue(lineLength, opt, translation_domain); 00377 if (defs) { 00378 char * t = malloc((help ? strlen(help) : 0) + 00379 strlen(defs) + sizeof(" ")); 00380 if (t) { 00381 char * te = t; 00382 if (help) 00383 te = stpcpy(te, help); 00384 *te++ = ' '; 00385 strcpy(te, defs); 00386 defs = _free(defs); 00387 defs = t; 00388 } 00389 } 00390 } 00391 00392 if (opt->argDescrip == NULL) { 00393 switch (poptArgType(opt)) { 00394 case POPT_ARG_NONE: 00395 break; 00396 case POPT_ARG_VAL: 00397 #ifdef NOTNOW /* XXX pug ugly nerdy output */ 00398 { long aLong = opt->val; 00399 int ops = F_ISSET(opt, LOGICALOPS); 00400 int negate = F_ISSET(opt, NOT); 00401 00402 /* Don't bother displaying typical values */ 00403 if (!ops && (aLong == 0L || aLong == 1L || aLong == -1L)) 00404 break; 00405 *le++ = '['; 00406 switch (ops) { 00407 case POPT_ARGFLAG_OR: 00408 *le++ = '|'; 00409 /*@innerbreak@*/ break; 00410 case POPT_ARGFLAG_AND: 00411 *le++ = '&'; 00412 /*@innerbreak@*/ break; 00413 case POPT_ARGFLAG_XOR: 00414 *le++ = '^'; 00415 /*@innerbreak@*/ break; 00416 default: 00417 /*@innerbreak@*/ break; 00418 } 00419 *le++ = (opt->longName != NULL ? '=' : ' '); 00420 if (negate) *le++ = '~'; 00421 /*@-formatconst@*/ 00422 le += sprintf(le, (ops ? "0x%lx" : "%ld"), aLong); 00423 /*@=formatconst@*/ 00424 *le++ = ']'; 00425 } 00426 #endif 00427 break; 00428 case POPT_ARG_INT: 00429 case POPT_ARG_SHORT: 00430 case POPT_ARG_LONG: 00431 case POPT_ARG_LONGLONG: 00432 case POPT_ARG_FLOAT: 00433 case POPT_ARG_DOUBLE: 00434 case POPT_ARG_STRING: 00435 *le++ = (opt->longName != NULL ? '=' : ' '); 00436 le = stpcpy(le, argDescrip); 00437 break; 00438 default: 00439 break; 00440 } 00441 } else { 00442 char *leo; 00443 00444 /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */ 00445 if (!strchr(" =(", argDescrip[0])) 00446 *le++ = ((poptArgType(opt) == POPT_ARG_MAINCALL) ? ' ' : 00447 (poptArgType(opt) == POPT_ARG_ARGV) ? ' ' : '='); 00448 le = stpcpy(leo = le, argDescrip); 00449 00450 /* Adjust for (possible) wide characters. */ 00451 displaypad = (int)((le - leo) - stringDisplayWidth(argDescrip)); 00452 } 00453 if (F_ISSET(opt, OPTIONAL)) 00454 *le++ = ']'; 00455 *le = '\0'; 00456 } 00457 00458 if (help) 00459 xx = POPT_fprintf(fp," %-*s ", (int)(maxLeftCol+displaypad), left); 00460 else { 00461 xx = POPT_fprintf(fp," %s\n", left); 00462 goto out; 00463 } 00464 00465 left = _free(left); 00466 if (defs) 00467 help = defs; 00468 00469 helpLength = strlen(help); 00470 while (helpLength > lineLength) { 00471 const char * ch; 00472 char format[16]; 00473 00474 ch = help + lineLength - 1; 00475 while (ch > help && !_isspaceptr(ch)) 00476 ch = POPT_prev_char(ch); 00477 if (ch == help) break; /* give up */ 00478 while (ch > (help + 1) && _isspaceptr(ch)) 00479 ch = POPT_prev_char (ch); 00480 ch = POPT_next_char(ch); 00481 00482 /* 00483 * XXX strdup is necessary to add NUL terminator so that an unknown 00484 * no. of (possible) multi-byte characters can be displayed. 00485 */ 00486 { char * fmthelp = xstrdup(help); 00487 if (fmthelp) { 00488 fmthelp[ch - help] = '\0'; 00489 sprintf(format, "%%s\n%%%ds", (int) indentLength); 00490 /*@-formatconst@*/ 00491 xx = POPT_fprintf(fp, format, fmthelp, " "); 00492 /*@=formatconst@*/ 00493 free(fmthelp); 00494 } 00495 } 00496 00497 help = ch; 00498 while (_isspaceptr(help) && *help) 00499 help = POPT_next_char(help); 00500 helpLength = strlen(help); 00501 } 00502 00503 if (helpLength) fprintf(fp, "%s\n", help); 00504 help = NULL; 00505 00506 out: 00507 /*@-dependenttrans@*/ 00508 defs = _free(defs); 00509 /*@=dependenttrans@*/ 00510 left = _free(left); 00511 } 00512 00519 static size_t maxArgWidth(const struct poptOption * opt, 00520 /*@null@*/ const char * translation_domain) 00521 /*@*/ 00522 { 00523 size_t max = 0; 00524 size_t len = 0; 00525 const char * argDescrip; 00526 00527 if (opt != NULL) 00528 while (opt->longName || opt->shortName || opt->arg) { 00529 if (poptArgType(opt) == POPT_ARG_INCLUDE_TABLE) { 00530 if (opt->arg) /* XXX program error */ 00531 len = maxArgWidth(opt->arg, translation_domain); 00532 if (len > max) max = len; 00533 } else if (!F_ISSET(opt, DOC_HIDDEN)) { 00534 len = sizeof(" ")-1; 00535 /* XXX --long always padded for alignment with/without "-X, ". */ 00536 len += sizeof("-X, ")-1; 00537 if (opt->longName) { 00538 len += (F_ISSET(opt, ONEDASH) ? sizeof("-") : sizeof("--")) - 1; 00539 len += strlen(opt->longName); 00540 } 00541 00542 argDescrip = getArgDescrip(opt, translation_domain); 00543 00544 if (argDescrip) { 00545 00546 /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */ 00547 if (!strchr(" =(", argDescrip[0])) len += sizeof("=")-1; 00548 00549 /* Adjust for (possible) wide characters. */ 00550 len += stringDisplayWidth(argDescrip); 00551 } 00552 00553 if (F_ISSET(opt, OPTIONAL)) len += sizeof("[]")-1; 00554 if (len > max) max = len; 00555 } 00556 opt++; 00557 } 00558 00559 return max; 00560 } 00561 00570 static void itemHelp(FILE * fp, 00571 /*@null@*/ poptItem items, int nitems, 00572 columns_t columns, 00573 /*@null@*/ const char * translation_domain) 00574 /*@globals fileSystem @*/ 00575 /*@modifies fp, fileSystem @*/ 00576 { 00577 poptItem item; 00578 int i; 00579 00580 if (items != NULL) 00581 for (i = 0, item = items; i < nitems; i++, item++) { 00582 const struct poptOption * opt; 00583 opt = &item->option; 00584 if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN)) 00585 singleOptionHelp(fp, columns, opt, translation_domain); 00586 } 00587 } 00588 00597 static void singleTableHelp(poptContext con, FILE * fp, 00598 /*@null@*/ const struct poptOption * table, 00599 columns_t columns, 00600 /*@null@*/ const char * translation_domain) 00601 /*@globals fileSystem @*/ 00602 /*@modifies fp, columns->cur, fileSystem @*/ 00603 { 00604 const struct poptOption * opt; 00605 const char *sub_transdom; 00606 int xx; 00607 00608 if (table == poptAliasOptions) { 00609 itemHelp(fp, con->aliases, con->numAliases, columns, NULL); 00610 itemHelp(fp, con->execs, con->numExecs, columns, NULL); 00611 return; 00612 } 00613 00614 if (table != NULL) 00615 for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) { 00616 if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN)) 00617 singleOptionHelp(fp, columns, opt, translation_domain); 00618 } 00619 00620 if (table != NULL) 00621 for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) { 00622 if (poptArgType(opt) != POPT_ARG_INCLUDE_TABLE) 00623 continue; 00624 sub_transdom = getTableTranslationDomain(opt->arg); 00625 if (sub_transdom == NULL) 00626 sub_transdom = translation_domain; 00627 00628 /* If no popt aliases/execs, skip poptAliasOption processing. */ 00629 if (opt->arg == poptAliasOptions && !(con->numAliases || con->numExecs)) 00630 continue; 00631 if (opt->descrip) 00632 xx = POPT_fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip)); 00633 00634 singleTableHelp(con, fp, opt->arg, columns, sub_transdom); 00635 } 00636 } 00637 00642 static size_t showHelpIntro(poptContext con, FILE * fp) 00643 /*@globals fileSystem @*/ 00644 /*@modifies fp, fileSystem @*/ 00645 { 00646 size_t len = (size_t)6; 00647 int xx; 00648 00649 xx = POPT_fprintf(fp, POPT_("Usage:")); 00650 if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) { 00651 struct optionStackEntry * os = con->optionStack; 00652 const char * fn = (os->argv ? os->argv[0] : NULL); 00653 if (fn == NULL) return len; 00654 if (strchr(fn, '/')) fn = strrchr(fn, '/') + 1; 00655 /* XXX POPT_fprintf not needed for argv[0] display. */ 00656 fprintf(fp, " %s", fn); 00657 len += strlen(fn) + 1; 00658 } 00659 00660 return len; 00661 } 00662 00663 void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags)) 00664 { 00665 columns_t columns = calloc((size_t)1, sizeof(*columns)); 00666 int xx; 00667 00668 (void) showHelpIntro(con, fp); 00669 if (con->otherHelp) 00670 xx = POPT_fprintf(fp, " %s\n", con->otherHelp); 00671 else 00672 xx = POPT_fprintf(fp, " %s\n", POPT_("[OPTION...]")); 00673 00674 if (columns) { 00675 columns->cur = maxArgWidth(con->options, NULL); 00676 columns->max = maxColumnWidth(fp); 00677 singleTableHelp(con, fp, con->options, columns, NULL); 00678 free(columns); 00679 } 00680 } 00681 00689 static size_t singleOptionUsage(FILE * fp, columns_t columns, 00690 const struct poptOption * opt, 00691 /*@null@*/ const char *translation_domain) 00692 /*@globals fileSystem @*/ 00693 /*@modifies fp, columns->cur, fileSystem @*/ 00694 { 00695 size_t len = sizeof(" []")-1; 00696 const char * argDescrip = getArgDescrip(opt, translation_domain); 00697 /* Display shortName iff printable non-space. */ 00698 int prtshort = (int)(isprint((int)opt->shortName) && opt->shortName != ' '); 00699 00700 #define prtlong (opt->longName != NULL) /* XXX splint needs a clue */ 00701 if (!(prtshort || prtlong)) 00702 return columns->cur; 00703 00704 len = sizeof(" []")-1; 00705 if (prtshort) 00706 len += sizeof("-c")-1; 00707 if (prtlong) { 00708 if (prtshort) len += sizeof("|")-1; 00709 len += (F_ISSET(opt, ONEDASH) ? sizeof("-") : sizeof("--")) - 1; 00710 len += strlen(opt->longName); 00711 } 00712 00713 if (argDescrip) { 00714 00715 /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */ 00716 if (!strchr(" =(", argDescrip[0])) len += sizeof("=")-1; 00717 00718 /* Adjust for (possible) wide characters. */ 00719 len += stringDisplayWidth(argDescrip); 00720 } 00721 00722 if ((columns->cur + len) > columns->max) { 00723 fprintf(fp, "\n "); 00724 columns->cur = (size_t)7; 00725 } 00726 00727 fprintf(fp, " ["); 00728 if (prtshort) 00729 fprintf(fp, "-%c", opt->shortName); 00730 if (prtlong) 00731 fprintf(fp, "%s%s%s", 00732 (prtshort ? "|" : ""), 00733 (F_ISSET(opt, ONEDASH) ? "-" : "--"), 00734 opt->longName); 00735 #undef prtlong 00736 00737 if (argDescrip) { 00738 /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */ 00739 if (!strchr(" =(", argDescrip[0])) fprintf(fp, "="); 00740 fprintf(fp, "%s", argDescrip); 00741 } 00742 fprintf(fp, "]"); 00743 00744 return columns->cur + len + 1; 00745 } 00746 00755 static size_t itemUsage(FILE * fp, columns_t columns, 00756 /*@null@*/ poptItem item, int nitems, 00757 /*@null@*/ const char * translation_domain) 00758 /*@globals fileSystem @*/ 00759 /*@modifies fp, columns->cur, fileSystem @*/ 00760 { 00761 int i; 00762 00763 if (item != NULL) 00764 for (i = 0; i < nitems; i++, item++) { 00765 const struct poptOption * opt; 00766 opt = &item->option; 00767 if (poptArgType(opt) == POPT_ARG_INTL_DOMAIN) { 00768 translation_domain = (const char *)opt->arg; 00769 } else 00770 if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN)) { 00771 columns->cur = singleOptionUsage(fp, columns, opt, translation_domain); 00772 } 00773 } 00774 00775 return columns->cur; 00776 } 00777 00781 typedef struct poptDone_s { 00782 int nopts; 00783 int maxopts; 00784 /*@null@*/ 00785 const void ** opts; 00786 } * poptDone; 00787 00798 static size_t singleTableUsage(poptContext con, FILE * fp, columns_t columns, 00799 /*@null@*/ const struct poptOption * opt, 00800 /*@null@*/ const char * translation_domain, 00801 /*@null@*/ poptDone done) 00802 /*@globals fileSystem @*/ 00803 /*@modifies fp, columns->cur, done, fileSystem @*/ 00804 { 00805 if (opt != NULL) 00806 for (; (opt->longName || opt->shortName || opt->arg) ; opt++) { 00807 if (poptArgType(opt) == POPT_ARG_INTL_DOMAIN) { 00808 translation_domain = (const char *)opt->arg; 00809 } else 00810 if (poptArgType(opt) == POPT_ARG_INCLUDE_TABLE) { 00811 if (done) { 00812 int i = 0; 00813 if (done->opts != NULL) 00814 for (i = 0; i < done->nopts; i++) { 00815 const void * that = done->opts[i]; 00816 if (that == NULL || that != opt->arg) 00817 /*@innercontinue@*/ continue; 00818 /*@innerbreak@*/ break; 00819 } 00820 /* Skip if this table has already been processed. */ 00821 if (opt->arg == NULL || i < done->nopts) 00822 continue; 00823 if (done->opts != NULL && done->nopts < done->maxopts) 00824 done->opts[done->nopts++] = (const void *) opt->arg; 00825 } 00826 columns->cur = singleTableUsage(con, fp, columns, opt->arg, 00827 translation_domain, done); 00828 } else 00829 if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN)) { 00830 columns->cur = singleOptionUsage(fp, columns, opt, translation_domain); 00831 } 00832 } 00833 00834 return columns->cur; 00835 } 00836 00845 static size_t showShortOptions(const struct poptOption * opt, FILE * fp, 00846 /*@null@*/ char * str) 00847 /*@globals fileSystem @*/ 00848 /*@modifies str, *fp, fileSystem @*/ 00849 /*@requires maxRead(str) >= 0 @*/ 00850 { 00851 /* bufsize larger then the ascii set, lazy allocation on top level call. */ 00852 size_t nb = (size_t)300; 00853 char * s = (str != NULL ? str : calloc((size_t)1, nb)); 00854 size_t len = (size_t)0; 00855 00856 if (s == NULL) 00857 return 0; 00858 00859 if (opt != NULL) 00860 for (; (opt->longName || opt->shortName || opt->arg); opt++) { 00861 if (!F_ISSET(opt, DOC_HIDDEN) && opt->shortName && !poptArgType(opt)) 00862 { 00863 /* Display shortName iff unique printable non-space. */ 00864 if (!strchr(s, opt->shortName) && isprint((int)opt->shortName) 00865 && opt->shortName != ' ') 00866 s[strlen(s)] = opt->shortName; 00867 } else if (poptArgType(opt) == POPT_ARG_INCLUDE_TABLE) 00868 if (opt->arg) /* XXX program error */ 00869 len = showShortOptions(opt->arg, fp, s); 00870 } 00871 00872 /* On return to top level, print the short options, return print length. */ 00873 if (s != str && *s != '\0') { 00874 fprintf(fp, " [-%s]", s); 00875 len = strlen(s) + sizeof(" [-]")-1; 00876 } 00877 /*@-temptrans@*/ /* LCL: local s, not str arg, is being freed. */ 00878 if (s != str) 00879 free(s); 00880 /*@=temptrans@*/ 00881 return len; 00882 } 00883 00884 void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags)) 00885 { 00886 columns_t columns = calloc((size_t)1, sizeof(*columns)); 00887 struct poptDone_s done_buf; 00888 poptDone done = &done_buf; 00889 00890 memset(done, 0, sizeof(*done)); 00891 done->nopts = 0; 00892 done->maxopts = 64; 00893 if (columns) { 00894 columns->cur = done->maxopts * sizeof(*done->opts); 00895 columns->max = maxColumnWidth(fp); 00896 done->opts = calloc((size_t)1, columns->cur); 00897 /*@-keeptrans@*/ 00898 if (done->opts != NULL) 00899 done->opts[done->nopts++] = (const void *) con->options; 00900 /*@=keeptrans@*/ 00901 00902 columns->cur = showHelpIntro(con, fp); 00903 columns->cur += showShortOptions(con->options, fp, NULL); 00904 columns->cur = singleTableUsage(con, fp, columns, con->options, NULL, done); 00905 columns->cur = itemUsage(fp, columns, con->aliases, con->numAliases, NULL); 00906 columns->cur = itemUsage(fp, columns, con->execs, con->numExecs, NULL); 00907 00908 if (con->otherHelp) { 00909 columns->cur += strlen(con->otherHelp) + 1; 00910 if (columns->cur > columns->max) fprintf(fp, "\n "); 00911 fprintf(fp, " %s", con->otherHelp); 00912 } 00913 00914 fprintf(fp, "\n"); 00915 if (done->opts != NULL) 00916 free(done->opts); 00917 free(columns); 00918 } 00919 } 00920 00921 void poptSetOtherOptionHelp(poptContext con, const char * text) 00922 { 00923 con->otherHelp = _free(con->otherHelp); 00924 con->otherHelp = xstrdup(text); 00925 }