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