popthelp.c

Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
00002 
00007 /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
00008    file accompanying popt source distributions, available from 
00009    ftp://ftp.rpm.org/pub/rpm/dist. */
00010 
00011 #include "system.h"
00012 
00013 #define POPT_USE_TIOCGWINSZ
00014 #ifdef  POPT_USE_TIOCGWINSZ
00015 #include <sys/ioctl.h>
00016 #endif
00017 
00018 #define POPT_WCHAR_HACK
00019 #ifdef  POPT_WCHAR_HACK
00020 #include <wchar.h>                      /* for mbsrtowcs */
00021 /*@access mbstate_t @*/
00022 #endif
00023 #include "poptint.h"
00024 
00025 /*@access poptContext@*/
00026 
00035 /*@exits@*/
00036 static void displayArgs(poptContext con,
00037                 /*@unused@*/ enum poptCallbackReason foo,
00038                 struct poptOption * key, 
00039                 /*@unused@*/ const char * arg, /*@unused@*/ void * data)
00040         /*@globals fileSystem@*/
00041         /*@modifies con, fileSystem@*/
00042 {
00043     if (key->shortName == '?')
00044         poptPrintHelp(con, stdout, 0);
00045     else
00046         poptPrintUsage(con, stdout, 0);
00047 /*@i@*/ con = poptFreeContext(con);             /* XXX keep valgrind happy */
00048     exit(0);
00049 }
00050 
00051 #ifdef  NOTYET
00052 /*@unchecked@*/
00053 static int show_option_defaults = 0;
00054 #endif
00055 
00059 /*@observer@*/ /*@unchecked@*/
00060 struct poptOption poptAliasOptions[] = {
00061     POPT_TABLEEND
00062 };
00063 
00067 /*@-castfcnptr@*/
00068 /*@observer@*/ /*@unchecked@*/
00069 struct poptOption poptHelpOptions[] = {
00070   { NULL, '\0', POPT_ARG_CALLBACK, (void *)displayArgs, 0, NULL, NULL },
00071   { "help", '?', 0, NULL, (int)'?', N_("Show this help message"), NULL },
00072   { "usage", '\0', 0, NULL, (int)'u', N_("Display brief usage message"), NULL },
00073     POPT_TABLEEND
00074 } ;
00075 
00076 /*@observer@*/ /*@unchecked@*/
00077 static struct poptOption poptHelpOptions2[] = {
00078 /*@-readonlytrans@*/
00079   { NULL, '\0', POPT_ARG_INTL_DOMAIN, PACKAGE, 0, NULL, NULL},
00080 /*@=readonlytrans@*/
00081   { NULL, '\0', POPT_ARG_CALLBACK, (void *)displayArgs, 0, NULL, NULL },
00082   { "help", '?', 0, NULL, (int)'?', N_("Show this help message"), NULL },
00083   { "usage", '\0', 0, NULL, (int)'u', N_("Display brief usage message"), NULL },
00084 #ifdef  NOTYET
00085   { "defaults", '\0', POPT_ARG_NONE, &show_option_defaults, 0,
00086         N_("Display option defaults in message"), NULL },
00087 #endif
00088     POPT_TABLEEND
00089 } ;
00090 
00091 /*@observer@*/ /*@unchecked@*/
00092 struct poptOption * poptHelpOptionsI18N = poptHelpOptions2;
00093 /*@=castfcnptr@*/
00094 
00095 #define _POPTHELP_MAXLINE       ((size_t)79)
00096 
00097 typedef struct columns_s {
00098     size_t cur;
00099     size_t max;
00100 } * columns_t;
00101 
00107 static size_t maxColumnWidth(FILE *fp)
00108         /*@*/
00109 {
00110     size_t maxcols = _POPTHELP_MAXLINE;
00111 #if defined(TIOCGWINSZ)
00112     struct winsize ws;
00113     int fdno = fileno(fp ? fp : stdout);
00114 
00115     if (fdno >= 0 && !ioctl(fdno, TIOCGWINSZ, &ws)
00116      && ws.ws_col > maxcols && ws.ws_col < 256)
00117         maxcols = ws.ws_col - 1;
00118 #endif
00119     return maxcols;
00120 }
00121 
00125 /*@observer@*/ /*@null@*/ static const char *
00126 getTableTranslationDomain(/*@null@*/ const struct poptOption *table)
00127         /*@*/
00128 {
00129     const struct poptOption *opt;
00130 
00131     if (table != NULL)
00132     for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) {
00133         if (opt->argInfo == POPT_ARG_INTL_DOMAIN)
00134             return opt->arg;
00135     }
00136     return NULL;
00137 }
00138 
00143 /*@observer@*/ /*@null@*/ static const char *
00144 getArgDescrip(const struct poptOption * opt,
00145                 /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */
00146                 /*@null@*/ const char * translation_domain)
00147                 /*@=paramuse@*/
00148         /*@*/
00149 {
00150     if (!(opt->argInfo & POPT_ARG_MASK)) return NULL;
00151 
00152     if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_MAINCALL)
00153         return opt->argDescrip;
00154 
00155     if (opt->argDescrip) {
00156         /* Some strings need popt library, not application, i18n domain. */
00157         if (opt == (poptHelpOptions + 1)
00158          || opt == (poptHelpOptions + 2)
00159          || !strcmp(opt->argDescrip,N_("Help options:"))
00160          || !strcmp(opt->argDescrip,N_("Options implemented via popt alias/exec:")))
00161             return POPT_(opt->argDescrip);
00162 
00163         /* Use the application i18n domain. */
00164         return D_(translation_domain, opt->argDescrip);
00165     }
00166 
00167     switch (opt->argInfo & POPT_ARG_MASK) {
00168     case POPT_ARG_NONE:         return POPT_("NONE");
00169 #ifdef  DYING
00170     case POPT_ARG_VAL:          return POPT_("VAL");
00171 #else
00172     case POPT_ARG_VAL:          return NULL;
00173 #endif
00174     case POPT_ARG_INT:          return POPT_("INT");
00175     case POPT_ARG_LONG:         return POPT_("LONG");
00176     case POPT_ARG_STRING:       return POPT_("STRING");
00177     case POPT_ARG_FLOAT:        return POPT_("FLOAT");
00178     case POPT_ARG_DOUBLE:       return POPT_("DOUBLE");
00179     case POPT_ARG_MAINCALL:     return NULL;
00180     default:                    return POPT_("ARG");
00181     }
00182 }
00183 
00191 static /*@only@*/ /*@null@*/ char *
00192 singleOptionDefaultValue(size_t lineLength,
00193                 const struct poptOption * opt,
00194                 /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */
00195                 /*@null@*/ const char * translation_domain)
00196                 /*@=paramuse@*/
00197         /*@*/
00198 {
00199     const char * defstr = D_(translation_domain, "default");
00200     char * le = malloc(4*lineLength + 1);
00201     char * l = le;
00202 
00203     if (le == NULL) return NULL;        /* XXX can't happen */
00204 /*@-boundswrite@*/
00205     *le = '\0';
00206     *le++ = '(';
00207     strcpy(le, defstr); le += strlen(le);
00208     *le++ = ':';
00209     *le++ = ' ';
00210     if (opt->arg)       /* XXX programmer error */
00211     switch (opt->argInfo & POPT_ARG_MASK) {
00212     case POPT_ARG_VAL:
00213     case POPT_ARG_INT:
00214     {   long aLong = *((int *)opt->arg);
00215         le += sprintf(le, "%ld", aLong);
00216     }   break;
00217     case POPT_ARG_LONG:
00218     {   long aLong = *((long *)opt->arg);
00219         le += sprintf(le, "%ld", aLong);
00220     }   break;
00221     case POPT_ARG_FLOAT:
00222     {   double aDouble = *((float *)opt->arg);
00223         le += sprintf(le, "%g", aDouble);
00224     }   break;
00225     case POPT_ARG_DOUBLE:
00226     {   double aDouble = *((double *)opt->arg);
00227         le += sprintf(le, "%g", aDouble);
00228     }   break;
00229     case POPT_ARG_MAINCALL:
00230         le += sprintf(le, "%p", opt->arg);
00231         break;
00232     case POPT_ARG_STRING:
00233     {   const char * s = *(const char **)opt->arg;
00234         if (s == NULL) {
00235             strcpy(le, "null"); le += strlen(le);
00236         } else {
00237             size_t slen = 4*lineLength - (le - l) - sizeof("\"...\")");
00238             *le++ = '"';
00239             strncpy(le, s, slen); le[slen] = '\0'; le += strlen(le);    
00240             if (slen < strlen(s)) {
00241                 strcpy(le, "...");      le += strlen(le);
00242             }
00243             *le++ = '"';
00244         }
00245     }   break;
00246     case POPT_ARG_NONE:
00247     default:
00248         l = _free(l);
00249         return NULL;
00250         /*@notreached@*/ break;
00251     }
00252     *le++ = ')';
00253     *le = '\0';
00254 /*@=boundswrite@*/
00255 
00256     return l;
00257 }
00258 
00266 static void singleOptionHelp(FILE * fp, columns_t columns,
00267                 const struct poptOption * opt,
00268                 /*@null@*/ const char * translation_domain)
00269         /*@globals fileSystem @*/
00270         /*@modifies *fp, fileSystem @*/
00271 {
00272     size_t maxLeftCol = columns->cur;
00273     size_t indentLength = maxLeftCol + 5;
00274     size_t lineLength = columns->max - indentLength;
00275     const char * help = D_(translation_domain, opt->descrip);
00276     const char * argDescrip = getArgDescrip(opt, translation_domain);
00277     size_t helpLength;
00278     char * defs = NULL;
00279     char * left;
00280     size_t nb = maxLeftCol + 1;
00281     int displaypad = 0;
00282 
00283     /* Make sure there's more than enough room in target buffer. */
00284     if (opt->longName)  nb += strlen(opt->longName);
00285     if (argDescrip)     nb += strlen(argDescrip);
00286 
00287 /*@-boundswrite@*/
00288     left = malloc(nb);
00289     if (left == NULL) return;   /* XXX can't happen */
00290     left[0] = '\0';
00291     left[maxLeftCol] = '\0';
00292 
00293     if (opt->longName && opt->shortName)
00294         sprintf(left, "-%c, %s%s", opt->shortName,
00295                 ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
00296                 opt->longName);
00297     else if (opt->shortName != '\0') 
00298         sprintf(left, "-%c", opt->shortName);
00299     else if (opt->longName)
00300         sprintf(left, "%s%s",
00301                 ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_MAINCALL ? "" :
00302                 ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--")),
00303                 opt->longName);
00304     if (!*left) goto out;
00305 
00306     if (argDescrip) {
00307         char * le = left + strlen(left);
00308 
00309         if (opt->argInfo & POPT_ARGFLAG_OPTIONAL)
00310             *le++ = '[';
00311 
00312         /* Choose type of output */
00313 /*@-branchstate@*/
00314         if (opt->argInfo & POPT_ARGFLAG_SHOW_DEFAULT) {
00315             defs = singleOptionDefaultValue(lineLength, opt, translation_domain);
00316             if (defs) {
00317                 char * t = malloc((help ? strlen(help) : 0) +
00318                                 strlen(defs) + sizeof(" "));
00319                 if (t) {
00320                     char * te = t;
00321                     *te = '\0';
00322                     if (help) {
00323                         strcpy(te, help);       te += strlen(te);
00324                     }
00325                     *te++ = ' ';
00326                     strcpy(te, defs);
00327                     defs = _free(defs);
00328                 }
00329                 defs = t;
00330             }
00331         }
00332 /*@=branchstate@*/
00333 
00334         if (opt->argDescrip == NULL) {
00335             switch (opt->argInfo & POPT_ARG_MASK) {
00336             case POPT_ARG_NONE:
00337                 break;
00338             case POPT_ARG_VAL:
00339 #ifdef  NOTNOW  /* XXX pug ugly nerdy output */
00340             {   long aLong = opt->val;
00341                 int ops = (opt->argInfo & POPT_ARGFLAG_LOGICALOPS);
00342                 int negate = (opt->argInfo & POPT_ARGFLAG_NOT);
00343 
00344                 /* Don't bother displaying typical values */
00345                 if (!ops && (aLong == 0L || aLong == 1L || aLong == -1L))
00346                     break;
00347                 *le++ = '[';
00348                 switch (ops) {
00349                 case POPT_ARGFLAG_OR:
00350                     *le++ = '|';
00351                     /*@innerbreak@*/ break;
00352                 case POPT_ARGFLAG_AND:
00353                     *le++ = '&';
00354                     /*@innerbreak@*/ break;
00355                 case POPT_ARGFLAG_XOR:
00356                     *le++ = '^';
00357                     /*@innerbreak@*/ break;
00358                 default:
00359                     /*@innerbreak@*/ break;
00360                 }
00361                 *le++ = (opt->longName != NULL ? '=' : ' ');
00362                 if (negate) *le++ = '~';
00363                 /*@-formatconst@*/
00364                 le += sprintf(le, (ops ? "0x%lx" : "%ld"), aLong);
00365                 /*@=formatconst@*/
00366                 *le++ = ']';
00367             }
00368 #endif
00369                 break;
00370             case POPT_ARG_INT:
00371             case POPT_ARG_LONG:
00372             case POPT_ARG_FLOAT:
00373             case POPT_ARG_DOUBLE:
00374             case POPT_ARG_STRING:
00375                 *le++ = (opt->longName != NULL ? '=' : ' ');
00376                 strcpy(le, argDescrip);         le += strlen(le);
00377                 break;
00378             default:
00379                 break;
00380             }
00381         } else {
00382             size_t lelen;
00383 
00384             *le++ = ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_MAINCALL)
00385                 ? ' ' : '=';
00386             strcpy(le, argDescrip);
00387             lelen = strlen(le);
00388             le += lelen;
00389 
00390 #ifdef  POPT_WCHAR_HACK
00391             {   const char * scopy = argDescrip;
00392                 mbstate_t t;
00393                 size_t n;
00394 
00395                 memset ((void *)&t, 0, sizeof (t));     /* In initial state.  */
00396                 /* Determine number of characters.  */
00397                 n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t);
00398 
00399                 displaypad = (int) (lelen-n);
00400             }
00401 #endif
00402         }
00403         if (opt->argInfo & POPT_ARGFLAG_OPTIONAL)
00404             *le++ = ']';
00405         *le = '\0';
00406     }
00407 /*@=boundswrite@*/
00408 
00409     if (help)
00410         fprintf(fp,"  %-*s   ", (int)(maxLeftCol+displaypad), left);
00411     else {
00412         fprintf(fp,"  %s\n", left); 
00413         goto out;
00414     }
00415 
00416     left = _free(left);
00417 /*@-branchstate@*/
00418     if (defs) {
00419         help = defs;
00420     }
00421 
00422     helpLength = strlen(help);
00423 /*@-boundsread@*/
00424     while (helpLength > lineLength) {
00425         const char * ch;
00426         char format[16];
00427 
00428         ch = help + lineLength - 1;
00429         while (ch > help && !isspace(*ch)) ch--;
00430         if (ch == help) break;          /* give up */
00431         while (ch > (help + 1) && isspace(*ch)) ch--;
00432         ch++;
00433 
00434         sprintf(format, "%%.%ds\n%%%ds", (int) (ch - help), (int) indentLength);
00435         /*@-formatconst@*/
00436         fprintf(fp, format, help, " ");
00437         /*@=formatconst@*/
00438         help = ch;
00439         while (isspace(*help) && *help) help++;
00440         helpLength = strlen(help);
00441     }
00442 /*@=boundsread@*/
00443 /*@=branchstate@*/
00444 
00445     if (helpLength) fprintf(fp, "%s\n", help);
00446     help = NULL;
00447 
00448 out:
00449     /*@-dependenttrans@*/
00450     defs = _free(defs);
00451     /*@=dependenttrans@*/
00452     left = _free(left);
00453 }
00454 
00461 static size_t maxArgWidth(const struct poptOption * opt,
00462                        /*@null@*/ const char * translation_domain)
00463         /*@*/
00464 {
00465     size_t max = 0;
00466     size_t len = 0;
00467     const char * s;
00468     
00469     if (opt != NULL)
00470     while (opt->longName || opt->shortName || opt->arg) {
00471         if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
00472             if (opt->arg)       /* XXX program error */
00473                 len = maxArgWidth(opt->arg, translation_domain);
00474             if (len > max) max = len;
00475         } else if (!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
00476             len = sizeof("  ")-1;
00477             if (opt->shortName != '\0') len += sizeof("-X")-1;
00478             if (opt->shortName != '\0' && opt->longName) len += sizeof(", ")-1;
00479             if (opt->longName) {
00480                 len += ((opt->argInfo & POPT_ARGFLAG_ONEDASH)
00481                         ? sizeof("-")-1 : sizeof("--")-1);
00482                 len += strlen(opt->longName);
00483             }
00484 
00485             s = getArgDescrip(opt, translation_domain);
00486 
00487 #ifdef POPT_WCHAR_HACK
00488             /* XXX Calculate no. of display characters. */
00489             if (s) {
00490                 const char * scopy = s;
00491                 mbstate_t t;
00492                 size_t n;
00493 
00494 /*@-boundswrite@*/
00495                 memset ((void *)&t, 0, sizeof (t));     /* In initial state.  */
00496 /*@=boundswrite@*/
00497                 /* Determine number of characters.  */
00498                 n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t);
00499                 len += sizeof("=")-1 + n;
00500             }
00501 #else
00502             if (s)
00503                 len += sizeof("=")-1 + strlen(s);
00504 #endif
00505 
00506             if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) len += sizeof("[]")-1;
00507             if (len > max) max = len;
00508         }
00509 
00510         opt++;
00511     }
00512     
00513     return max;
00514 }
00515 
00524 static void itemHelp(FILE * fp,
00525                 /*@null@*/ poptItem items, int nitems,
00526                 columns_t columns,
00527                 /*@null@*/ const char * translation_domain)
00528         /*@globals fileSystem @*/
00529         /*@modifies *fp, fileSystem @*/
00530 {
00531     poptItem item;
00532     int i;
00533 
00534     if (items != NULL)
00535     for (i = 0, item = items; i < nitems; i++, item++) {
00536         const struct poptOption * opt;
00537         opt = &item->option;
00538         if ((opt->longName || opt->shortName) && 
00539             !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
00540             singleOptionHelp(fp, columns, opt, translation_domain);
00541     }
00542 }
00543 
00552 static void singleTableHelp(poptContext con, FILE * fp,
00553                 /*@null@*/ const struct poptOption * table,
00554                 columns_t columns,
00555                 /*@null@*/ const char * translation_domain)
00556         /*@globals fileSystem @*/
00557         /*@modifies *fp, fileSystem @*/
00558 {
00559     const struct poptOption * opt;
00560     const char *sub_transdom;
00561 
00562     if (table == poptAliasOptions) {
00563         itemHelp(fp, con->aliases, con->numAliases, columns, NULL);
00564         itemHelp(fp, con->execs, con->numExecs, columns, NULL);
00565         return;
00566     }
00567 
00568     if (table != NULL)
00569     for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) {
00570         if ((opt->longName || opt->shortName) && 
00571             !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
00572             singleOptionHelp(fp, columns, opt, translation_domain);
00573     }
00574 
00575     if (table != NULL)
00576     for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) {
00577         if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_INCLUDE_TABLE)
00578             continue;
00579         sub_transdom = getTableTranslationDomain(opt->arg);
00580         if (sub_transdom == NULL)
00581             sub_transdom = translation_domain;
00582             
00583         if (opt->descrip)
00584             POPT_fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip));
00585 
00586         singleTableHelp(con, fp, opt->arg, columns, sub_transdom);
00587     }
00588 }
00589 
00594 static size_t showHelpIntro(poptContext con, FILE * fp)
00595         /*@globals fileSystem @*/
00596         /*@modifies *fp, fileSystem @*/
00597 {
00598     size_t len = (size_t)6;
00599     const char * fn;
00600 
00601     fprintf(fp, POPT_("Usage:"));
00602     if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) {
00603 /*@-boundsread@*/
00604 /*@-type@*/     /* LCL: wazzup? */
00605         fn = con->optionStack->argv[0];
00606 /*@=type@*/
00607 /*@=boundsread@*/
00608         if (fn == NULL) return len;
00609         if (strchr(fn, '/')) fn = strrchr(fn, '/') + 1;
00610         fprintf(fp, " %s", fn);
00611         len += strlen(fn) + 1;
00612     }
00613 
00614     return len;
00615 }
00616 
00617 void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ int flags)
00618 {
00619     columns_t columns = memset(alloca(sizeof(*columns)), 0, sizeof(*columns));
00620 
00621     (void) showHelpIntro(con, fp);
00622     if (con->otherHelp)
00623         fprintf(fp, " %s\n", con->otherHelp);
00624     else
00625         fprintf(fp, " %s\n", POPT_("[OPTION...]"));
00626 
00627     columns->cur = maxArgWidth(con->options, NULL);
00628     columns->max = maxColumnWidth(fp);
00629     singleTableHelp(con, fp, con->options, columns, NULL);
00630 }
00631 
00639 static size_t singleOptionUsage(FILE * fp, columns_t columns,
00640                 const struct poptOption * opt,
00641                 /*@null@*/ const char *translation_domain)
00642         /*@globals fileSystem @*/
00643         /*@modifies *fp, fileSystem @*/
00644 {
00645     size_t len = (size_t)4;
00646     char shortStr[2] = { '\0', '\0' };
00647     const char * item = shortStr;
00648     const char * argDescrip = getArgDescrip(opt, translation_domain);
00649     int bingo = 0;
00650 
00651     if (opt->shortName != '\0' && opt->longName != NULL) {
00652         len += 2;
00653         if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++;
00654         len += strlen(opt->longName);
00655         bingo++;
00656     } else if (opt->shortName != '\0') {
00657         len++;
00658         shortStr[0] = opt->shortName;
00659         shortStr[1] = '\0';
00660         bingo++;
00661     } else if (opt->longName) {
00662         len += strlen(opt->longName);
00663         if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++;
00664         item = opt->longName;
00665         bingo++;
00666     }
00667 
00668     if (!bingo) return columns->cur;
00669 
00670 #ifdef POPT_WCHAR_HACK
00671     /* XXX Calculate no. of display characters. */
00672     if (argDescrip) {
00673         const char * scopy = argDescrip;
00674         mbstate_t t;
00675         size_t n;
00676 
00677 /*@-boundswrite@*/
00678         memset ((void *)&t, 0, sizeof (t));     /* In initial state.  */
00679 /*@=boundswrite@*/
00680         /* Determine number of characters.  */
00681         n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t);
00682         len += sizeof("=")-1 + n;
00683     }
00684 #else
00685     if (argDescrip) 
00686         len += sizeof("=")-1 + strlen(argDescrip);
00687 #endif
00688 
00689     if ((columns->cur + len) > columns->max) {
00690         fprintf(fp, "\n       ");
00691         columns->cur = (size_t)7;
00692     } 
00693 
00694     if (opt->longName && opt->shortName) {
00695         fprintf(fp, " [-%c|-%s%s%s%s]",
00696             opt->shortName, ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "" : "-"),
00697             opt->longName,
00698             (argDescrip ? " " : ""),
00699             (argDescrip ? argDescrip : ""));
00700     } else {
00701         fprintf(fp, " [-%s%s%s%s]",
00702             ((opt->shortName || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) ? "" : "-"),
00703             item,
00704             (argDescrip ? (opt->shortName != '\0' ? " " : "=") : ""),
00705             (argDescrip ? argDescrip : ""));
00706     }
00707 
00708     return columns->cur + len + 1;
00709 }
00710 
00719 static size_t itemUsage(FILE * fp, columns_t columns,
00720                 /*@null@*/ poptItem item, int nitems,
00721                 /*@null@*/ const char * translation_domain)
00722         /*@globals fileSystem @*/
00723         /*@modifies *fp, fileSystem @*/
00724 {
00725     int i;
00726 
00727 /*@-branchstate@*/              /* FIX: W2DO? */
00728     if (item != NULL)
00729     for (i = 0; i < nitems; i++, item++) {
00730         const struct poptOption * opt;
00731         opt = &item->option;
00732         if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) {
00733             translation_domain = (const char *)opt->arg;
00734         } else if ((opt->longName || opt->shortName) &&
00735                  !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
00736             columns->cur = singleOptionUsage(fp, columns, opt, translation_domain);
00737         }
00738     }
00739 /*@=branchstate@*/
00740 
00741     return columns->cur;
00742 }
00743 
00747 typedef struct poptDone_s {
00748     int nopts;
00749     int maxopts;
00750     const void ** opts;
00751 } * poptDone;
00752 
00763 static size_t singleTableUsage(poptContext con, FILE * fp, columns_t columns,
00764                 /*@null@*/ const struct poptOption * opt,
00765                 /*@null@*/ const char * translation_domain,
00766                 /*@null@*/ poptDone done)
00767         /*@globals fileSystem @*/
00768         /*@modifies *fp, done, fileSystem @*/
00769 {
00770 /*@-branchstate@*/              /* FIX: W2DO? */
00771     if (opt != NULL)
00772     for (; (opt->longName || opt->shortName || opt->arg) ; opt++) {
00773         if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) {
00774             translation_domain = (const char *)opt->arg;
00775         } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
00776             if (done) {
00777                 int i = 0;
00778                 for (i = 0; i < done->nopts; i++) {
00779 /*@-boundsread@*/
00780                     const void * that = done->opts[i];
00781 /*@=boundsread@*/
00782                     if (that == NULL || that != opt->arg)
00783                         /*@innercontinue@*/ continue;
00784                     /*@innerbreak@*/ break;
00785                 }
00786                 /* Skip if this table has already been processed. */
00787                 if (opt->arg == NULL || i < done->nopts)
00788                     continue;
00789 /*@-boundswrite@*/
00790                 if (done->nopts < done->maxopts)
00791                     done->opts[done->nopts++] = (const void *) opt->arg;
00792 /*@=boundswrite@*/
00793             }
00794             columns->cur = singleTableUsage(con, fp, columns, opt->arg,
00795                         translation_domain, done);
00796         } else if ((opt->longName || opt->shortName) &&
00797                  !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
00798             columns->cur = singleOptionUsage(fp, columns, opt, translation_domain);
00799         }
00800     }
00801 /*@=branchstate@*/
00802 
00803     return columns->cur;
00804 }
00805 
00814 static size_t showShortOptions(const struct poptOption * opt, FILE * fp,
00815                 /*@null@*/ char * str)
00816         /*@globals fileSystem @*/
00817         /*@modifies *str, *fp, fileSystem @*/
00818         /*@requires maxRead(str) >= 0 @*/
00819 {
00820     /* bufsize larger then the ascii set, lazy allocation on top level call. */
00821     size_t nb = (size_t)300;
00822     char * s = (str != NULL ? str : calloc(1, nb));
00823     size_t len = (size_t)0;
00824 
00825     if (s == NULL)
00826         return 0;
00827 
00828 /*@-boundswrite@*/
00829     if (opt != NULL)
00830     for (; (opt->longName || opt->shortName || opt->arg); opt++) {
00831         if (opt->shortName && !(opt->argInfo & POPT_ARG_MASK))
00832             s[strlen(s)] = opt->shortName;
00833         else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE)
00834             if (opt->arg)       /* XXX program error */
00835                 len = showShortOptions(opt->arg, fp, s);
00836     } 
00837 /*@=boundswrite@*/
00838 
00839     /* On return to top level, print the short options, return print length. */
00840     if (s != str && *s != '\0') {
00841         fprintf(fp, " [-%s]", s);
00842         len = strlen(s) + sizeof(" [-]")-1;
00843     }
00844     if (s != str)
00845         free(s);
00846     return len;
00847 }
00848 
00849 void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ int flags)
00850 {
00851     columns_t columns = memset(alloca(sizeof(*columns)), 0, sizeof(*columns));
00852     struct poptDone_s done_buf;
00853     poptDone done = &done_buf;
00854 
00855     memset(done, 0, sizeof(*done));
00856     done->nopts = 0;
00857     done->maxopts = 64;
00858     columns->cur = done->maxopts * sizeof(*done->opts);
00859     columns->max = maxColumnWidth(fp);
00860 /*@-boundswrite@*/
00861     done->opts = calloc(1, columns->cur);
00862     /*@-keeptrans@*/
00863     done->opts[done->nopts++] = (const void *) con->options;
00864     /*@=keeptrans@*/
00865 /*@=boundswrite@*/
00866 
00867     columns->cur = showHelpIntro(con, fp);
00868     columns->cur += showShortOptions(con->options, fp, NULL);
00869     columns->cur = singleTableUsage(con, fp, columns, con->options, NULL, done);
00870     columns->cur = itemUsage(fp, columns, con->aliases, con->numAliases, NULL);
00871     columns->cur = itemUsage(fp, columns, con->execs, con->numExecs, NULL);
00872 
00873     if (con->otherHelp) {
00874         columns->cur += strlen(con->otherHelp) + 1;
00875         if (columns->cur > columns->max) fprintf(fp, "\n       ");
00876         fprintf(fp, " %s", con->otherHelp);
00877     }
00878 
00879     fprintf(fp, "\n");
00880     free(done->opts);
00881 }
00882 
00883 void poptSetOtherOptionHelp(poptContext con, const char * text)
00884 {
00885     con->otherHelp = _free(con->otherHelp);
00886     con->otherHelp = xstrdup(text);
00887 }

Generated on Thu Aug 30 14:33:19 2007 for popt by  doxygen 1.5.2