popt 1.13
|
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 00024 00025 #include "poptint.h" 00026 00027 /*@access poptContext@*/ 00028 00037 /*@exits@*/ 00038 static void displayArgs(poptContext con, 00039 /*@unused@*/ enum poptCallbackReason foo, 00040 struct poptOption * key, 00041 /*@unused@*/ const char * arg, /*@unused@*/ void * data) 00042 /*@globals fileSystem@*/ 00043 /*@modifies con, fileSystem@*/ 00044 { 00045 if (key->shortName == '?') 00046 poptPrintHelp(con, stdout, 0); 00047 else 00048 poptPrintUsage(con, stdout, 0); 00049 00050 /*@i@*/ con = poptFreeContext(con); /* XXX keep valgrind happy */ 00051 exit(0); 00052 } 00053 00054 #ifdef NOTYET 00055 /*@unchecked@*/ 00056 static int show_option_defaults = 0; 00057 #endif 00058 00062 /*@observer@*/ /*@unchecked@*/ 00063 struct poptOption poptAliasOptions[] = { 00064 POPT_TABLEEND 00065 }; 00066 00070 /*@-castfcnptr@*/ 00071 /*@observer@*/ /*@unchecked@*/ 00072 struct poptOption poptHelpOptions[] = { 00073 { NULL, '\0', POPT_ARG_CALLBACK, (void *)displayArgs, 0, NULL, NULL }, 00074 { "help", '?', 0, NULL, (int)'?', N_("Show this help message"), NULL }, 00075 { "usage", '\0', 0, NULL, (int)'u', N_("Display brief usage message"), NULL }, 00076 POPT_TABLEEND 00077 } ; 00078 00079 /*@observer@*/ /*@unchecked@*/ 00080 static struct poptOption poptHelpOptions2[] = { 00081 /*@-readonlytrans@*/ 00082 { NULL, '\0', POPT_ARG_INTL_DOMAIN, PACKAGE, 0, NULL, NULL}, 00083 /*@=readonlytrans@*/ 00084 { NULL, '\0', POPT_ARG_CALLBACK, (void *)displayArgs, 0, NULL, NULL }, 00085 { "help", '?', 0, NULL, (int)'?', N_("Show this help message"), NULL }, 00086 { "usage", '\0', 0, NULL, (int)'u', N_("Display brief usage message"), NULL }, 00087 #ifdef NOTYET 00088 { "defaults", '\0', POPT_ARG_NONE, &show_option_defaults, 0, 00089 N_("Display option defaults in message"), NULL }, 00090 #endif 00091 POPT_TABLEEND 00092 } ; 00093 00094 /*@observer@*/ /*@unchecked@*/ 00095 struct poptOption * poptHelpOptionsI18N = poptHelpOptions2; 00096 /*@=castfcnptr@*/ 00097 00098 #define _POPTHELP_MAXLINE ((size_t)79) 00099 00100 typedef struct columns_s { 00101 size_t cur; 00102 size_t max; 00103 } * columns_t; 00104 00110 static size_t maxColumnWidth(FILE *fp) 00111 /*@*/ 00112 { 00113 size_t maxcols = _POPTHELP_MAXLINE; 00114 #if defined(TIOCGWINSZ) 00115 struct winsize ws; 00116 int fdno = fileno(fp ? fp : stdout); 00117 00118 memset(&ws, 0, sizeof(ws)); 00119 if (fdno >= 0 && !ioctl(fdno, TIOCGWINSZ, &ws) 00120 && (size_t)ws.ws_col > maxcols && ws.ws_col < 256) 00121 maxcols = ws.ws_col - 1; 00122 #endif 00123 return maxcols; 00124 } 00125 00129 /*@observer@*/ /*@null@*/ static const char * 00130 getTableTranslationDomain(/*@null@*/ const struct poptOption *table) 00131 /*@*/ 00132 { 00133 const struct poptOption *opt; 00134 00135 if (table != NULL) 00136 for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) { 00137 if (opt->argInfo == POPT_ARG_INTL_DOMAIN) 00138 return opt->arg; 00139 } 00140 return NULL; 00141 } 00142 00147 /*@observer@*/ /*@null@*/ static const char * 00148 getArgDescrip(const struct poptOption * opt, 00149 /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */ 00150 /*@null@*/ const char * translation_domain) 00151 /*@=paramuse@*/ 00152 /*@*/ 00153 { 00154 if (!(opt->argInfo & POPT_ARG_MASK)) return NULL; 00155 00156 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_MAINCALL) 00157 return opt->argDescrip; 00158 00159 if (opt->argDescrip) { 00160 /* Some strings need popt library, not application, i18n domain. */ 00161 if (opt == (poptHelpOptions + 1) 00162 || opt == (poptHelpOptions + 2) 00163 || !strcmp(opt->argDescrip,N_("Help options:")) 00164 || !strcmp(opt->argDescrip,N_("Options implemented via popt alias/exec:"))) 00165 return POPT_(opt->argDescrip); 00166 00167 /* Use the application i18n domain. */ 00168 return D_(translation_domain, opt->argDescrip); 00169 } 00170 00171 switch (opt->argInfo & POPT_ARG_MASK) { 00172 case POPT_ARG_NONE: return POPT_("NONE"); 00173 #ifdef DYING 00174 case POPT_ARG_VAL: return POPT_("VAL"); 00175 #else 00176 case POPT_ARG_VAL: return NULL; 00177 #endif 00178 case POPT_ARG_INT: return POPT_("INT"); 00179 case POPT_ARG_LONG: return POPT_("LONG"); 00180 case POPT_ARG_STRING: return POPT_("STRING"); 00181 case POPT_ARG_FLOAT: return POPT_("FLOAT"); 00182 case POPT_ARG_DOUBLE: return POPT_("DOUBLE"); 00183 case POPT_ARG_MAINCALL: return NULL; 00184 default: return POPT_("ARG"); 00185 } 00186 } 00187 00195 static /*@only@*/ /*@null@*/ char * 00196 singleOptionDefaultValue(size_t lineLength, 00197 const struct poptOption * opt, 00198 /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */ 00199 /*@null@*/ const char * translation_domain) 00200 /*@=paramuse@*/ 00201 /*@*/ 00202 { 00203 const char * defstr = D_(translation_domain, "default"); 00204 char * le = malloc(4*lineLength + 1); 00205 char * l = le; 00206 00207 if (le == NULL) return NULL; /* XXX can't happen */ 00208 *le = '\0'; 00209 *le++ = '('; 00210 strcpy(le, defstr); le += strlen(le); 00211 *le++ = ':'; 00212 *le++ = ' '; 00213 if (opt->arg) /* XXX programmer error */ 00214 switch (opt->argInfo & POPT_ARG_MASK) { 00215 case POPT_ARG_VAL: 00216 case POPT_ARG_INT: 00217 { long aLong = *((int *)opt->arg); 00218 le += sprintf(le, "%ld", aLong); 00219 } break; 00220 case POPT_ARG_LONG: 00221 { long aLong = *((long *)opt->arg); 00222 le += sprintf(le, "%ld", aLong); 00223 } break; 00224 case POPT_ARG_FLOAT: 00225 { double aDouble = *((float *)opt->arg); 00226 le += sprintf(le, "%g", aDouble); 00227 } break; 00228 case POPT_ARG_DOUBLE: 00229 { double aDouble = *((double *)opt->arg); 00230 le += sprintf(le, "%g", aDouble); 00231 } break; 00232 case POPT_ARG_MAINCALL: 00233 le += sprintf(le, "%p", opt->arg); 00234 break; 00235 case POPT_ARG_STRING: 00236 { const char * s = *(const char **)opt->arg; 00237 if (s == NULL) { 00238 strcpy(le, "null"); le += strlen(le); 00239 } else { 00240 size_t slen = 4*lineLength - (le - l) - sizeof("\"...\")"); 00241 *le++ = '"'; 00242 strncpy(le, s, slen); le[slen] = '\0'; le += strlen(le); 00243 if (slen < strlen(s)) { 00244 strcpy(le, "..."); le += strlen(le); 00245 } 00246 *le++ = '"'; 00247 } 00248 } break; 00249 case POPT_ARG_NONE: 00250 default: 00251 l = _free(l); 00252 return NULL; 00253 /*@notreached@*/ break; 00254 } 00255 *le++ = ')'; 00256 *le = '\0'; 00257 00258 return l; 00259 } 00260 00268 static void singleOptionHelp(FILE * fp, columns_t columns, 00269 const struct poptOption * opt, 00270 /*@null@*/ const char * translation_domain) 00271 /*@globals fileSystem @*/ 00272 /*@modifies fp, fileSystem @*/ 00273 { 00274 size_t maxLeftCol = columns->cur; 00275 size_t indentLength = maxLeftCol + 5; 00276 size_t lineLength = columns->max - indentLength; 00277 const char * help = D_(translation_domain, opt->descrip); 00278 const char * argDescrip = getArgDescrip(opt, translation_domain); 00279 size_t helpLength; 00280 char * defs = NULL; 00281 char * left; 00282 size_t nb = maxLeftCol + 1; 00283 int displaypad = 0; 00284 00285 /* Make sure there's more than enough room in target buffer. */ 00286 if (opt->longName) nb += strlen(opt->longName); 00287 if (argDescrip) nb += strlen(argDescrip); 00288 00289 left = malloc(nb); 00290 if (left == NULL) return; /* XXX can't happen */ 00291 left[0] = '\0'; 00292 left[maxLeftCol] = '\0'; 00293 00294 if (opt->longName && opt->shortName) 00295 sprintf(left, "-%c, %s%s", opt->shortName, 00296 ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"), 00297 opt->longName); 00298 else if (opt->shortName != '\0') 00299 sprintf(left, "-%c", opt->shortName); 00300 else if (opt->longName) 00301 sprintf(left, "%s%s", 00302 ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_MAINCALL ? "" : 00303 ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--")), 00304 opt->longName); 00305 if (!*left) goto out; 00306 00307 if (argDescrip) { 00308 char * le = left + strlen(left); 00309 00310 if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) 00311 *le++ = '['; 00312 00313 /* Choose type of output */ 00314 if (opt->argInfo & POPT_ARGFLAG_SHOW_DEFAULT) { 00315 defs = singleOptionDefaultValue(lineLength, opt, translation_domain); 00316 if (defs) { 00317 char * t = malloc((help ? strlen(help) : 0) + 00318 strlen(defs) + sizeof(" ")); 00319 if (t) { 00320 char * te = t; 00321 *te = '\0'; 00322 if (help) { 00323 strcpy(te, help); te += strlen(te); 00324 } 00325 *te++ = ' '; 00326 strcpy(te, defs); 00327 defs = _free(defs); 00328 } 00329 defs = t; 00330 } 00331 } 00332 00333 if (opt->argDescrip == NULL) { 00334 switch (opt->argInfo & POPT_ARG_MASK) { 00335 case POPT_ARG_NONE: 00336 break; 00337 case POPT_ARG_VAL: 00338 #ifdef NOTNOW /* XXX pug ugly nerdy output */ 00339 { long aLong = opt->val; 00340 int ops = (opt->argInfo & POPT_ARGFLAG_LOGICALOPS); 00341 int negate = (opt->argInfo & POPT_ARGFLAG_NOT); 00342 00343 /* Don't bother displaying typical values */ 00344 if (!ops && (aLong == 0L || aLong == 1L || aLong == -1L)) 00345 break; 00346 *le++ = '['; 00347 switch (ops) { 00348 case POPT_ARGFLAG_OR: 00349 *le++ = '|'; 00350 /*@innerbreak@*/ break; 00351 case POPT_ARGFLAG_AND: 00352 *le++ = '&'; 00353 /*@innerbreak@*/ break; 00354 case POPT_ARGFLAG_XOR: 00355 *le++ = '^'; 00356 /*@innerbreak@*/ break; 00357 default: 00358 /*@innerbreak@*/ break; 00359 } 00360 *le++ = (opt->longName != NULL ? '=' : ' '); 00361 if (negate) *le++ = '~'; 00362 /*@-formatconst@*/ 00363 le += sprintf(le, (ops ? "0x%lx" : "%ld"), aLong); 00364 /*@=formatconst@*/ 00365 *le++ = ']'; 00366 } 00367 #endif 00368 break; 00369 case POPT_ARG_INT: 00370 case POPT_ARG_LONG: 00371 case POPT_ARG_FLOAT: 00372 case POPT_ARG_DOUBLE: 00373 case POPT_ARG_STRING: 00374 *le++ = (opt->longName != NULL ? '=' : ' '); 00375 strcpy(le, argDescrip); le += strlen(le); 00376 break; 00377 default: 00378 break; 00379 } 00380 } else { 00381 size_t lelen; 00382 00383 *le++ = ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_MAINCALL) 00384 ? ' ' : '='; 00385 strcpy(le, argDescrip); 00386 lelen = strlen(le); 00387 le += lelen; 00388 00389 #ifdef POPT_WCHAR_HACK 00390 { const char * scopy = argDescrip; 00391 mbstate_t t; 00392 size_t n; 00393 00394 memset ((void *)&t, 0, sizeof (t)); /* In initial state. */ 00395 /* Determine number of characters. */ 00396 n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t); 00397 00398 displaypad = (int) (lelen-n); 00399 } 00400 #endif 00401 } 00402 if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) 00403 *le++ = ']'; 00404 *le = '\0'; 00405 } 00406 00407 if (help) 00408 fprintf(fp," %-*s ", (int)(maxLeftCol+displaypad), left); 00409 else { 00410 fprintf(fp," %s\n", left); 00411 goto out; 00412 } 00413 00414 left = _free(left); 00415 if (defs) { 00416 help = defs; 00417 } 00418 00419 helpLength = strlen(help); 00420 while (helpLength > lineLength) { 00421 const char * ch; 00422 char format[16]; 00423 00424 ch = help + lineLength - 1; 00425 while (ch > help && !_isspaceptr(ch)) 00426 ch = POPT_prev_char (ch); 00427 if (ch == help) break; /* give up */ 00428 while (ch > (help + 1) && _isspaceptr(ch)) 00429 ch = POPT_prev_char (ch); 00430 ch = POPT_next_char(ch); 00431 00432 sprintf(format, "%%.%ds\n%%%ds", (int) (ch - help), (int) indentLength); 00433 /*@-formatconst@*/ 00434 fprintf(fp, format, help, " "); 00435 /*@=formatconst@*/ 00436 help = ch; 00437 while (_isspaceptr(help) && *help) 00438 help = POPT_next_char(help); 00439 helpLength = strlen(help); 00440 } 00441 00442 if (helpLength) fprintf(fp, "%s\n", help); 00443 help = NULL; 00444 00445 out: 00446 /*@-dependenttrans@*/ 00447 defs = _free(defs); 00448 /*@=dependenttrans@*/ 00449 left = _free(left); 00450 } 00451 00458 static size_t maxArgWidth(const struct poptOption * opt, 00459 /*@null@*/ const char * translation_domain) 00460 /*@*/ 00461 { 00462 size_t max = 0; 00463 size_t len = 0; 00464 const char * s; 00465 00466 if (opt != NULL) 00467 while (opt->longName || opt->shortName || opt->arg) { 00468 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { 00469 if (opt->arg) /* XXX program error */ 00470 len = maxArgWidth(opt->arg, translation_domain); 00471 if (len > max) max = len; 00472 } else if (!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) { 00473 len = sizeof(" ")-1; 00474 if (opt->shortName != '\0') len += sizeof("-X")-1; 00475 if (opt->shortName != '\0' && opt->longName) len += sizeof(", ")-1; 00476 if (opt->longName) { 00477 len += ((opt->argInfo & POPT_ARGFLAG_ONEDASH) 00478 ? sizeof("-")-1 : sizeof("--")-1); 00479 len += strlen(opt->longName); 00480 } 00481 00482 s = getArgDescrip(opt, translation_domain); 00483 00484 #ifdef POPT_WCHAR_HACK 00485 /* XXX Calculate no. of display characters. */ 00486 if (s) { 00487 const char * scopy = s; 00488 mbstate_t t; 00489 size_t n; 00490 00491 memset ((void *)&t, 0, sizeof (t)); /* In initial state. */ 00492 /* Determine number of characters. */ 00493 n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t); 00494 len += sizeof("=")-1 + n; 00495 } 00496 #else 00497 if (s) 00498 len += sizeof("=")-1 + strlen(s); 00499 #endif 00500 00501 if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) len += sizeof("[]")-1; 00502 if (len > max) max = len; 00503 } 00504 00505 opt++; 00506 } 00507 00508 return max; 00509 } 00510 00519 static void itemHelp(FILE * fp, 00520 /*@null@*/ poptItem items, int nitems, 00521 columns_t columns, 00522 /*@null@*/ const char * translation_domain) 00523 /*@globals fileSystem @*/ 00524 /*@modifies fp, fileSystem @*/ 00525 { 00526 poptItem item; 00527 int i; 00528 00529 if (items != NULL) 00530 for (i = 0, item = items; i < nitems; i++, item++) { 00531 const struct poptOption * opt; 00532 opt = &item->option; 00533 if ((opt->longName || opt->shortName) && 00534 !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) 00535 singleOptionHelp(fp, columns, opt, translation_domain); 00536 } 00537 } 00538 00547 static void singleTableHelp(poptContext con, FILE * fp, 00548 /*@null@*/ const struct poptOption * table, 00549 columns_t columns, 00550 /*@null@*/ const char * translation_domain) 00551 /*@globals fileSystem @*/ 00552 /*@modifies fp, columns->cur, fileSystem @*/ 00553 { 00554 const struct poptOption * opt; 00555 const char *sub_transdom; 00556 00557 if (table == poptAliasOptions) { 00558 itemHelp(fp, con->aliases, con->numAliases, columns, NULL); 00559 itemHelp(fp, con->execs, con->numExecs, columns, NULL); 00560 return; 00561 } 00562 00563 if (table != NULL) 00564 for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) { 00565 if ((opt->longName || opt->shortName) && 00566 !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) 00567 singleOptionHelp(fp, columns, opt, translation_domain); 00568 } 00569 00570 if (table != NULL) 00571 for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) { 00572 if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_INCLUDE_TABLE) 00573 continue; 00574 sub_transdom = getTableTranslationDomain(opt->arg); 00575 if (sub_transdom == NULL) 00576 sub_transdom = translation_domain; 00577 00578 if (opt->descrip) 00579 fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip)); 00580 00581 singleTableHelp(con, fp, opt->arg, columns, sub_transdom); 00582 } 00583 } 00584 00589 static size_t showHelpIntro(poptContext con, FILE * fp) 00590 /*@globals fileSystem @*/ 00591 /*@modifies *fp, fileSystem @*/ 00592 { 00593 size_t len = (size_t)6; 00594 const char * fn; 00595 00596 fprintf(fp, POPT_("Usage:")); 00597 if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) { 00598 /*@-type@*/ /* LCL: wazzup? */ 00599 fn = con->optionStack->argv[0]; 00600 /*@=type@*/ 00601 if (fn == NULL) return len; 00602 if (strchr(fn, '/')) fn = strrchr(fn, '/') + 1; 00603 fprintf(fp, " %s", fn); 00604 len += strlen(fn) + 1; 00605 } 00606 00607 return len; 00608 } 00609 00610 void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ int flags) 00611 { 00612 columns_t columns = calloc(1, sizeof(*columns)); 00613 00614 (void) showHelpIntro(con, fp); 00615 if (con->otherHelp) 00616 fprintf(fp, " %s\n", con->otherHelp); 00617 else 00618 fprintf(fp, " %s\n", POPT_("[OPTION...]")); 00619 00620 if (columns) { 00621 columns->cur = maxArgWidth(con->options, NULL); 00622 columns->max = maxColumnWidth(fp); 00623 singleTableHelp(con, fp, con->options, columns, NULL); 00624 free(columns); 00625 } 00626 } 00627 00635 static size_t singleOptionUsage(FILE * fp, columns_t columns, 00636 const struct poptOption * opt, 00637 /*@null@*/ const char *translation_domain) 00638 /*@globals fileSystem @*/ 00639 /*@modifies fp, columns->cur, fileSystem @*/ 00640 { 00641 size_t len = (size_t)4; 00642 char shortStr[2] = { '\0', '\0' }; 00643 const char * item = shortStr; 00644 const char * argDescrip = getArgDescrip(opt, translation_domain); 00645 int bingo = 0; 00646 00647 if (opt->shortName != '\0' && opt->longName != NULL) { 00648 len += 2; 00649 if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++; 00650 len += strlen(opt->longName); 00651 bingo++; 00652 } else if (opt->shortName != '\0') { 00653 len++; 00654 shortStr[0] = opt->shortName; 00655 shortStr[1] = '\0'; 00656 bingo++; 00657 } else if (opt->longName) { 00658 len += strlen(opt->longName); 00659 if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++; 00660 item = opt->longName; 00661 bingo++; 00662 } 00663 00664 if (!bingo) return columns->cur; 00665 00666 #ifdef POPT_WCHAR_HACK 00667 /* XXX Calculate no. of display characters. */ 00668 if (argDescrip) { 00669 const char * scopy = argDescrip; 00670 mbstate_t t; 00671 size_t n; 00672 00673 memset ((void *)&t, 0, sizeof (t)); /* In initial state. */ 00674 /* Determine number of characters. */ 00675 n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t); 00676 len += sizeof("=")-1 + n; 00677 } 00678 #else 00679 if (argDescrip) 00680 len += sizeof("=")-1 + strlen(argDescrip); 00681 #endif 00682 00683 if ((columns->cur + len) > columns->max) { 00684 fprintf(fp, "\n "); 00685 columns->cur = (size_t)7; 00686 } 00687 00688 if (opt->longName && opt->shortName) { 00689 fprintf(fp, " [-%c|-%s%s%s%s]", 00690 opt->shortName, ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "" : "-"), 00691 opt->longName, 00692 (argDescrip ? " " : ""), 00693 (argDescrip ? argDescrip : "")); 00694 } else { 00695 fprintf(fp, " [-%s%s%s%s]", 00696 ((opt->shortName || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) ? "" : "-"), 00697 item, 00698 (argDescrip ? (opt->shortName != '\0' ? " " : "=") : ""), 00699 (argDescrip ? argDescrip : "")); 00700 } 00701 00702 return columns->cur + len + 1; 00703 } 00704 00713 static size_t itemUsage(FILE * fp, columns_t columns, 00714 /*@null@*/ poptItem item, int nitems, 00715 /*@null@*/ const char * translation_domain) 00716 /*@globals fileSystem @*/ 00717 /*@modifies fp, columns->cur, fileSystem @*/ 00718 { 00719 int i; 00720 00721 if (item != NULL) 00722 for (i = 0; i < nitems; i++, item++) { 00723 const struct poptOption * opt; 00724 opt = &item->option; 00725 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) { 00726 translation_domain = (const char *)opt->arg; 00727 } else if ((opt->longName || opt->shortName) && 00728 !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) { 00729 columns->cur = singleOptionUsage(fp, columns, opt, translation_domain); 00730 } 00731 } 00732 00733 return columns->cur; 00734 } 00735 00739 typedef struct poptDone_s { 00740 int nopts; 00741 int maxopts; 00742 /*@null@*/ 00743 const void ** opts; 00744 } * poptDone; 00745 00756 static size_t singleTableUsage(poptContext con, FILE * fp, columns_t columns, 00757 /*@null@*/ const struct poptOption * opt, 00758 /*@null@*/ const char * translation_domain, 00759 /*@null@*/ poptDone done) 00760 /*@globals fileSystem @*/ 00761 /*@modifies fp, columns->cur, done, fileSystem @*/ 00762 { 00763 if (opt != NULL) 00764 for (; (opt->longName || opt->shortName || opt->arg) ; opt++) { 00765 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) { 00766 translation_domain = (const char *)opt->arg; 00767 } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { 00768 if (done) { 00769 int i = done->nopts; 00770 if (done->opts != NULL) 00771 for (i = 0; i < done->nopts; i++) { 00772 const void * that = done->opts[i]; 00773 if (that == NULL || that != opt->arg) 00774 /*@innercontinue@*/ continue; 00775 /*@innerbreak@*/ break; 00776 } 00777 /* Skip if this table has already been processed. */ 00778 if (opt->arg == NULL || i < done->nopts) 00779 continue; 00780 if (done->opts != NULL && done->nopts < done->maxopts) 00781 done->opts[done->nopts++] = (const void *) opt->arg; 00782 } 00783 columns->cur = singleTableUsage(con, fp, columns, opt->arg, 00784 translation_domain, done); 00785 } else if ((opt->longName || opt->shortName) && 00786 !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) { 00787 columns->cur = singleOptionUsage(fp, columns, opt, translation_domain); 00788 } 00789 } 00790 00791 return columns->cur; 00792 } 00793 00802 static size_t showShortOptions(const struct poptOption * opt, FILE * fp, 00803 /*@null@*/ char * str) 00804 /*@globals fileSystem @*/ 00805 /*@modifies str, *fp, fileSystem @*/ 00806 /*@requires maxRead(str) >= 0 @*/ 00807 { 00808 /* bufsize larger then the ascii set, lazy allocation on top level call. */ 00809 size_t nb = (size_t)300; 00810 char * s = (str != NULL ? str : calloc(1, nb)); 00811 size_t len = (size_t)0; 00812 00813 if (s == NULL) 00814 return 0; 00815 00816 if (opt != NULL) 00817 for (; (opt->longName || opt->shortName || opt->arg); opt++) { 00818 if (opt->shortName && !(opt->argInfo & POPT_ARG_MASK)) 00819 s[strlen(s)] = opt->shortName; 00820 else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) 00821 if (opt->arg) /* XXX program error */ 00822 len = showShortOptions(opt->arg, fp, s); 00823 } 00824 00825 /* On return to top level, print the short options, return print length. */ 00826 if (s != str && *s != '\0') { 00827 fprintf(fp, " [-%s]", s); 00828 len = strlen(s) + sizeof(" [-]")-1; 00829 } 00830 /*@-temptrans@*/ /* LCL: local s, not str arg, is being freed. */ 00831 if (s != str) 00832 free(s); 00833 /*@=temptrans@*/ 00834 return len; 00835 } 00836 00837 void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ int flags) 00838 { 00839 columns_t columns = calloc(1, sizeof(*columns)); 00840 struct poptDone_s done_buf; 00841 poptDone done = &done_buf; 00842 00843 memset(done, 0, sizeof(*done)); 00844 done->nopts = 0; 00845 done->maxopts = 64; 00846 if (columns) { 00847 columns->cur = done->maxopts * sizeof(*done->opts); 00848 columns->max = maxColumnWidth(fp); 00849 done->opts = calloc(1, columns->cur); 00850 /*@-keeptrans@*/ 00851 if (done->opts != NULL) 00852 done->opts[done->nopts++] = (const void *) con->options; 00853 /*@=keeptrans@*/ 00854 00855 columns->cur = showHelpIntro(con, fp); 00856 columns->cur += showShortOptions(con->options, fp, NULL); 00857 columns->cur = singleTableUsage(con, fp, columns, con->options, NULL, done); 00858 columns->cur = itemUsage(fp, columns, con->aliases, con->numAliases, NULL); 00859 columns->cur = itemUsage(fp, columns, con->execs, con->numExecs, NULL); 00860 00861 if (con->otherHelp) { 00862 columns->cur += strlen(con->otherHelp) + 1; 00863 if (columns->cur > columns->max) fprintf(fp, "\n "); 00864 fprintf(fp, " %s", con->otherHelp); 00865 } 00866 00867 fprintf(fp, "\n"); 00868 if (done->opts != NULL) 00869 free(done->opts); 00870 free(columns); 00871 } 00872 } 00873 00874 void poptSetOtherOptionHelp(poptContext con, const char * text) 00875 { 00876 con->otherHelp = _free(con->otherHelp); 00877 con->otherHelp = xstrdup(text); 00878 }