Annotation of embedaddon/rsync/popt/popthelp.c, revision 1.1
1.1 ! misho 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@*/ UNUSED(enum poptCallbackReason foo),
! 32: struct poptOption * key,
! 33: /*@unused@*/ UNUSED(const char * arg), /*@unused@*/ 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@*/ UNUSED(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");*/ /* impossible */
! 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@*/ UNUSED(const char * translation_domain))
! 151: /*@=paramuse@*/
! 152: /*@*/
! 153: {
! 154: const char * defstr = D_(translation_domain, "default");
! 155: size_t limit, bufsize = 4*lineLength + 1;
! 156: char * le = malloc(bufsize);
! 157: char * l = le;
! 158:
! 159: if (le == NULL) return NULL; /* XXX can't happen */
! 160: /*@-boundswrite@*/
! 161: *le++ = '(';
! 162: le += strlcpy(le, defstr, bufsize - 3);
! 163: *le++ = ':';
! 164: *le++ = ' ';
! 165: limit = bufsize - (le - l) - 1; /* -1 for closing paren */
! 166: if (opt->arg) /* XXX programmer error */
! 167: switch (opt->argInfo & POPT_ARG_MASK) {
! 168: case POPT_ARG_VAL:
! 169: case POPT_ARG_INT:
! 170: { long aLong = *((int *)opt->arg);
! 171: le += snprintf(le, limit, "%ld", aLong);
! 172: } break;
! 173: case POPT_ARG_LONG:
! 174: { long aLong = *((long *)opt->arg);
! 175: le += snprintf(le, limit, "%ld", aLong);
! 176: } break;
! 177: case POPT_ARG_FLOAT:
! 178: { double aDouble = *((float *)opt->arg);
! 179: le += snprintf(le, limit, "%g", aDouble);
! 180: } break;
! 181: case POPT_ARG_DOUBLE:
! 182: { double aDouble = *((double *)opt->arg);
! 183: le += snprintf(le, limit, "%g", aDouble);
! 184: } break;
! 185: case POPT_ARG_STRING:
! 186: { const char * s = *(const char **)opt->arg;
! 187: if (s == NULL) {
! 188: le += strlcpy(le, "null", limit);
! 189: } else {
! 190: size_t len;
! 191: limit -= 2; /* make room for quotes */
! 192: *le++ = '"';
! 193: len = strlcpy(le, s, limit);
! 194: if (len >= limit) {
! 195: le += limit - 3 - 1;
! 196: *le++ = '.'; *le++ = '.'; *le++ = '.';
! 197: } else
! 198: le += len;
! 199: *le++ = '"';
! 200: }
! 201: } break;
! 202: case POPT_ARG_NONE:
! 203: default:
! 204: l = _free(l);
! 205: return NULL;
! 206: /*@notreached@*/ break;
! 207: }
! 208: *le++ = ')';
! 209: *le = '\0';
! 210: /*@=boundswrite@*/
! 211:
! 212: return l;
! 213: }
! 214:
! 215: /**
! 216: * Display help text for an option.
! 217: * @param fp output file handle
! 218: * @param maxLeftCol largest argument display width
! 219: * @param opt option(s)
! 220: * @param translation_domain translation domain
! 221: */
! 222: static void singleOptionHelp(FILE * fp, size_t maxLeftCol,
! 223: const struct poptOption * opt,
! 224: /*@null@*/ UNUSED(const char * translation_domain))
! 225: /*@globals fileSystem @*/
! 226: /*@modifies *fp, fileSystem @*/
! 227: {
! 228: size_t indentLength = maxLeftCol + 5;
! 229: size_t lineLength = 79 - indentLength;
! 230: const char * help = D_(translation_domain, opt->descrip);
! 231: const char * argDescrip = getArgDescrip(opt, translation_domain);
! 232: size_t helpLength;
! 233: char * defs = NULL;
! 234: char * left;
! 235: size_t lelen, limit;
! 236: size_t nb = maxLeftCol + 1;
! 237: int displaypad = 0;
! 238:
! 239: /* Make sure there's more than enough room in target buffer. */
! 240: if (opt->longName) nb += strlen(opt->longName);
! 241: if (argDescrip) nb += strlen(argDescrip);
! 242:
! 243: /*@-boundswrite@*/
! 244: left = malloc(nb);
! 245: if (left == NULL) return; /* XXX can't happen */
! 246: left[0] = '\0';
! 247: left[maxLeftCol] = '\0';
! 248:
! 249: if (opt->longName && opt->shortName)
! 250: snprintf(left, nb, "-%c, %s%s", opt->shortName,
! 251: ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
! 252: opt->longName);
! 253: else if (opt->shortName != '\0')
! 254: snprintf(left, nb, "-%c", opt->shortName);
! 255: else if (opt->longName)
! 256: snprintf(left, nb, "%s%s",
! 257: ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
! 258: opt->longName);
! 259: if (!*left) goto out;
! 260:
! 261: if (argDescrip) {
! 262: char * le = left + strlen(left);
! 263:
! 264: if (opt->argInfo & POPT_ARGFLAG_OPTIONAL)
! 265: *le++ = '[';
! 266:
! 267: /* Choose type of output */
! 268: /*@-branchstate@*/
! 269: if (opt->argInfo & POPT_ARGFLAG_SHOW_DEFAULT) {
! 270: defs = singleOptionDefaultValue(lineLength, opt, translation_domain);
! 271: if (defs) {
! 272: size_t bufsize = (help ? strlen(help) : 0) + sizeof " " + strlen(defs);
! 273: char * t = malloc(bufsize);
! 274: if (t) {
! 275: snprintf(t, bufsize, "%s %s", help ? help : "", defs);
! 276: defs = _free(defs);
! 277: }
! 278: defs = t;
! 279: }
! 280: }
! 281: /*@=branchstate@*/
! 282:
! 283: if (opt->argDescrip == NULL) {
! 284: switch (opt->argInfo & POPT_ARG_MASK) {
! 285: case POPT_ARG_NONE:
! 286: break;
! 287: case POPT_ARG_VAL:
! 288: #ifdef NOTNOW /* XXX pug ugly nerdy output */
! 289: { long aLong = opt->val;
! 290: int ops = (opt->argInfo & POPT_ARGFLAG_LOGICALOPS);
! 291: int negate = (opt->argInfo & POPT_ARGFLAG_NOT);
! 292:
! 293: /* Don't bother displaying typical values */
! 294: if (!ops && (aLong == 0L || aLong == 1L || aLong == -1L))
! 295: break;
! 296: *le++ = '[';
! 297: switch (ops) {
! 298: case POPT_ARGFLAG_OR:
! 299: *le++ = '|';
! 300: /*@innerbreak@*/ break;
! 301: case POPT_ARGFLAG_AND:
! 302: *le++ = '&';
! 303: /*@innerbreak@*/ break;
! 304: case POPT_ARGFLAG_XOR:
! 305: *le++ = '^';
! 306: /*@innerbreak@*/ break;
! 307: default:
! 308: /*@innerbreak@*/ break;
! 309: }
! 310: *le++ = (opt->longName != NULL ? '=' : ' ');
! 311: if (negate) *le++ = '~';
! 312: /*@-formatconst@*/
! 313: limit = nb - (le - left);
! 314: lelen = snprintf(le, limit, (ops ? "0x%lx" : "%ld"), aLong);
! 315: le += lelen >= limit ? limit - 1 : lelen;
! 316: /*@=formatconst@*/
! 317: *le++ = ']';
! 318: }
! 319: #endif
! 320: break;
! 321: case POPT_ARG_INT:
! 322: case POPT_ARG_LONG:
! 323: case POPT_ARG_FLOAT:
! 324: case POPT_ARG_DOUBLE:
! 325: case POPT_ARG_STRING:
! 326: *le++ = (opt->longName != NULL ? '=' : ' ');
! 327: limit = nb - (le - left);
! 328: lelen = strlcpy(le, argDescrip, limit);
! 329: le += lelen >= limit ? limit - 1 : lelen;
! 330: break;
! 331: default:
! 332: break;
! 333: }
! 334: } else {
! 335:
! 336: *le++ = '=';
! 337: limit = nb - (le - left);
! 338: lelen = strlcpy(le, argDescrip, limit);
! 339: if (lelen >= limit)
! 340: lelen = limit - 1;
! 341: le += lelen;
! 342:
! 343: #ifdef POPT_WCHAR_HACK
! 344: { const char * scopy = argDescrip;
! 345: mbstate_t t;
! 346: size_t n;
! 347:
! 348: memset ((void *)&t, '\0', sizeof (t)); /* In initial state. */
! 349: /* Determine number of characters. */
! 350: n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t);
! 351:
! 352: displaypad = (int) (lelen-n);
! 353: }
! 354: #endif
! 355: }
! 356: if (opt->argInfo & POPT_ARGFLAG_OPTIONAL)
! 357: *le++ = ']';
! 358: *le = '\0';
! 359: }
! 360: /*@=boundswrite@*/
! 361:
! 362: if (help)
! 363: fprintf(fp," %-*s ", (int)maxLeftCol+displaypad, left);
! 364: else {
! 365: fprintf(fp," %s\n", left);
! 366: goto out;
! 367: }
! 368:
! 369: left = _free(left);
! 370: /*@-branchstate@*/
! 371: if (defs) {
! 372: help = defs;
! 373: defs = NULL;
! 374: }
! 375: /*@=branchstate@*/
! 376:
! 377: helpLength = strlen(help);
! 378: /*@-boundsread@*/
! 379: while (helpLength > lineLength) {
! 380: const char * ch;
! 381: char format[16];
! 382:
! 383: ch = help + lineLength - 1;
! 384: while (ch > help && !isSpace(ch)) ch--;
! 385: if (ch == help) break; /* give up */
! 386: while (ch > (help + 1) && isSpace(ch)) ch--;
! 387: ch++;
! 388:
! 389: snprintf(format, sizeof format, "%%.%ds\n%%%ds", (int) (ch - help), (int) indentLength);
! 390: /*@-formatconst@*/
! 391: fprintf(fp, format, help, " ");
! 392: /*@=formatconst@*/
! 393: help = ch;
! 394: while (isSpace(help) && *help) help++;
! 395: helpLength = strlen(help);
! 396: }
! 397: /*@=boundsread@*/
! 398:
! 399: if (helpLength) fprintf(fp, "%s\n", help);
! 400:
! 401: out:
! 402: /*@-dependenttrans@*/
! 403: defs = _free(defs);
! 404: /*@=dependenttrans@*/
! 405: left = _free(left);
! 406: }
! 407:
! 408: /**
! 409: * Find display width for longest argument string.
! 410: * @param opt option(s)
! 411: * @param translation_domain translation domain
! 412: * @return display width
! 413: */
! 414: static size_t maxArgWidth(const struct poptOption * opt,
! 415: /*@null@*/ UNUSED(const char * translation_domain))
! 416: /*@*/
! 417: {
! 418: size_t max = 0;
! 419: size_t len = 0;
! 420: const char * s;
! 421:
! 422: if (opt != NULL)
! 423: while (opt->longName || opt->shortName || opt->arg) {
! 424: if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
! 425: if (opt->arg) /* XXX program error */
! 426: len = maxArgWidth(opt->arg, translation_domain);
! 427: if (len > max) max = len;
! 428: } else if (!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
! 429: len = sizeof(" ")-1;
! 430: if (opt->shortName != '\0') len += sizeof("-X")-1;
! 431: if (opt->shortName != '\0' && opt->longName) len += sizeof(", ")-1;
! 432: if (opt->longName) {
! 433: len += ((opt->argInfo & POPT_ARGFLAG_ONEDASH)
! 434: ? sizeof("-")-1 : sizeof("--")-1);
! 435: len += strlen(opt->longName);
! 436: }
! 437:
! 438: s = getArgDescrip(opt, translation_domain);
! 439:
! 440: #ifdef POPT_WCHAR_HACK
! 441: /* XXX Calculate no. of display characters. */
! 442: if (s) {
! 443: const char * scopy = s;
! 444: mbstate_t t;
! 445: size_t n;
! 446:
! 447: /*@-boundswrite@*/
! 448: memset ((void *)&t, '\0', sizeof (t)); /* In initial state. */
! 449: /*@=boundswrite@*/
! 450: /* Determine number of characters. */
! 451: n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t);
! 452: len += sizeof("=")-1 + n;
! 453: }
! 454: #else
! 455: if (s)
! 456: len += sizeof("=")-1 + strlen(s);
! 457: #endif
! 458:
! 459: if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) len += sizeof("[]")-1;
! 460: if (len > max) max = len;
! 461: }
! 462:
! 463: opt++;
! 464: }
! 465:
! 466: return max;
! 467: }
! 468:
! 469: /**
! 470: * Display popt alias and exec help.
! 471: * @param fp output file handle
! 472: * @param items alias/exec array
! 473: * @param nitems no. of alias/exec entries
! 474: * @param left largest argument display width
! 475: * @param translation_domain translation domain
! 476: */
! 477: static void itemHelp(FILE * fp,
! 478: /*@null@*/ poptItem items, int nitems, size_t left,
! 479: /*@null@*/ UNUSED(const char * translation_domain))
! 480: /*@globals fileSystem @*/
! 481: /*@modifies *fp, fileSystem @*/
! 482: {
! 483: poptItem item;
! 484: int i;
! 485:
! 486: if (items != NULL)
! 487: for (i = 0, item = items; i < nitems; i++, item++) {
! 488: const struct poptOption * opt;
! 489: opt = &item->option;
! 490: if ((opt->longName || opt->shortName) &&
! 491: !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
! 492: singleOptionHelp(fp, left, opt, translation_domain);
! 493: }
! 494: }
! 495:
! 496: /**
! 497: * Display help text for a table of options.
! 498: * @param con context
! 499: * @param fp output file handle
! 500: * @param table option(s)
! 501: * @param left largest argument display width
! 502: * @param translation_domain translation domain
! 503: */
! 504: static void singleTableHelp(poptContext con, FILE * fp,
! 505: /*@null@*/ const struct poptOption * table, size_t left,
! 506: /*@null@*/ UNUSED(const char * translation_domain))
! 507: /*@globals fileSystem @*/
! 508: /*@modifies *fp, fileSystem @*/
! 509: {
! 510: const struct poptOption * opt;
! 511: const char *sub_transdom;
! 512:
! 513: if (table == poptAliasOptions) {
! 514: itemHelp(fp, con->aliases, con->numAliases, left, NULL);
! 515: itemHelp(fp, con->execs, con->numExecs, left, NULL);
! 516: return;
! 517: }
! 518:
! 519: if (table != NULL)
! 520: for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) {
! 521: if ((opt->longName || opt->shortName) &&
! 522: !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
! 523: singleOptionHelp(fp, left, opt, translation_domain);
! 524: }
! 525:
! 526: if (table != NULL)
! 527: for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) {
! 528: if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_INCLUDE_TABLE)
! 529: continue;
! 530: sub_transdom = getTableTranslationDomain(opt->arg);
! 531: if (sub_transdom == NULL)
! 532: sub_transdom = translation_domain;
! 533:
! 534: if (opt->descrip)
! 535: fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip));
! 536:
! 537: singleTableHelp(con, fp, opt->arg, left, sub_transdom);
! 538: }
! 539: }
! 540:
! 541: /**
! 542: * @param con context
! 543: * @param fp output file handle
! 544: */
! 545: static int showHelpIntro(poptContext con, FILE * fp)
! 546: /*@globals fileSystem @*/
! 547: /*@modifies *fp, fileSystem @*/
! 548: {
! 549: int len = 6;
! 550: const char * fn;
! 551:
! 552: fprintf(fp, POPT_("Usage:"));
! 553: if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) {
! 554: /*@-boundsread@*/
! 555: /*@-nullderef -type@*/ /* LCL: wazzup? */
! 556: fn = con->optionStack->argv[0];
! 557: /*@=nullderef =type@*/
! 558: /*@=boundsread@*/
! 559: if (fn == NULL) return len;
! 560: if (strchr(fn, '/')) fn = strrchr(fn, '/') + 1;
! 561: fprintf(fp, " %s", fn);
! 562: len += strlen(fn) + 1;
! 563: }
! 564:
! 565: return len;
! 566: }
! 567:
! 568: void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags))
! 569: {
! 570: size_t leftColWidth;
! 571:
! 572: (void) showHelpIntro(con, fp);
! 573: if (con->otherHelp)
! 574: fprintf(fp, " %s\n", con->otherHelp);
! 575: else
! 576: fprintf(fp, " %s\n", POPT_("[OPTION...]"));
! 577:
! 578: leftColWidth = maxArgWidth(con->options, NULL);
! 579: singleTableHelp(con, fp, con->options, leftColWidth, NULL);
! 580: }
! 581:
! 582: /**
! 583: * Display usage text for an option.
! 584: * @param fp output file handle
! 585: * @param cursor current display position
! 586: * @param opt option(s)
! 587: * @param translation_domain translation domain
! 588: */
! 589: static size_t singleOptionUsage(FILE * fp, size_t cursor,
! 590: const struct poptOption * opt,
! 591: /*@null@*/ const char *translation_domain)
! 592: /*@globals fileSystem @*/
! 593: /*@modifies *fp, fileSystem @*/
! 594: {
! 595: size_t len = 4;
! 596: char shortStr[2] = { '\0', '\0' };
! 597: const char * item = shortStr;
! 598: const char * argDescrip = getArgDescrip(opt, translation_domain);
! 599:
! 600: if (opt->shortName != '\0' && opt->longName != NULL) {
! 601: len += 2;
! 602: if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++;
! 603: len += strlen(opt->longName);
! 604: } else if (opt->shortName != '\0') {
! 605: len++;
! 606: shortStr[0] = opt->shortName;
! 607: shortStr[1] = '\0';
! 608: } else if (opt->longName) {
! 609: len += strlen(opt->longName);
! 610: if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++;
! 611: item = opt->longName;
! 612: }
! 613:
! 614: if (len == 4) return cursor;
! 615:
! 616: #ifdef POPT_WCHAR_HACK
! 617: /* XXX Calculate no. of display characters. */
! 618: if (argDescrip) {
! 619: const char * scopy = argDescrip;
! 620: mbstate_t t;
! 621: size_t n;
! 622:
! 623: /*@-boundswrite@*/
! 624: memset ((void *)&t, '\0', sizeof (t)); /* In initial state. */
! 625: /*@=boundswrite@*/
! 626: /* Determine number of characters. */
! 627: n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t);
! 628: len += sizeof("=")-1 + n;
! 629: }
! 630: #else
! 631: if (argDescrip)
! 632: len += sizeof("=")-1 + strlen(argDescrip);
! 633: #endif
! 634:
! 635: if ((cursor + len) > 79) {
! 636: fprintf(fp, "\n ");
! 637: cursor = 7;
! 638: }
! 639:
! 640: if (opt->longName && opt->shortName) {
! 641: fprintf(fp, " [-%c|-%s%s%s%s]",
! 642: opt->shortName, ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "" : "-"),
! 643: opt->longName,
! 644: (argDescrip ? " " : ""),
! 645: (argDescrip ? argDescrip : ""));
! 646: } else {
! 647: fprintf(fp, " [-%s%s%s%s]",
! 648: ((opt->shortName || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) ? "" : "-"),
! 649: item,
! 650: (argDescrip ? (opt->shortName != '\0' ? " " : "=") : ""),
! 651: (argDescrip ? argDescrip : ""));
! 652: }
! 653:
! 654: return cursor + len + 1;
! 655: }
! 656:
! 657: /**
! 658: * Display popt alias and exec usage.
! 659: * @param fp output file handle
! 660: * @param cursor current display position
! 661: * @param item alias/exec array
! 662: * @param nitems no. of ara/exec entries
! 663: * @param translation_domain translation domain
! 664: */
! 665: static size_t itemUsage(FILE * fp, size_t cursor,
! 666: /*@null@*/ poptItem item, int nitems,
! 667: /*@null@*/ UNUSED(const char * translation_domain))
! 668: /*@globals fileSystem @*/
! 669: /*@modifies *fp, fileSystem @*/
! 670: {
! 671: int i;
! 672:
! 673: /*@-branchstate@*/ /* FIX: W2DO? */
! 674: if (item != NULL)
! 675: for (i = 0; i < nitems; i++, item++) {
! 676: const struct poptOption * opt;
! 677: opt = &item->option;
! 678: if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) {
! 679: translation_domain = (const char *)opt->arg;
! 680: } else if ((opt->longName || opt->shortName) &&
! 681: !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
! 682: cursor = singleOptionUsage(fp, cursor, opt, translation_domain);
! 683: }
! 684: }
! 685: /*@=branchstate@*/
! 686:
! 687: return cursor;
! 688: }
! 689:
! 690: /**
! 691: * Keep track of option tables already processed.
! 692: */
! 693: typedef struct poptDone_s {
! 694: int nopts;
! 695: int maxopts;
! 696: const void ** opts;
! 697: } * poptDone;
! 698:
! 699: /**
! 700: * Display usage text for a table of options.
! 701: * @param con context
! 702: * @param fp output file handle
! 703: * @param cursor current display position
! 704: * @param opt option(s)
! 705: * @param translation_domain translation domain
! 706: * @param done tables already processed
! 707: * @return
! 708: */
! 709: static size_t singleTableUsage(poptContext con, FILE * fp, size_t cursor,
! 710: /*@null@*/ const struct poptOption * opt,
! 711: /*@null@*/ UNUSED(const char * translation_domain),
! 712: /*@null@*/ poptDone done)
! 713: /*@globals fileSystem @*/
! 714: /*@modifies *fp, done, fileSystem @*/
! 715: {
! 716: /*@-branchstate@*/ /* FIX: W2DO? */
! 717: if (opt != NULL)
! 718: for (; (opt->longName || opt->shortName || opt->arg) ; opt++) {
! 719: if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) {
! 720: translation_domain = (const char *)opt->arg;
! 721: } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
! 722: if (done) {
! 723: int i = 0;
! 724: for (i = 0; i < done->nopts; i++) {
! 725: /*@-boundsread@*/
! 726: const void * that = done->opts[i];
! 727: /*@=boundsread@*/
! 728: if (that == NULL || that != opt->arg)
! 729: /*@innercontinue@*/ continue;
! 730: /*@innerbreak@*/ break;
! 731: }
! 732: /* Skip if this table has already been processed. */
! 733: if (opt->arg == NULL || i < done->nopts)
! 734: continue;
! 735: /*@-boundswrite@*/
! 736: if (done->nopts < done->maxopts)
! 737: done->opts[done->nopts++] = (const void *) opt->arg;
! 738: /*@=boundswrite@*/
! 739: }
! 740: cursor = singleTableUsage(con, fp, cursor, opt->arg,
! 741: translation_domain, done);
! 742: } else if ((opt->longName || opt->shortName) &&
! 743: !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
! 744: cursor = singleOptionUsage(fp, cursor, opt, translation_domain);
! 745: }
! 746: }
! 747: /*@=branchstate@*/
! 748:
! 749: return cursor;
! 750: }
! 751:
! 752: /**
! 753: * Return concatenated short options for display.
! 754: * @todo Sub-tables should be recursed.
! 755: * @param opt option(s)
! 756: * @param fp output file handle
! 757: * @retval str concatenation of short options
! 758: * @return length of display string
! 759: */
! 760: static int showShortOptions(const struct poptOption * opt, FILE * fp,
! 761: /*@null@*/ char * str)
! 762: /*@globals fileSystem @*/
! 763: /*@modifies *str, *fp, fileSystem @*/
! 764: /*@requires maxRead(str) >= 0 @*/
! 765: {
! 766: /* bufsize larger then the ascii set, lazy alloca on top level call. */
! 767: char * s = (str != NULL ? str : memset(alloca(300), 0, 300));
! 768: int len = 0;
! 769:
! 770: if (s == NULL)
! 771: return 0;
! 772:
! 773: /*@-boundswrite@*/
! 774: if (opt != NULL)
! 775: for (; (opt->longName || opt->shortName || opt->arg); opt++) {
! 776: if (opt->shortName && !(opt->argInfo & POPT_ARG_MASK))
! 777: s[strlen(s)] = opt->shortName;
! 778: else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE)
! 779: if (opt->arg) /* XXX program error */
! 780: len = showShortOptions(opt->arg, fp, s);
! 781: }
! 782: /*@=boundswrite@*/
! 783:
! 784: /* On return to top level, print the short options, return print length. */
! 785: if (s == str && *s != '\0') {
! 786: fprintf(fp, " [-%s]", s);
! 787: len = strlen(s) + sizeof(" [-]")-1;
! 788: }
! 789: return len;
! 790: }
! 791:
! 792: void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags))
! 793: {
! 794: poptDone done = memset(alloca(sizeof(*done)), 0, sizeof(*done));
! 795: size_t cursor;
! 796:
! 797: done->nopts = 0;
! 798: done->maxopts = 64;
! 799: cursor = done->maxopts * sizeof(*done->opts);
! 800: /*@-boundswrite@*/
! 801: done->opts = memset(alloca(cursor), 0, cursor);
! 802: /*@-keeptrans@*/
! 803: done->opts[done->nopts++] = (const void *) con->options;
! 804: /*@=keeptrans@*/
! 805: /*@=boundswrite@*/
! 806:
! 807: cursor = showHelpIntro(con, fp);
! 808: cursor += showShortOptions(con->options, fp, NULL);
! 809: cursor = singleTableUsage(con, fp, cursor, con->options, NULL, done);
! 810: cursor = itemUsage(fp, cursor, con->aliases, con->numAliases, NULL);
! 811: cursor = itemUsage(fp, cursor, con->execs, con->numExecs, NULL);
! 812:
! 813: if (con->otherHelp) {
! 814: cursor += strlen(con->otherHelp) + 1;
! 815: if (cursor > 79) fprintf(fp, "\n ");
! 816: fprintf(fp, " %s", con->otherHelp);
! 817: }
! 818:
! 819: fprintf(fp, "\n");
! 820: }
! 821:
! 822: void poptSetOtherOptionHelp(poptContext con, const char * text)
! 823: {
! 824: con->otherHelp = _free(con->otherHelp);
! 825: con->otherHelp = xstrdup(text);
! 826: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>