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 (con == NULL) return; 00609 00610 if (table == poptAliasOptions) { 00611 itemHelp(fp, con->aliases, con->numAliases, columns, NULL); 00612 itemHelp(fp, con->execs, con->numExecs, columns, NULL); 00613 return; 00614 } 00615 00616 if (table != NULL) 00617 for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) { 00618 if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN)) 00619 singleOptionHelp(fp, columns, opt, translation_domain); 00620 } 00621 00622 if (table != NULL) 00623 for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) { 00624 if (poptArgType(opt) != POPT_ARG_INCLUDE_TABLE) 00625 continue; 00626 sub_transdom = getTableTranslationDomain(opt->arg); 00627 if (sub_transdom == NULL) 00628 sub_transdom = translation_domain; 00629 00630 /* If no popt aliases/execs, skip poptAliasOption processing. */ 00631 if (opt->arg == poptAliasOptions && !(con->numAliases || con->numExecs)) 00632 continue; 00633 if (opt->descrip) 00634 xx = POPT_fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip)); 00635 00636 singleTableHelp(con, fp, opt->arg, columns, sub_transdom); 00637 } 00638 } 00639 00644 static size_t showHelpIntro(poptContext con, FILE * fp) 00645 /*@globals fileSystem @*/ 00646 /*@modifies fp, fileSystem @*/ 00647 { 00648 size_t len = (size_t)6; 00649 int xx; 00650 00651 xx = POPT_fprintf(fp, POPT_("Usage:")); 00652 if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) { 00653 struct optionStackEntry * os = con->optionStack; 00654 const char * fn = (os->argv ? os->argv[0] : NULL); 00655 if (fn == NULL) return len; 00656 if (strchr(fn, '/')) fn = strrchr(fn, '/') + 1; 00657 /* XXX POPT_fprintf not needed for argv[0] display. */ 00658 fprintf(fp, " %s", fn); 00659 len += strlen(fn) + 1; 00660 } 00661 00662 return len; 00663 } 00664 00665 void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags)) 00666 { 00667 columns_t columns = calloc((size_t)1, sizeof(*columns)); 00668 int xx; 00669 00670 if (con == NULL) return; 00671 00672 (void) showHelpIntro(con, fp); 00673 if (con->otherHelp) 00674 xx = POPT_fprintf(fp, " %s\n", con->otherHelp); 00675 else 00676 xx = POPT_fprintf(fp, " %s\n", POPT_("[OPTION...]")); 00677 00678 if (columns) { 00679 columns->cur = maxArgWidth(con->options, NULL); 00680 columns->max = maxColumnWidth(fp); 00681 singleTableHelp(con, fp, con->options, columns, NULL); 00682 free(columns); 00683 } 00684 } 00685 00693 static size_t singleOptionUsage(FILE * fp, columns_t columns, 00694 const struct poptOption * opt, 00695 /*@null@*/ const char *translation_domain) 00696 /*@globals fileSystem @*/ 00697 /*@modifies fp, columns->cur, fileSystem @*/ 00698 { 00699 size_t len = sizeof(" []")-1; 00700 const char * argDescrip = getArgDescrip(opt, translation_domain); 00701 /* Display shortName iff printable non-space. */ 00702 int prtshort = (int)(isprint((int)opt->shortName) && opt->shortName != ' '); 00703 00704 #define prtlong (opt->longName != NULL) /* XXX splint needs a clue */ 00705 if (!(prtshort || prtlong)) 00706 return columns->cur; 00707 00708 len = sizeof(" []")-1; 00709 if (prtshort) 00710 len += sizeof("-c")-1; 00711 if (prtlong) { 00712 if (prtshort) len += sizeof("|")-1; 00713 len += (F_ISSET(opt, ONEDASH) ? sizeof("-") : sizeof("--")) - 1; 00714 len += strlen(opt->longName); 00715 } 00716 00717 if (argDescrip) { 00718 00719 /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */ 00720 if (!strchr(" =(", argDescrip[0])) len += sizeof("=")-1; 00721 00722 /* Adjust for (possible) wide characters. */ 00723 len += stringDisplayWidth(argDescrip); 00724 } 00725 00726 if ((columns->cur + len) > columns->max) { 00727 fprintf(fp, "\n "); 00728 columns->cur = (size_t)7; 00729 } 00730 00731 fprintf(fp, " ["); 00732 if (prtshort) 00733 fprintf(fp, "-%c", opt->shortName); 00734 if (prtlong) 00735 fprintf(fp, "%s%s%s", 00736 (prtshort ? "|" : ""), 00737 (F_ISSET(opt, ONEDASH) ? "-" : "--"), 00738 opt->longName); 00739 #undef prtlong 00740 00741 if (argDescrip) { 00742 /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */ 00743 if (!strchr(" =(", argDescrip[0])) fprintf(fp, "="); 00744 fprintf(fp, "%s", argDescrip); 00745 } 00746 fprintf(fp, "]"); 00747 00748 return columns->cur + len + 1; 00749 } 00750 00759 static size_t itemUsage(FILE * fp, columns_t columns, 00760 /*@null@*/ poptItem item, int nitems, 00761 /*@null@*/ const char * translation_domain) 00762 /*@globals fileSystem @*/ 00763 /*@modifies fp, columns->cur, fileSystem @*/ 00764 { 00765 int i; 00766 00767 if (item != NULL) 00768 for (i = 0; i < nitems; i++, item++) { 00769 const struct poptOption * opt; 00770 opt = &item->option; 00771 if (poptArgType(opt) == POPT_ARG_INTL_DOMAIN) { 00772 translation_domain = (const char *)opt->arg; 00773 } else 00774 if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN)) { 00775 columns->cur = singleOptionUsage(fp, columns, opt, translation_domain); 00776 } 00777 } 00778 00779 return columns->cur; 00780 } 00781 00785 typedef struct poptDone_s { 00786 int nopts; 00787 int maxopts; 00788 /*@null@*/ 00789 const void ** opts; 00790 } * poptDone; 00791 00802 static size_t singleTableUsage(poptContext con, FILE * fp, columns_t columns, 00803 /*@null@*/ const struct poptOption * opt, 00804 /*@null@*/ const char * translation_domain, 00805 /*@null@*/ poptDone done) 00806 /*@globals fileSystem @*/ 00807 /*@modifies fp, columns->cur, done, fileSystem @*/ 00808 { 00809 if (con != NULL && opt != NULL) 00810 for (; (opt->longName || opt->shortName || opt->arg) ; opt++) { 00811 if (poptArgType(opt) == POPT_ARG_INTL_DOMAIN) { 00812 translation_domain = (const char *)opt->arg; 00813 } else 00814 if (poptArgType(opt) == POPT_ARG_INCLUDE_TABLE) { 00815 if (done) { 00816 int i = 0; 00817 if (done->opts != NULL) 00818 for (i = 0; i < done->nopts; i++) { 00819 const void * that = done->opts[i]; 00820 if (that == NULL || that != opt->arg) 00821 /*@innercontinue@*/ continue; 00822 /*@innerbreak@*/ break; 00823 } 00824 /* Skip if this table has already been processed. */ 00825 if (opt->arg == NULL || i < done->nopts) 00826 continue; 00827 if (done->opts != NULL && done->nopts < done->maxopts) 00828 done->opts[done->nopts++] = (const void *) opt->arg; 00829 } 00830 columns->cur = singleTableUsage(con, fp, columns, opt->arg, 00831 translation_domain, done); 00832 } else 00833 if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN)) { 00834 columns->cur = singleOptionUsage(fp, columns, opt, translation_domain); 00835 } 00836 } 00837 00838 return columns->cur; 00839 } 00840 00849 static size_t showShortOptions(const struct poptOption * opt, FILE * fp, 00850 /*@null@*/ char * str) 00851 /*@globals fileSystem @*/ 00852 /*@modifies str, *fp, fileSystem @*/ 00853 /*@requires maxRead(str) >= 0 @*/ 00854 { 00855 /* bufsize larger then the ascii set, lazy allocation on top level call. */ 00856 size_t nb = (size_t)300; 00857 char * s = (str != NULL ? str : calloc((size_t)1, nb)); 00858 size_t len = (size_t)0; 00859 00860 if (s == NULL) 00861 return 0; 00862 00863 if (opt != NULL) 00864 for (; (opt->longName || opt->shortName || opt->arg); opt++) { 00865 if (!F_ISSET(opt, DOC_HIDDEN) && opt->shortName && !poptArgType(opt)) 00866 { 00867 /* Display shortName iff unique printable non-space. */ 00868 if (!strchr(s, opt->shortName) && isprint((int)opt->shortName) 00869 && opt->shortName != ' ') 00870 s[strlen(s)] = opt->shortName; 00871 } else if (poptArgType(opt) == POPT_ARG_INCLUDE_TABLE) 00872 if (opt->arg) /* XXX program error */ 00873 len = showShortOptions(opt->arg, fp, s); 00874 } 00875 00876 /* On return to top level, print the short options, return print length. */ 00877 if (s != str && *s != '\0') { 00878 fprintf(fp, " [-%s]", s); 00879 len = strlen(s) + sizeof(" [-]")-1; 00880 } 00881 /*@-temptrans@*/ /* LCL: local s, not str arg, is being freed. */ 00882 if (s != str) 00883 free(s); 00884 /*@=temptrans@*/ 00885 return len; 00886 } 00887 00888 void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags)) 00889 { 00890 columns_t columns = calloc((size_t)1, sizeof(*columns)); 00891 struct poptDone_s done_buf; 00892 poptDone done = &done_buf; 00893 00894 if (con == NULL) return; 00895 00896 memset(done, 0, sizeof(*done)); 00897 done->nopts = 0; 00898 done->maxopts = 64; 00899 if (columns) { 00900 columns->cur = done->maxopts * sizeof(*done->opts); 00901 columns->max = maxColumnWidth(fp); 00902 done->opts = calloc((size_t)1, columns->cur); 00903 /*@-keeptrans@*/ 00904 if (done->opts != NULL) 00905 done->opts[done->nopts++] = (const void *) con->options; 00906 /*@=keeptrans@*/ 00907 00908 columns->cur = showHelpIntro(con, fp); 00909 columns->cur += showShortOptions(con->options, fp, NULL); 00910 columns->cur = singleTableUsage(con, fp, columns, con->options, NULL, done); 00911 columns->cur = itemUsage(fp, columns, con->aliases, con->numAliases, NULL); 00912 columns->cur = itemUsage(fp, columns, con->execs, con->numExecs, NULL); 00913 00914 if (con->otherHelp) { 00915 columns->cur += strlen(con->otherHelp) + 1; 00916 if (columns->cur > columns->max) fprintf(fp, "\n "); 00917 fprintf(fp, " %s", con->otherHelp); 00918 } 00919 00920 fprintf(fp, "\n"); 00921 if (done->opts != NULL) 00922 free(done->opts); 00923 free(columns); 00924 } 00925 } 00926 00927 void poptSetOtherOptionHelp(poptContext con, const char * text) 00928 { 00929 if (con == NULL) return; 00930 00931 con->otherHelp = _free(con->otherHelp); 00932 con->otherHelp = xstrdup(text); 00933 }