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 
00024 
00025 #include "poptint.h"
00026 
00027 /*@access poptContext@*/
00028 
00037 /*@exits@*/
00038 static void displayArgs(poptContext con,
00039                 /*@unused@*/ enum poptCallbackReason foo,
00040                 struct poptOption * key, 
00041                 /*@unused@*/ const char * arg, /*@unused@*/ void * data)
00042         /*@globals fileSystem@*/
00043         /*@modifies con, fileSystem@*/
00044 {
00045     if (key->shortName == '?')
00046         poptPrintHelp(con, stdout, 0);
00047     else
00048         poptPrintUsage(con, stdout, 0);
00049 
00050 /*@i@*/ con = poptFreeContext(con);             /* XXX keep valgrind happy */
00051     exit(0);
00052 }
00053 
00054 #ifdef  NOTYET
00055 /*@unchecked@*/
00056 static int show_option_defaults = 0;
00057 #endif
00058 
00062 /*@observer@*/ /*@unchecked@*/
00063 struct poptOption poptAliasOptions[] = {
00064     POPT_TABLEEND
00065 };
00066 
00070 /*@-castfcnptr@*/
00071 /*@observer@*/ /*@unchecked@*/
00072 struct poptOption poptHelpOptions[] = {
00073   { NULL, '\0', POPT_ARG_CALLBACK, (void *)displayArgs, 0, NULL, NULL },
00074   { "help", '?', 0, NULL, (int)'?', N_("Show this help message"), NULL },
00075   { "usage", '\0', 0, NULL, (int)'u', N_("Display brief usage message"), NULL },
00076     POPT_TABLEEND
00077 } ;
00078 
00079 /*@observer@*/ /*@unchecked@*/
00080 static struct poptOption poptHelpOptions2[] = {
00081 /*@-readonlytrans@*/
00082   { NULL, '\0', POPT_ARG_INTL_DOMAIN, PACKAGE, 0, NULL, NULL},
00083 /*@=readonlytrans@*/
00084   { NULL, '\0', POPT_ARG_CALLBACK, (void *)displayArgs, 0, NULL, NULL },
00085   { "help", '?', 0, NULL, (int)'?', N_("Show this help message"), NULL },
00086   { "usage", '\0', 0, NULL, (int)'u', N_("Display brief usage message"), NULL },
00087 #ifdef  NOTYET
00088   { "defaults", '\0', POPT_ARG_NONE, &show_option_defaults, 0,
00089         N_("Display option defaults in message"), NULL },
00090 #endif
00091     POPT_TABLEEND
00092 } ;
00093 
00094 /*@observer@*/ /*@unchecked@*/
00095 struct poptOption * poptHelpOptionsI18N = poptHelpOptions2;
00096 /*@=castfcnptr@*/
00097 
00098 #define _POPTHELP_MAXLINE       ((size_t)79)
00099 
00100 typedef struct columns_s {
00101     size_t cur;
00102     size_t max;
00103 } * columns_t;
00104 
00110 static size_t maxColumnWidth(FILE *fp)
00111         /*@*/
00112 {
00113     size_t maxcols = _POPTHELP_MAXLINE;
00114 #if defined(TIOCGWINSZ)
00115     struct winsize ws;
00116     int fdno = fileno(fp ? fp : stdout);
00117 
00118     memset(&ws, 0, sizeof(ws));
00119     if (fdno >= 0 && !ioctl(fdno, TIOCGWINSZ, &ws)
00120      && (size_t)ws.ws_col > maxcols && ws.ws_col < 256)
00121         maxcols = ws.ws_col - 1;
00122 #endif
00123     return maxcols;
00124 }
00125 
00129 /*@observer@*/ /*@null@*/ static const char *
00130 getTableTranslationDomain(/*@null@*/ const struct poptOption *table)
00131         /*@*/
00132 {
00133     const struct poptOption *opt;
00134 
00135     if (table != NULL)
00136     for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) {
00137         if (opt->argInfo == POPT_ARG_INTL_DOMAIN)
00138             return opt->arg;
00139     }
00140     return NULL;
00141 }
00142 
00147 /*@observer@*/ /*@null@*/ static const char *
00148 getArgDescrip(const struct poptOption * opt,
00149                 /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */
00150                 /*@null@*/ const char * translation_domain)
00151                 /*@=paramuse@*/
00152         /*@*/
00153 {
00154     if (!(opt->argInfo & POPT_ARG_MASK)) return NULL;
00155 
00156     if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_MAINCALL)
00157         return opt->argDescrip;
00158 
00159     if (opt->argDescrip) {
00160         /* Some strings need popt library, not application, i18n domain. */
00161         if (opt == (poptHelpOptions + 1)
00162          || opt == (poptHelpOptions + 2)
00163          || !strcmp(opt->argDescrip,N_("Help options:"))
00164          || !strcmp(opt->argDescrip,N_("Options implemented via popt alias/exec:")))
00165             return POPT_(opt->argDescrip);
00166 
00167         /* Use the application i18n domain. */
00168         return D_(translation_domain, opt->argDescrip);
00169     }
00170 
00171     switch (opt->argInfo & POPT_ARG_MASK) {
00172     case POPT_ARG_NONE:         return POPT_("NONE");
00173 #ifdef  DYING
00174     case POPT_ARG_VAL:          return POPT_("VAL");
00175 #else
00176     case POPT_ARG_VAL:          return NULL;
00177 #endif
00178     case POPT_ARG_INT:          return POPT_("INT");
00179     case POPT_ARG_LONG:         return POPT_("LONG");
00180     case POPT_ARG_STRING:       return POPT_("STRING");
00181     case POPT_ARG_FLOAT:        return POPT_("FLOAT");
00182     case POPT_ARG_DOUBLE:       return POPT_("DOUBLE");
00183     case POPT_ARG_MAINCALL:     return NULL;
00184     default:                    return POPT_("ARG");
00185     }
00186 }
00187 
00195 static /*@only@*/ /*@null@*/ char *
00196 singleOptionDefaultValue(size_t lineLength,
00197                 const struct poptOption * opt,
00198                 /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */
00199                 /*@null@*/ const char * translation_domain)
00200                 /*@=paramuse@*/
00201         /*@*/
00202 {
00203     const char * defstr = D_(translation_domain, "default");
00204     char * le = malloc(4*lineLength + 1);
00205     char * l = le;
00206 
00207     if (le == NULL) return NULL;        /* XXX can't happen */
00208     *le = '\0';
00209     *le++ = '(';
00210     strcpy(le, defstr); le += strlen(le);
00211     *le++ = ':';
00212     *le++ = ' ';
00213     if (opt->arg)       /* XXX programmer error */
00214     switch (opt->argInfo & POPT_ARG_MASK) {
00215     case POPT_ARG_VAL:
00216     case POPT_ARG_INT:
00217     {   long aLong = *((int *)opt->arg);
00218         le += sprintf(le, "%ld", aLong);
00219     }   break;
00220     case POPT_ARG_LONG:
00221     {   long aLong = *((long *)opt->arg);
00222         le += sprintf(le, "%ld", aLong);
00223     }   break;
00224     case POPT_ARG_FLOAT:
00225     {   double aDouble = *((float *)opt->arg);
00226         le += sprintf(le, "%g", aDouble);
00227     }   break;
00228     case POPT_ARG_DOUBLE:
00229     {   double aDouble = *((double *)opt->arg);
00230         le += sprintf(le, "%g", aDouble);
00231     }   break;
00232     case POPT_ARG_MAINCALL:
00233         le += sprintf(le, "%p", opt->arg);
00234         break;
00235     case POPT_ARG_STRING:
00236     {   const char * s = *(const char **)opt->arg;
00237         if (s == NULL) {
00238             strcpy(le, "null"); le += strlen(le);
00239         } else {
00240             size_t slen = 4*lineLength - (le - l) - sizeof("\"...\")");
00241             *le++ = '"';
00242             strncpy(le, s, slen); le[slen] = '\0'; le += strlen(le);    
00243             if (slen < strlen(s)) {
00244                 strcpy(le, "...");      le += strlen(le);
00245             }
00246             *le++ = '"';
00247         }
00248     }   break;
00249     case POPT_ARG_NONE:
00250     default:
00251         l = _free(l);
00252         return NULL;
00253         /*@notreached@*/ break;
00254     }
00255     *le++ = ')';
00256     *le = '\0';
00257 
00258     return l;
00259 }
00260 
00268 static void singleOptionHelp(FILE * fp, columns_t columns,
00269                 const struct poptOption * opt,
00270                 /*@null@*/ const char * translation_domain)
00271         /*@globals fileSystem @*/
00272         /*@modifies fp, fileSystem @*/
00273 {
00274     size_t maxLeftCol = columns->cur;
00275     size_t indentLength = maxLeftCol + 5;
00276     size_t lineLength = columns->max - indentLength;
00277     const char * help = D_(translation_domain, opt->descrip);
00278     const char * argDescrip = getArgDescrip(opt, translation_domain);
00279     size_t helpLength;
00280     char * defs = NULL;
00281     char * left;
00282     size_t nb = maxLeftCol + 1;
00283     int displaypad = 0;
00284     int xx;
00285 
00286     /* Make sure there's more than enough room in target buffer. */
00287     if (opt->longName)  nb += strlen(opt->longName);
00288     if (argDescrip)     nb += strlen(argDescrip);
00289 
00290     left = malloc(nb);
00291     if (left == NULL) return;   /* XXX can't happen */
00292     left[0] = '\0';
00293     left[maxLeftCol] = '\0';
00294 
00295     if (opt->longName && opt->shortName)
00296         sprintf(left, "-%c, %s%s", opt->shortName,
00297                 ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
00298                 opt->longName);
00299     else if (opt->shortName != '\0') 
00300         sprintf(left, "-%c", opt->shortName);
00301     else if (opt->longName)
00302         sprintf(left, "%s%s",
00303                 ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_MAINCALL ? "" :
00304                 ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--")),
00305                 opt->longName);
00306     if (!*left) goto out;
00307 
00308     if (argDescrip) {
00309         char * le = left + strlen(left);
00310 
00311         if (opt->argInfo & POPT_ARGFLAG_OPTIONAL)
00312             *le++ = '[';
00313 
00314         /* Choose type of output */
00315         if (opt->argInfo & POPT_ARGFLAG_SHOW_DEFAULT) {
00316             defs = singleOptionDefaultValue(lineLength, opt, translation_domain);
00317             if (defs) {
00318                 char * t = malloc((help ? strlen(help) : 0) +
00319                                 strlen(defs) + sizeof(" "));
00320                 if (t) {
00321                     char * te = t;
00322                     *te = '\0';
00323                     if (help) {
00324                         strcpy(te, help);       te += strlen(te);
00325                     }
00326                     *te++ = ' ';
00327                     strcpy(te, defs);
00328                     defs = _free(defs);
00329                 }
00330                 defs = t;
00331             }
00332         }
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 
00408     if (help)
00409         xx = POPT_fprintf(fp,"  %-*s   ", (int)(maxLeftCol+displaypad), left);
00410     else {
00411         xx = POPT_fprintf(fp,"  %s\n", left); 
00412         goto out;
00413     }
00414 
00415     left = _free(left);
00416     if (defs) {
00417         help = defs;
00418     }
00419 
00420     helpLength = strlen(help);
00421     while (helpLength > lineLength) {
00422         const char * ch;
00423         char format[16];
00424 
00425         ch = help + lineLength - 1;
00426         while (ch > help && !_isspaceptr(ch))
00427             ch = POPT_prev_char (ch);
00428         if (ch == help) break;          /* give up */
00429         while (ch > (help + 1) && _isspaceptr(ch))
00430             ch = POPT_prev_char (ch);
00431         ch++;
00432 
00433         sprintf(format, "%%.%ds\n%%%ds", (int) (ch - help), (int) indentLength);
00434         /*@-formatconst@*/
00435         xx = POPT_fprintf(fp, format, help, " ");
00436         /*@=formatconst@*/
00437         help = ch;
00438         while (_isspaceptr(help) && *help) help++;
00439         helpLength = strlen(help);
00440     }
00441 
00442     if (helpLength) xx = POPT_fprintf(fp, "%s\n", help);
00443     help = NULL;
00444 
00445 out:
00446     /*@-dependenttrans@*/
00447     defs = _free(defs);
00448     /*@=dependenttrans@*/
00449     left = _free(left);
00450 }
00451 
00458 static size_t maxArgWidth(const struct poptOption * opt,
00459                        /*@null@*/ const char * translation_domain)
00460         /*@*/
00461 {
00462     size_t max = 0;
00463     size_t len = 0;
00464     const char * s;
00465     
00466     if (opt != NULL)
00467     while (opt->longName || opt->shortName || opt->arg) {
00468         if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
00469             if (opt->arg)       /* XXX program error */
00470                 len = maxArgWidth(opt->arg, translation_domain);
00471             if (len > max) max = len;
00472         } else if (!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
00473             len = sizeof("  ")-1;
00474             if (opt->shortName != '\0') len += sizeof("-X")-1;
00475             if (opt->shortName != '\0' && opt->longName) len += sizeof(", ")-1;
00476             if (opt->longName) {
00477                 len += ((opt->argInfo & POPT_ARGFLAG_ONEDASH)
00478                         ? sizeof("-")-1 : sizeof("--")-1);
00479                 len += strlen(opt->longName);
00480             }
00481 
00482             s = getArgDescrip(opt, translation_domain);
00483 
00484 #ifdef POPT_WCHAR_HACK
00485             /* XXX Calculate no. of display characters. */
00486             if (s) {
00487                 const char * scopy = s;
00488                 mbstate_t t;
00489                 size_t n;
00490 
00491                 memset ((void *)&t, 0, sizeof (t));     /* In initial state.  */
00492                 /* Determine number of characters.  */
00493                 n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t);
00494                 len += sizeof("=")-1 + n;
00495             }
00496 #else
00497             if (s)
00498                 len += sizeof("=")-1 + strlen(s);
00499 #endif
00500 
00501             if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) len += sizeof("[]")-1;
00502             if (len > max) max = len;
00503         }
00504 
00505         opt++;
00506     }
00507     
00508     return max;
00509 }
00510 
00519 static void itemHelp(FILE * fp,
00520                 /*@null@*/ poptItem items, int nitems,
00521                 columns_t columns,
00522                 /*@null@*/ const char * translation_domain)
00523         /*@globals fileSystem @*/
00524         /*@modifies fp, fileSystem @*/
00525 {
00526     poptItem item;
00527     int i;
00528 
00529     if (items != NULL)
00530     for (i = 0, item = items; i < nitems; i++, item++) {
00531         const struct poptOption * opt;
00532         opt = &item->option;
00533         if ((opt->longName || opt->shortName) && 
00534             !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
00535             singleOptionHelp(fp, columns, opt, translation_domain);
00536     }
00537 }
00538 
00547 static void singleTableHelp(poptContext con, FILE * fp,
00548                 /*@null@*/ const struct poptOption * table,
00549                 columns_t columns,
00550                 /*@null@*/ const char * translation_domain)
00551         /*@globals fileSystem @*/
00552         /*@modifies fp, columns->cur, fileSystem @*/
00553 {
00554     const struct poptOption * opt;
00555     const char *sub_transdom;
00556     int xx;
00557 
00558     if (table == poptAliasOptions) {
00559         itemHelp(fp, con->aliases, con->numAliases, columns, NULL);
00560         itemHelp(fp, con->execs, con->numExecs, columns, NULL);
00561         return;
00562     }
00563 
00564     if (table != NULL)
00565     for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) {
00566         if ((opt->longName || opt->shortName) && 
00567             !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
00568             singleOptionHelp(fp, columns, opt, translation_domain);
00569     }
00570 
00571     if (table != NULL)
00572     for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) {
00573         if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_INCLUDE_TABLE)
00574             continue;
00575         sub_transdom = getTableTranslationDomain(opt->arg);
00576         if (sub_transdom == NULL)
00577             sub_transdom = translation_domain;
00578             
00579         if (opt->descrip)
00580             xx = POPT_fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip));
00581 
00582         singleTableHelp(con, fp, opt->arg, columns, sub_transdom);
00583     }
00584 }
00585 
00590 static size_t showHelpIntro(poptContext con, FILE * fp)
00591         /*@globals fileSystem @*/
00592         /*@modifies *fp, fileSystem @*/
00593 {
00594     size_t len = (size_t)6;
00595     const char * fn;
00596 
00597     fprintf(fp, POPT_("Usage:"));
00598     if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) {
00599 /*@-type@*/     /* LCL: wazzup? */
00600         fn = con->optionStack->argv[0];
00601 /*@=type@*/
00602         if (fn == NULL) return len;
00603         if (strchr(fn, '/')) fn = strrchr(fn, '/') + 1;
00604         fprintf(fp, " %s", fn);
00605         len += strlen(fn) + 1;
00606     }
00607 
00608     return len;
00609 }
00610 
00611 void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ int flags)
00612 {
00613     columns_t columns = calloc(1, sizeof(*columns));
00614 
00615     (void) showHelpIntro(con, fp);
00616     if (con->otherHelp)
00617         fprintf(fp, " %s\n", con->otherHelp);
00618     else
00619         fprintf(fp, " %s\n", POPT_("[OPTION...]"));
00620 
00621     if (columns) {
00622         columns->cur = maxArgWidth(con->options, NULL);
00623         columns->max = maxColumnWidth(fp);
00624         singleTableHelp(con, fp, con->options, columns, NULL);
00625         free(columns);
00626     }
00627 }
00628 
00636 static size_t singleOptionUsage(FILE * fp, columns_t columns,
00637                 const struct poptOption * opt,
00638                 /*@null@*/ const char *translation_domain)
00639         /*@globals fileSystem @*/
00640         /*@modifies fp, columns->cur, fileSystem @*/
00641 {
00642     size_t len = (size_t)4;
00643     char shortStr[2] = { '\0', '\0' };
00644     const char * item = shortStr;
00645     const char * argDescrip = getArgDescrip(opt, translation_domain);
00646     int bingo = 0;
00647 
00648     if (opt->shortName != '\0' && opt->longName != NULL) {
00649         len += 2;
00650         if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++;
00651         len += strlen(opt->longName);
00652         bingo++;
00653     } else if (opt->shortName != '\0') {
00654         len++;
00655         shortStr[0] = opt->shortName;
00656         shortStr[1] = '\0';
00657         bingo++;
00658     } else if (opt->longName) {
00659         len += strlen(opt->longName);
00660         if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++;
00661         item = opt->longName;
00662         bingo++;
00663     }
00664 
00665     if (!bingo) return columns->cur;
00666 
00667 #ifdef POPT_WCHAR_HACK
00668     /* XXX Calculate no. of display characters. */
00669     if (argDescrip) {
00670         const char * scopy = argDescrip;
00671         mbstate_t t;
00672         size_t n;
00673 
00674         memset ((void *)&t, 0, sizeof (t));     /* In initial state.  */
00675         /* Determine number of characters.  */
00676         n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t);
00677         len += sizeof("=")-1 + n;
00678     }
00679 #else
00680     if (argDescrip) 
00681         len += sizeof("=")-1 + strlen(argDescrip);
00682 #endif
00683 
00684     if ((columns->cur + len) > columns->max) {
00685         fprintf(fp, "\n       ");
00686         columns->cur = (size_t)7;
00687     } 
00688 
00689     if (opt->longName && opt->shortName) {
00690         fprintf(fp, " [-%c|-%s%s%s%s]",
00691             opt->shortName, ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "" : "-"),
00692             opt->longName,
00693             (argDescrip ? " " : ""),
00694             (argDescrip ? argDescrip : ""));
00695     } else {
00696         fprintf(fp, " [-%s%s%s%s]",
00697             ((opt->shortName || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) ? "" : "-"),
00698             item,
00699             (argDescrip ? (opt->shortName != '\0' ? " " : "=") : ""),
00700             (argDescrip ? argDescrip : ""));
00701     }
00702 
00703     return columns->cur + len + 1;
00704 }
00705 
00714 static size_t itemUsage(FILE * fp, columns_t columns,
00715                 /*@null@*/ poptItem item, int nitems,
00716                 /*@null@*/ const char * translation_domain)
00717         /*@globals fileSystem @*/
00718         /*@modifies fp, columns->cur, fileSystem @*/
00719 {
00720     int i;
00721 
00722     if (item != NULL)
00723     for (i = 0; i < nitems; i++, item++) {
00724         const struct poptOption * opt;
00725         opt = &item->option;
00726         if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) {
00727             translation_domain = (const char *)opt->arg;
00728         } else if ((opt->longName || opt->shortName) &&
00729                  !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
00730             columns->cur = singleOptionUsage(fp, columns, opt, translation_domain);
00731         }
00732     }
00733 
00734     return columns->cur;
00735 }
00736 
00740 typedef struct poptDone_s {
00741     int nopts;
00742     int maxopts;
00743 /*@null@*/
00744     const void ** opts;
00745 } * poptDone;
00746 
00757 static size_t singleTableUsage(poptContext con, FILE * fp, columns_t columns,
00758                 /*@null@*/ const struct poptOption * opt,
00759                 /*@null@*/ const char * translation_domain,
00760                 /*@null@*/ poptDone done)
00761         /*@globals fileSystem @*/
00762         /*@modifies fp, columns->cur, done, fileSystem @*/
00763 {
00764     if (opt != NULL)
00765     for (; (opt->longName || opt->shortName || opt->arg) ; opt++) {
00766         if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) {
00767             translation_domain = (const char *)opt->arg;
00768         } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
00769             if (done) {
00770                 int i;
00771                 if (done->opts != NULL)
00772                 for (i = 0; i < done->nopts; i++) {
00773                     const void * that = done->opts[i];
00774                     if (that == NULL || that != opt->arg)
00775                         /*@innercontinue@*/ continue;
00776                     /*@innerbreak@*/ break;
00777                 }
00778                 /* Skip if this table has already been processed. */
00779                 if (opt->arg == NULL || i < done->nopts)
00780                     continue;
00781                 if (done->opts != NULL && done->nopts < done->maxopts)
00782                     done->opts[done->nopts++] = (const void *) opt->arg;
00783             }
00784             columns->cur = singleTableUsage(con, fp, columns, opt->arg,
00785                         translation_domain, done);
00786         } else if ((opt->longName || opt->shortName) &&
00787                  !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
00788             columns->cur = singleOptionUsage(fp, columns, opt, translation_domain);
00789         }
00790     }
00791 
00792     return columns->cur;
00793 }
00794 
00803 static size_t showShortOptions(const struct poptOption * opt, FILE * fp,
00804                 /*@null@*/ char * str)
00805         /*@globals fileSystem @*/
00806         /*@modifies str, *fp, fileSystem @*/
00807         /*@requires maxRead(str) >= 0 @*/
00808 {
00809     /* bufsize larger then the ascii set, lazy allocation on top level call. */
00810     size_t nb = (size_t)300;
00811     char * s = (str != NULL ? str : calloc(1, nb));
00812     size_t len = (size_t)0;
00813 
00814     if (s == NULL)
00815         return 0;
00816 
00817     if (opt != NULL)
00818     for (; (opt->longName || opt->shortName || opt->arg); opt++) {
00819         if (opt->shortName && !(opt->argInfo & POPT_ARG_MASK))
00820             s[strlen(s)] = opt->shortName;
00821         else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE)
00822             if (opt->arg)       /* XXX program error */
00823                 len = showShortOptions(opt->arg, fp, s);
00824     } 
00825 
00826     /* On return to top level, print the short options, return print length. */
00827     if (s != str && *s != '\0') {
00828         fprintf(fp, " [-%s]", s);
00829         len = strlen(s) + sizeof(" [-]")-1;
00830     }
00831 /*@-temptrans@*/        /* LCL: local s, not str arg, is being freed. */
00832     if (s != str)
00833         free(s);
00834 /*@=temptrans@*/
00835     return len;
00836 }
00837 
00838 void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ int flags)
00839 {
00840     columns_t columns = calloc(1, sizeof(*columns));
00841     struct poptDone_s done_buf;
00842     poptDone done = &done_buf;
00843 
00844     memset(done, 0, sizeof(*done));
00845     done->nopts = 0;
00846     done->maxopts = 64;
00847   if (columns) {
00848     columns->cur = done->maxopts * sizeof(*done->opts);
00849     columns->max = maxColumnWidth(fp);
00850     done->opts = calloc(1, columns->cur);
00851     /*@-keeptrans@*/
00852     if (done->opts != NULL)
00853         done->opts[done->nopts++] = (const void *) con->options;
00854     /*@=keeptrans@*/
00855 
00856     columns->cur = showHelpIntro(con, fp);
00857     columns->cur += showShortOptions(con->options, fp, NULL);
00858     columns->cur = singleTableUsage(con, fp, columns, con->options, NULL, done);
00859     columns->cur = itemUsage(fp, columns, con->aliases, con->numAliases, NULL);
00860     columns->cur = itemUsage(fp, columns, con->execs, con->numExecs, NULL);
00861 
00862     if (con->otherHelp) {
00863         columns->cur += strlen(con->otherHelp) + 1;
00864         if (columns->cur > columns->max) fprintf(fp, "\n       ");
00865         fprintf(fp, " %s", con->otherHelp);
00866     }
00867 
00868     fprintf(fp, "\n");
00869     if (done->opts != NULL)
00870         free(done->opts);
00871     free(columns);
00872   }
00873 }
00874 
00875 void poptSetOtherOptionHelp(poptContext con, const char * text)
00876 {
00877     con->otherHelp = _free(con->otherHelp);
00878     con->otherHelp = xstrdup(text);
00879 }

Generated on Sun Feb 3 19:33:36 2008 for popt by  doxygen 1.5.2