Annotation of embedaddon/rsync/popt/popthelp.c, revision 1.1.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>