1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */ 2 3 /** \ingroup popt 4 * \file popt/popthelp.c 5 */ 6 7 /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING 8 file accompanying popt source distributions, available from 9 ftp://ftp.rpm.org/pub/rpm/dist. */ 10 11 #include "system.h" 12 13 //#define POPT_WCHAR_HACK 14 #ifdef POPT_WCHAR_HACK 15 #include <wchar.h> /* for mbsrtowcs */ 16 /*@access mbstate_t @*/ 17 #endif 18 #include "poptint.h" 19 20 /*@access poptContext@*/ 21 22 /** 23 * Display arguments. 24 * @param con context 25 * @param foo (unused) 26 * @param key option(s) 27 * @param arg (unused) 28 * @param data (unused) 29 */ 30 static void displayArgs(poptContext con, 31 /*@unused@*/ enum poptCallbackReason foo, 32 struct poptOption * key, 33 /*@unused@*/ const char * arg, /*@unused@*/ void * data) 34 /*@globals fileSystem@*/ 35 /*@modifies fileSystem@*/ 36 { 37 if (key->shortName == '?') 38 poptPrintHelp(con, stdout, 0); 39 else 40 poptPrintUsage(con, stdout, 0); 41 exit(0); 42 } 43 44 #ifdef NOTYET 45 /*@unchecked@*/ 46 static int show_option_defaults = 0; 47 #endif 48 49 /** 50 * Empty table marker to enable displaying popt alias/exec options. 51 */ 52 /*@observer@*/ /*@unchecked@*/ 53 struct poptOption poptAliasOptions[] = { 54 POPT_TABLEEND 55 }; 56 57 /** 58 * Auto help table options. 59 */ 60 /*@-castfcnptr@*/ 61 /*@observer@*/ /*@unchecked@*/ 62 struct poptOption poptHelpOptions[] = { 63 { NULL, '\0', POPT_ARG_CALLBACK, (void *)&displayArgs, '\0', NULL, NULL }, 64 { "help", '?', 0, NULL, '?', N_("Show this help message"), NULL }, 65 { "usage", '\0', 0, NULL, 'u', N_("Display brief usage message"), NULL }, 66 POPT_TABLEEND 67 } ; 68 69 /*@observer@*/ /*@unchecked@*/ 70 static struct poptOption poptHelpOptions2[] = { 71 /*@-readonlytrans@*/ 72 { NULL, '\0', POPT_ARG_INTL_DOMAIN, PACKAGE, 0, NULL, NULL}, 73 /*@=readonlytrans@*/ 74 { NULL, '\0', POPT_ARG_CALLBACK, (void *)&displayArgs, '\0', NULL, NULL }, 75 { "help", '?', 0, NULL, '?', N_("Show this help message"), NULL }, 76 { "usage", '\0', 0, NULL, 'u', N_("Display brief usage message"), NULL }, 77 #ifdef NOTYET 78 { "defaults", '\0', POPT_ARG_NONE, &show_option_defaults, 0, 79 N_("Display option defaults in message"), NULL }, 80 #endif 81 POPT_TABLEEND 82 } ; 83 84 /*@observer@*/ /*@unchecked@*/ 85 struct poptOption * poptHelpOptionsI18N = poptHelpOptions2; 86 /*@=castfcnptr@*/ 87 88 /** 89 * @param table option(s) 90 */ 91 /*@observer@*/ /*@null@*/ static const char * 92 getTableTranslationDomain(/*@null@*/ const struct poptOption *table) 93 /*@*/ 94 { 95 const struct poptOption *opt; 96 97 if (table != NULL) 98 for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) { 99 if (opt->argInfo == POPT_ARG_INTL_DOMAIN) 100 return opt->arg; 101 } 102 return NULL; 103 } 104 105 /** 106 * @param opt option(s) 107 * @param translation_domain translation domain 108 */ 109 /*@observer@*/ /*@null@*/ static const char * 110 getArgDescrip(const struct poptOption * opt, 111 /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */ 112 /*@null@*/ const char * translation_domain) 113 /*@=paramuse@*/ 114 /*@*/ 115 { 116 if (!(opt->argInfo & POPT_ARG_MASK)) return NULL; 117 118 if (opt == (poptHelpOptions + 1) || opt == (poptHelpOptions + 2)) 119 if (opt->argDescrip) return POPT_(opt->argDescrip); 120 121 if (opt->argDescrip) return D_(translation_domain, opt->argDescrip); 122 123 switch (opt->argInfo & POPT_ARG_MASK) { 124 case POPT_ARG_NONE: return POPT_("NONE"); 125 #ifdef DYING 126 case POPT_ARG_VAL: return POPT_("VAL"); 127 #else 128 case POPT_ARG_VAL: return NULL; 129 #endif 130 case POPT_ARG_INT: return POPT_("INT"); 131 case POPT_ARG_LONG: return POPT_("LONG"); 132 case POPT_ARG_STRING: return POPT_("STRING"); 133 case POPT_ARG_FLOAT: return POPT_("FLOAT"); 134 case POPT_ARG_DOUBLE: return POPT_("DOUBLE"); 135 default: return POPT_("ARG"); 136 } 137 } 138 139 /** 140 * Display default value for an option. 141 * @param lineLength display positions remaining 142 * @param opt option(s) 143 * @param translation_domain translation domain 144 * @return 145 */ 146 static /*@only@*/ /*@null@*/ char * 147 singleOptionDefaultValue(size_t lineLength, 148 const struct poptOption * opt, 149 /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */ 150 /*@null@*/ const char * translation_domain) 151 /*@=paramuse@*/ 152 /*@*/ 153 { 154 const char * defstr = D_(translation_domain, "default"); 155 char * le = malloc(4*lineLength + 1); 156 char * l = le; 157 158 if (le == NULL) return NULL; /* XXX can't happen */ 159 /*@-boundswrite@*/ 160 *le = '\0'; 161 *le++ = '('; 162 strcpy(le, defstr); le += strlen(le); 163 *le++ = ':'; 164 *le++ = ' '; 165 if (opt->arg) /* XXX programmer error */ 166 switch (opt->argInfo & POPT_ARG_MASK) { 167 case POPT_ARG_VAL: 168 case POPT_ARG_INT: 169 { long aLong = *((int *)opt->arg); 170 le += sprintf(le, "%ld", aLong); 171 } break; 172 case POPT_ARG_LONG: 173 { long aLong = *((long *)opt->arg); 174 le += sprintf(le, "%ld", aLong); 175 } break; 176 case POPT_ARG_FLOAT: 177 { double aDouble = *((float *)opt->arg); 178 le += sprintf(le, "%g", aDouble); 179 } break; 180 case POPT_ARG_DOUBLE: 181 { double aDouble = *((double *)opt->arg); 182 le += sprintf(le, "%g", aDouble); 183 } break; 184 case POPT_ARG_STRING: 185 { const char * s = *(const char **)opt->arg; 186 if (s == NULL) { 187 strcpy(le, "null"); le += strlen(le); 188 } else { 189 size_t slen = 4*lineLength - (le - l) - sizeof("\"...\")"); 190 *le++ = '"'; 191 strncpy(le, s, slen); le[slen] = '\0'; le += strlen(le); 192 if (slen < strlen(s)) { 193 strcpy(le, "..."); le += strlen(le); 194 } 195 *le++ = '"'; 196 } 197 } break; 198 case POPT_ARG_NONE: 199 default: 200 l = _free(l); 201 return NULL; 202 /*@notreached@*/ break; 203 } 204 *le++ = ')'; 205 *le = '\0'; 206 /*@=boundswrite@*/ 207 208 return l; 209 } 210 211 /** 212 * Display help text for an option. 213 * @param fp output file handle 214 * @param maxLeftCol largest argument display width 215 * @param opt option(s) 216 * @param translation_domain translation domain 217 */ 218 static void singleOptionHelp(FILE * fp, size_t maxLeftCol, 219 const struct poptOption * opt, 220 /*@null@*/ const char * translation_domain) 221 /*@globals fileSystem @*/ 222 /*@modifies *fp, fileSystem @*/ 223 { 224 size_t indentLength = maxLeftCol + 5; 225 size_t lineLength = 79 - indentLength; 226 const char * help = D_(translation_domain, opt->descrip); 227 const char * argDescrip = getArgDescrip(opt, translation_domain); 228 size_t helpLength; 229 char * defs = NULL; 230 char * left; 231 size_t nb = maxLeftCol + 1; 232 int displaypad = 0; 233 234 /* Make sure there's more than enough room in target buffer. */ 235 if (opt->longName) nb += strlen(opt->longName); 236 if (argDescrip) nb += strlen(argDescrip); 237 238 /*@-boundswrite@*/ 239 left = malloc(nb); 240 if (left == NULL) return; /* XXX can't happen */ 241 left[0] = '\0'; 242 left[maxLeftCol] = '\0'; 243 244 if (opt->longName && opt->shortName) 245 sprintf(left, "-%c, %s%s", opt->shortName, 246 ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"), 247 opt->longName); 248 else if (opt->shortName != '\0') 249 sprintf(left, "-%c", opt->shortName); 250 else if (opt->longName) 251 sprintf(left, "%s%s", 252 ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"), 253 opt->longName); 254 if (!*left) goto out; 255 256 if (argDescrip) { 257 char * le = left + strlen(left); 258 259 if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) 260 *le++ = '['; 261 262 /* Choose type of output */ 263 /*@-branchstate@*/ 264 if (opt->argInfo & POPT_ARGFLAG_SHOW_DEFAULT) { 265 defs = singleOptionDefaultValue(lineLength, opt, translation_domain); 266 if (defs) { 267 char * t = malloc((help ? strlen(help) : 0) + 268 strlen(defs) + sizeof(" ")); 269 if (t) { 270 char * te = t; 271 *te = '\0'; 272 if (help) { 273 strcpy(te, help); te += strlen(te); 274 } 275 *te++ = ' '; 276 strcpy(te, defs); 277 defs = _free(defs); 278 } 279 defs = t; 280 } 281 } 282 /*@=branchstate@*/ 283 284 if (opt->argDescrip == NULL) { 285 switch (opt->argInfo & POPT_ARG_MASK) { 286 case POPT_ARG_NONE: 287 break; 288 case POPT_ARG_VAL: 289 #ifdef NOTNOW /* XXX pug ugly nerdy output */ 290 { long aLong = opt->val; 291 int ops = (opt->argInfo & POPT_ARGFLAG_LOGICALOPS); 292 int negate = (opt->argInfo & POPT_ARGFLAG_NOT); 293 294 /* Don't bother displaying typical values */ 295 if (!ops && (aLong == 0L || aLong == 1L || aLong == -1L)) 296 break; 297 *le++ = '['; 298 switch (ops) { 299 case POPT_ARGFLAG_OR: 300 *le++ = '|'; 301 /*@innerbreak@*/ break; 302 case POPT_ARGFLAG_AND: 303 *le++ = '&'; 304 /*@innerbreak@*/ break; 305 case POPT_ARGFLAG_XOR: 306 *le++ = '^'; 307 /*@innerbreak@*/ break; 308 default: 309 /*@innerbreak@*/ break; 310 } 311 *le++ = (opt->longName != NULL ? '=' : ' '); 312 if (negate) *le++ = '~'; 313 /*@-formatconst@*/ 314 le += sprintf(le, (ops ? "0x%lx" : "%ld"), aLong); 315 /*@=formatconst@*/ 316 *le++ = ']'; 317 } 318 #endif 319 break; 320 case POPT_ARG_INT: 321 case POPT_ARG_LONG: 322 case POPT_ARG_FLOAT: 323 case POPT_ARG_DOUBLE: 324 case POPT_ARG_STRING: 325 *le++ = (opt->longName != NULL ? '=' : ' '); 326 strcpy(le, argDescrip); le += strlen(le); 327 break; 328 default: 329 break; 330 } 331 } else { 332 size_t lelen; 333 334 *le++ = '='; 335 strcpy(le, argDescrip); 336 lelen = strlen(le); 337 le += lelen; 338 339 #ifdef POPT_WCHAR_HACK 340 { const char * scopy = argDescrip; 341 mbstate_t t; 342 size_t n; 343 344 memset ((void *)&t, '\0', sizeof (t)); /* In initial state. */ 345 /* Determine number of characters. */ 346 n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t); 347 348 displaypad = (int) (lelen-n); 349 } 350 #endif 351 } 352 if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) 353 *le++ = ']'; 354 *le = '\0'; 355 } 356 /*@=boundswrite@*/ 357 358 if (help) 359 fprintf(fp," %-*s ", maxLeftCol+displaypad, left); 360 else { 361 fprintf(fp," %s\n", left); 362 goto out; 363 } 364 365 left = _free(left); 366 /*@-branchstate@*/ 367 if (defs) { 368 help = defs; 369 defs = NULL; 370 } 371 /*@=branchstate@*/ 372 373 helpLength = strlen(help); 374 /*@-boundsread@*/ 375 while (helpLength > lineLength) { 376 const char * ch; 377 char format[16]; 378 379 ch = help + lineLength - 1; 380 while (ch > help && !isspace(*ch)) ch--; 381 if (ch == help) break; /* give up */ 382 while (ch > (help + 1) && isspace(*ch)) ch--; 383 ch++; 384 385 sprintf(format, "%%.%ds\n%%%ds", (int) (ch - help), (int) indentLength); 386 /*@-formatconst@*/ 387 fprintf(fp, format, help, " "); 388 /*@=formatconst@*/ 389 help = ch; 390 while (isspace(*help) && *help) help++; 391 helpLength = strlen(help); 392 } 393 /*@=boundsread@*/ 394 395 if (helpLength) fprintf(fp, "%s\n", help); 396 397 out: 398 /*@-dependenttrans@*/ 399 defs = _free(defs); 400 /*@=dependenttrans@*/ 401 left = _free(left); 402 } 403 404 /** 405 * Find display width for longest argument string. 406 * @param opt option(s) 407 * @param translation_domain translation domain 408 * @return display width 409 */ 410 static size_t maxArgWidth(const struct poptOption * opt, 411 /*@null@*/ const char * translation_domain) 412 /*@*/ 413 { 414 size_t max = 0; 415 size_t len = 0; 416 const char * s; 417 418 if (opt != NULL) 419 while (opt->longName || opt->shortName || opt->arg) { 420 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { 421 if (opt->arg) /* XXX program error */ 422 len = maxArgWidth(opt->arg, translation_domain); 423 if (len > max) max = len; 424 } else if (!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) { 425 len = sizeof(" ")-1; 426 if (opt->shortName != '\0') len += sizeof("-X")-1; 427 if (opt->shortName != '\0' && opt->longName) len += sizeof(", ")-1; 428 if (opt->longName) { 429 len += ((opt->argInfo & POPT_ARGFLAG_ONEDASH) 430 ? sizeof("-")-1 : sizeof("--")-1); 431 len += strlen(opt->longName); 432 } 433 434 s = getArgDescrip(opt, translation_domain); 435 436 #ifdef POPT_WCHAR_HACK 437 /* XXX Calculate no. of display characters. */ 438 if (s) { 439 const char * scopy = s; 440 mbstate_t t; 441 size_t n; 442 443 /*@-boundswrite@*/ 444 memset ((void *)&t, '\0', sizeof (t)); /* In initial state. */ 445 /*@=boundswrite@*/ 446 /* Determine number of characters. */ 447 n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t); 448 len += sizeof("=")-1 + n; 449 } 450 #else 451 if (s) 452 len += sizeof("=")-1 + strlen(s); 453 #endif 454 455 if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) len += sizeof("[]")-1; 456 if (len > max) max = len; 457 } 458 459 opt++; 460 } 461 462 return max; 463 } 464 465 /** 466 * Display popt alias and exec help. 467 * @param fp output file handle 468 * @param items alias/exec array 469 * @param nitems no. of alias/exec entries 470 * @param left largest argument display width 471 * @param translation_domain translation domain 472 */ 473 static void itemHelp(FILE * fp, 474 /*@null@*/ poptItem items, int nitems, size_t left, 475 /*@null@*/ const char * translation_domain) 476 /*@globals fileSystem @*/ 477 /*@modifies *fp, fileSystem @*/ 478 { 479 poptItem item; 480 int i; 481 482 if (items != NULL) 483 for (i = 0, item = items; i < nitems; i++, item++) { 484 const struct poptOption * opt; 485 opt = &item->option; 486 if ((opt->longName || opt->shortName) && 487 !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) 488 singleOptionHelp(fp, left, opt, translation_domain); 489 } 490 } 491 492 /** 493 * Display help text for a table of options. 494 * @param con context 495 * @param fp output file handle 496 * @param table option(s) 497 * @param left largest argument display width 498 * @param translation_domain translation domain 499 */ 500 static void singleTableHelp(poptContext con, FILE * fp, 501 /*@null@*/ const struct poptOption * table, size_t left, 502 /*@null@*/ const char * translation_domain) 503 /*@globals fileSystem @*/ 504 /*@modifies *fp, fileSystem @*/ 505 { 506 const struct poptOption * opt; 507 const char *sub_transdom; 508 509 if (table == poptAliasOptions) { 510 itemHelp(fp, con->aliases, con->numAliases, left, NULL); 511 itemHelp(fp, con->execs, con->numExecs, left, NULL); 512 return; 513 } 514 515 if (table != NULL) 516 for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) { 517 if ((opt->longName || opt->shortName) && 518 !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) 519 singleOptionHelp(fp, left, opt, translation_domain); 520 } 521 522 if (table != NULL) 523 for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) { 524 if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_INCLUDE_TABLE) 525 continue; 526 sub_transdom = getTableTranslationDomain(opt->arg); 527 if (sub_transdom == NULL) 528 sub_transdom = translation_domain; 529 530 if (opt->descrip) 531 fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip)); 532 533 singleTableHelp(con, fp, opt->arg, left, sub_transdom); 534 } 535 } 536 537 /** 538 * @param con context 539 * @param fp output file handle 540 */ 541 static int showHelpIntro(poptContext con, FILE * fp) 542 /*@globals fileSystem @*/ 543 /*@modifies *fp, fileSystem @*/ 544 { 545 int len = 6; 546 const char * fn; 547 548 fprintf(fp, POPT_("Usage:")); 549 if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) { 550 /*@-boundsread@*/ 551 /*@-nullderef -type@*/ /* LCL: wazzup? */ 552 fn = con->optionStack->argv[0]; 553 /*@=nullderef =type@*/ 554 /*@=boundsread@*/ 555 if (fn == NULL) return len; 556 if (strchr(fn, '/')) fn = strrchr(fn, '/') + 1; 557 fprintf(fp, " %s", fn); 558 len += strlen(fn) + 1; 559 } 560 561 return len; 562 } 563 564 void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ int flags) 565 { 566 size_t leftColWidth; 567 568 (void) showHelpIntro(con, fp); 569 if (con->otherHelp) 570 fprintf(fp, " %s\n", con->otherHelp); 571 else 572 fprintf(fp, " %s\n", POPT_("[OPTION...]")); 573 574 leftColWidth = maxArgWidth(con->options, NULL); 575 singleTableHelp(con, fp, con->options, leftColWidth, NULL); 576 } 577 578 /** 579 * Display usage text for an option. 580 * @param fp output file handle 581 * @param cursor current display position 582 * @param opt option(s) 583 * @param translation_domain translation domain 584 */ 585 static size_t singleOptionUsage(FILE * fp, size_t cursor, 586 const struct poptOption * opt, 587 /*@null@*/ const char *translation_domain) 588 /*@globals fileSystem @*/ 589 /*@modifies *fp, fileSystem @*/ 590 { 591 size_t len = 4; 592 char shortStr[2] = { '\0', '\0' }; 593 const char * item = shortStr; 594 const char * argDescrip = getArgDescrip(opt, translation_domain); 595 596 if (opt->shortName != '\0' && opt->longName != NULL) { 597 len += 2; 598 if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++; 599 len += strlen(opt->longName); 600 } else if (opt->shortName != '\0') { 601 len++; 602 shortStr[0] = opt->shortName; 603 shortStr[1] = '\0'; 604 } else if (opt->longName) { 605 len += strlen(opt->longName); 606 if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++; 607 item = opt->longName; 608 } 609 610 if (len == 4) return cursor; 611 612 #ifdef POPT_WCHAR_HACK 613 /* XXX Calculate no. of display characters. */ 614 if (argDescrip) { 615 const char * scopy = argDescrip; 616 mbstate_t t; 617 size_t n; 618 619 /*@-boundswrite@*/ 620 memset ((void *)&t, '\0', sizeof (t)); /* In initial state. */ 621 /*@=boundswrite@*/ 622 /* Determine number of characters. */ 623 n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t); 624 len += sizeof("=")-1 + n; 625 } 626 #else 627 if (argDescrip) 628 len += sizeof("=")-1 + strlen(argDescrip); 629 #endif 630 631 if ((cursor + len) > 79) { 632 fprintf(fp, "\n "); 633 cursor = 7; 634 } 635 636 if (opt->longName && opt->shortName) { 637 fprintf(fp, " [-%c|-%s%s%s%s]", 638 opt->shortName, ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "" : "-"), 639 opt->longName, 640 (argDescrip ? " " : ""), 641 (argDescrip ? argDescrip : "")); 642 } else { 643 fprintf(fp, " [-%s%s%s%s]", 644 ((opt->shortName || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) ? "" : "-"), 645 item, 646 (argDescrip ? (opt->shortName != '\0' ? " " : "=") : ""), 647 (argDescrip ? argDescrip : "")); 648 } 649 650 return cursor + len + 1; 651 } 652 653 /** 654 * Display popt alias and exec usage. 655 * @param fp output file handle 656 * @param cursor current display position 657 * @param item alias/exec array 658 * @param nitems no. of ara/exec entries 659 * @param translation_domain translation domain 660 */ 661 static size_t itemUsage(FILE * fp, size_t cursor, 662 /*@null@*/ poptItem item, int nitems, 663 /*@null@*/ const char * translation_domain) 664 /*@globals fileSystem @*/ 665 /*@modifies *fp, fileSystem @*/ 666 { 667 int i; 668 669 /*@-branchstate@*/ /* FIX: W2DO? */ 670 if (item != NULL) 671 for (i = 0; i < nitems; i++, item++) { 672 const struct poptOption * opt; 673 opt = &item->option; 674 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) { 675 translation_domain = (const char *)opt->arg; 676 } else if ((opt->longName || opt->shortName) && 677 !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) { 678 cursor = singleOptionUsage(fp, cursor, opt, translation_domain); 679 } 680 } 681 /*@=branchstate@*/ 682 683 return cursor; 684 } 685 686 /** 687 * Keep track of option tables already processed. 688 */ 689 typedef struct poptDone_s { 690 int nopts; 691 int maxopts; 692 const void ** opts; 693 } * poptDone; 694 695 /** 696 * Display usage text for a table of options. 697 * @param con context 698 * @param fp output file handle 699 * @param cursor current display position 700 * @param opt option(s) 701 * @param translation_domain translation domain 702 * @param done tables already processed 703 * @return 704 */ 705 static size_t singleTableUsage(poptContext con, FILE * fp, size_t cursor, 706 /*@null@*/ const struct poptOption * opt, 707 /*@null@*/ const char * translation_domain, 708 /*@null@*/ poptDone done) 709 /*@globals fileSystem @*/ 710 /*@modifies *fp, done, fileSystem @*/ 711 { 712 /*@-branchstate@*/ /* FIX: W2DO? */ 713 if (opt != NULL) 714 for (; (opt->longName || opt->shortName || opt->arg) ; opt++) { 715 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) { 716 translation_domain = (const char *)opt->arg; 717 } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { 718 if (done) { 719 int i = 0; 720 for (i = 0; i < done->nopts; i++) { 721 /*@-boundsread@*/ 722 const void * that = done->opts[i]; 723 /*@=boundsread@*/ 724 if (that == NULL || that != opt->arg) 725 /*@innercontinue@*/ continue; 726 /*@innerbreak@*/ break; 727 } 728 /* Skip if this table has already been processed. */ 729 if (opt->arg == NULL || i < done->nopts) 730 continue; 731 /*@-boundswrite@*/ 732 if (done->nopts < done->maxopts) 733 done->opts[done->nopts++] = (const void *) opt->arg; 734 /*@=boundswrite@*/ 735 } 736 cursor = singleTableUsage(con, fp, cursor, opt->arg, 737 translation_domain, done); 738 } else if ((opt->longName || opt->shortName) && 739 !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) { 740 cursor = singleOptionUsage(fp, cursor, opt, translation_domain); 741 } 742 } 743 /*@=branchstate@*/ 744 745 return cursor; 746 } 747 748 /** 749 * Return concatenated short options for display. 750 * @todo Sub-tables should be recursed. 751 * @param opt option(s) 752 * @param fp output file handle 753 * @retval str concatenation of short options 754 * @return length of display string 755 */ 756 static int showShortOptions(const struct poptOption * opt, FILE * fp, 757 /*@null@*/ char * str) 758 /*@globals fileSystem @*/ 759 /*@modifies *str, *fp, fileSystem @*/ 760 /*@requires maxRead(str) >= 0 @*/ 761 { 762 /* bufsize larger then the ascii set, lazy alloca on top level call. */ 763 char * s = (str != NULL ? str : memset(alloca(300), 0, 300)); 764 int len = 0; 765 766 /*@-boundswrite@*/ 767 if (opt != NULL) 768 for (; (opt->longName || opt->shortName || opt->arg); opt++) { 769 if (opt->shortName && !(opt->argInfo & POPT_ARG_MASK)) 770 s[strlen(s)] = opt->shortName; 771 else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) 772 if (opt->arg) /* XXX program error */ 773 len = showShortOptions(opt->arg, fp, s); 774 } 775 /*@=boundswrite@*/ 776 777 /* On return to top level, print the short options, return print length. */ 778 if (s == str && *s != '\0') { 779 fprintf(fp, " [-%s]", s); 780 len = strlen(s) + sizeof(" [-]")-1; 781 } 782 return len; 783 } 784 785 void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ int flags) 786 { 787 poptDone done = memset(alloca(sizeof(*done)), 0, sizeof(*done)); 788 size_t cursor; 789 790 done->nopts = 0; 791 done->maxopts = 64; 792 cursor = done->maxopts * sizeof(*done->opts); 793 /*@-boundswrite@*/ 794 done->opts = memset(alloca(cursor), 0, cursor); 795 /*@-keeptrans@*/ 796 done->opts[done->nopts++] = (const void *) con->options; 797 /*@=keeptrans@*/ 798 /*@=boundswrite@*/ 799 800 cursor = showHelpIntro(con, fp); 801 cursor += showShortOptions(con->options, fp, NULL); 802 cursor = singleTableUsage(con, fp, cursor, con->options, NULL, done); 803 cursor = itemUsage(fp, cursor, con->aliases, con->numAliases, NULL); 804 cursor = itemUsage(fp, cursor, con->execs, con->numExecs, NULL); 805 806 if (con->otherHelp) { 807 cursor += strlen(con->otherHelp) + 1; 808 if (cursor > 79) fprintf(fp, "\n "); 809 fprintf(fp, " %s", con->otherHelp); 810 } 811 812 fprintf(fp, "\n"); 813 } 814 815 void poptSetOtherOptionHelp(poptContext con, const char * text) 816 { 817 con->otherHelp = _free(con->otherHelp); 818 con->otherHelp = xstrdup(text); 819 } 820