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>