popt  1.16
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@*/ UNUSED(enum poptCallbackReason foo),
00038                 struct poptOption * key, 
00039                 /*@unused@*/ UNUSED(const char * arg),
00040                 /*@unused@*/ UNUSED(void * data))
00041         /*@globals fileSystem@*/
00042         /*@modifies fileSystem@*/
00043 {
00044     if (key->shortName == '?')
00045         poptPrintHelp(con, stdout, 0);
00046     else
00047         poptPrintUsage(con, stdout, 0);
00048 
00049 #if !defined(__LCLINT__)        /* XXX keep both splint & valgrind happy */
00050     con = poptFreeContext(con);
00051 #endif
00052     exit(0);
00053 }
00054 
00055 #ifdef  NOTYET
00056 /*@unchecked@*/
00057 static int show_option_defaults = 0;
00058 #endif
00059 
00063 /*@observer@*/ /*@unchecked@*/
00064 struct poptOption poptAliasOptions[] = {
00065     POPT_TABLEEND
00066 };
00067 
00071 /*@-castfcnptr@*/
00072 /*@observer@*/ /*@unchecked@*/
00073 struct poptOption poptHelpOptions[] = {
00074   { NULL, '\0', POPT_ARG_CALLBACK, (void *)displayArgs, 0, NULL, NULL },
00075   { "help", '?', 0, NULL, (int)'?', N_("Show this help message"), NULL },
00076   { "usage", '\0', 0, NULL, (int)'u', N_("Display brief usage message"), NULL },
00077     POPT_TABLEEND
00078 } ;
00079 
00080 /*@observer@*/ /*@unchecked@*/
00081 static struct poptOption poptHelpOptions2[] = {
00082 /*@-readonlytrans@*/
00083   { NULL, '\0', POPT_ARG_INTL_DOMAIN, PACKAGE, 0, NULL, NULL},
00084 /*@=readonlytrans@*/
00085   { NULL, '\0', POPT_ARG_CALLBACK, (void *)displayArgs, 0, NULL, NULL },
00086   { "help", '?', 0, NULL, (int)'?', N_("Show this help message"), NULL },
00087   { "usage", '\0', 0, NULL, (int)'u', N_("Display brief usage message"), NULL },
00088 #ifdef  NOTYET
00089   { "defaults", '\0', POPT_ARG_NONE, &show_option_defaults, 0,
00090         N_("Display option defaults in message"), NULL },
00091 #endif
00092   { "", '\0',   0, NULL, 0, N_("Terminate options"), NULL },
00093     POPT_TABLEEND
00094 } ;
00095 
00096 /*@observer@*/ /*@unchecked@*/
00097 struct poptOption * poptHelpOptionsI18N = poptHelpOptions2;
00098 /*@=castfcnptr@*/
00099 
00100 #define        _POPTHELP_MAXLINE       ((size_t)79)
00101 
00102 typedef struct columns_s {
00103     size_t cur;
00104     size_t max;
00105 } * columns_t;
00106 
00112 static size_t maxColumnWidth(FILE *fp)
00113         /*@*/
00114 {   
00115     size_t maxcols = _POPTHELP_MAXLINE;
00116 #if defined(TIOCGWINSZ)
00117     struct winsize ws;
00118     int fdno = fileno(fp ? fp : stdout);
00119 
00120     memset(&ws, 0, sizeof(ws));
00121     if (fdno >= 0 && !ioctl(fdno, (unsigned long)TIOCGWINSZ, &ws)) {
00122         size_t ws_col = (size_t)ws.ws_col;
00123         if (ws_col > maxcols && ws_col < (size_t)256)
00124             maxcols = ws_col - 1;
00125     }
00126 #endif
00127     return maxcols;
00128 }   
00129 
00135 static inline size_t stringDisplayWidth(const char *s)
00136         /*@*/
00137 {
00138     size_t n = strlen(s);
00139 #ifdef  POPT_WCHAR_HACK
00140     mbstate_t t;
00141 
00142     memset ((void *)&t, 0, sizeof (t)); /* In initial state.  */
00143     /* Determine number of display characters.  */
00144     n = mbsrtowcs (NULL, &s, n, &t);
00145 #else
00146     n = 0;
00147     for (; *s; s = POPT_next_char(s))
00148         n++;
00149 #endif
00150 
00151     return n;
00152 }
00153 
00157 /*@observer@*/ /*@null@*/ static const char *
00158 getTableTranslationDomain(/*@null@*/ const struct poptOption *opt)
00159         /*@*/
00160 {
00161     if (opt != NULL)
00162     for (; opt->longName || opt->shortName || opt->arg; opt++) {
00163         if (opt->argInfo == POPT_ARG_INTL_DOMAIN)
00164             return opt->arg;
00165     }
00166     return NULL;
00167 }
00168 
00173 /*@observer@*/ /*@null@*/ static const char *
00174 getArgDescrip(const struct poptOption * opt,
00175                 /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */
00176                 /*@null@*/ const char * translation_domain)
00177                 /*@=paramuse@*/
00178         /*@*/
00179 {
00180     if (!poptArgType(opt)) return NULL;
00181 
00182     if (poptArgType(opt) == POPT_ARG_MAINCALL)
00183         return opt->argDescrip;
00184     if (poptArgType(opt) == POPT_ARG_ARGV)
00185         return opt->argDescrip;
00186 
00187     if (opt->argDescrip) {
00188         /* Some strings need popt library, not application, i18n domain. */
00189         if (opt == (poptHelpOptions + 1)
00190          || opt == (poptHelpOptions + 2)
00191          || !strcmp(opt->argDescrip, N_("Help options:"))
00192          || !strcmp(opt->argDescrip, N_("Options implemented via popt alias/exec:")))
00193             return POPT_(opt->argDescrip);
00194 
00195         /* Use the application i18n domain. */
00196         return D_(translation_domain, opt->argDescrip);
00197     }
00198 
00199     switch (poptArgType(opt)) {
00200     case POPT_ARG_NONE:         return POPT_("NONE");
00201 #ifdef  DYING
00202     case POPT_ARG_VAL:          return POPT_("VAL");
00203 #else
00204     case POPT_ARG_VAL:          return NULL;
00205 #endif
00206     case POPT_ARG_INT:          return POPT_("INT");
00207     case POPT_ARG_SHORT:        return POPT_("SHORT");
00208     case POPT_ARG_LONG:         return POPT_("LONG");
00209     case POPT_ARG_LONGLONG:     return POPT_("LONGLONG");
00210     case POPT_ARG_STRING:       return POPT_("STRING");
00211     case POPT_ARG_FLOAT:        return POPT_("FLOAT");
00212     case POPT_ARG_DOUBLE:       return POPT_("DOUBLE");
00213     case POPT_ARG_MAINCALL:     return NULL;
00214     case POPT_ARG_ARGV:         return NULL;
00215     default:                    return POPT_("ARG");
00216     }
00217 }
00218 
00226 static /*@only@*/ /*@null@*/ char *
00227 singleOptionDefaultValue(size_t lineLength,
00228                 const struct poptOption * opt,
00229                 /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */
00230                 /*@null@*/ const char * translation_domain)
00231                 /*@=paramuse@*/
00232         /*@*/
00233 {
00234     const char * defstr = D_(translation_domain, "default");
00235     char * le = malloc(4*lineLength + 1);
00236     char * l = le;
00237 
00238     if (le == NULL) return NULL;        /* XXX can't happen */
00239     *le = '\0';
00240     *le++ = '(';
00241     le = stpcpy(le, defstr);
00242     *le++ = ':';
00243     *le++ = ' ';
00244   if (opt->arg) {       /* XXX programmer error */
00245     poptArg arg = { .ptr = opt->arg };
00246     switch (poptArgType(opt)) {
00247     case POPT_ARG_VAL:
00248     case POPT_ARG_INT:
00249         le += sprintf(le, "%d", arg.intp[0]);
00250         break;
00251     case POPT_ARG_SHORT:
00252         le += sprintf(le, "%hd", arg.shortp[0]);
00253         break;
00254     case POPT_ARG_LONG:
00255         le += sprintf(le, "%ld", arg.longp[0]);
00256         break;
00257     case POPT_ARG_LONGLONG:
00258         le += sprintf(le, "%lld", arg.longlongp[0]);
00259         break;
00260     case POPT_ARG_FLOAT:
00261     {   double aDouble = (double) arg.floatp[0];
00262         le += sprintf(le, "%g", aDouble);
00263     }   break;
00264     case POPT_ARG_DOUBLE:
00265         le += sprintf(le, "%g", arg.doublep[0]);
00266         break;
00267     case POPT_ARG_MAINCALL:
00268         le += sprintf(le, "%p", opt->arg);
00269         break;
00270     case POPT_ARG_ARGV:
00271         le += sprintf(le, "%p", opt->arg);
00272         break;
00273     case POPT_ARG_STRING:
00274     {   const char * s = arg.argv[0];
00275         if (s == NULL)
00276             le = stpcpy(le, "null");
00277         else {
00278             size_t limit = 4*lineLength - (le - l) - sizeof("\"\")");
00279             size_t slen;
00280             *le++ = '"';
00281             strncpy(le, s, limit); le[limit] = '\0'; le += (slen = strlen(le));
00282             if (slen == limit && s[limit])
00283                 le[-1] = le[-2] = le[-3] = '.';
00284             *le++ = '"';
00285         }
00286     }   break;
00287     case POPT_ARG_NONE:
00288     default:
00289         l = _free(l);
00290         return NULL;
00291         /*@notreached@*/ break;
00292     }
00293   }
00294     *le++ = ')';
00295     *le = '\0';
00296 
00297     return l;
00298 }
00299 
00307 static void singleOptionHelp(FILE * fp, columns_t columns,
00308                 const struct poptOption * opt,
00309                 /*@null@*/ const char * translation_domain)
00310         /*@globals fileSystem @*/
00311         /*@modifies fp, fileSystem @*/
00312 {
00313     size_t maxLeftCol = columns->cur;
00314     size_t indentLength = maxLeftCol + 5;
00315     size_t lineLength = columns->max - indentLength;
00316     const char * help = D_(translation_domain, opt->descrip);
00317     const char * argDescrip = getArgDescrip(opt, translation_domain);
00318     /* Display shortName iff printable non-space. */
00319     int prtshort = (int)(isprint((int)opt->shortName) && opt->shortName != ' ');
00320     size_t helpLength;
00321     char * defs = NULL;
00322     char * left;
00323     size_t nb = maxLeftCol + 1;
00324     int displaypad = 0;
00325     int xx;
00326 
00327     /* Make sure there's more than enough room in target buffer. */
00328     if (opt->longName)  nb += strlen(opt->longName);
00329     if (F_ISSET(opt, TOGGLE)) nb += sizeof("[no]") - 1;
00330     if (argDescrip)     nb += strlen(argDescrip);
00331 
00332     left = malloc(nb);
00333     if (left == NULL) return;   /* XXX can't happen */
00334     left[0] = '\0';
00335     left[maxLeftCol] = '\0';
00336 
00337 #define prtlong (opt->longName != NULL) /* XXX splint needs a clue */
00338     if (!(prtshort || prtlong))
00339         goto out;
00340     if (prtshort && prtlong) {
00341         char *dash = F_ISSET(opt, ONEDASH) ? "-" : "--";
00342         left[0] = '-';
00343         left[1] = opt->shortName;
00344         (void) stpcpy(stpcpy(stpcpy(left+2, ", "), dash), opt->longName);
00345     } else if (prtshort) {
00346         left[0] = '-';
00347         left[1] = opt->shortName;
00348         left[2] = '\0';
00349     } else if (prtlong) {
00350         /* XXX --long always padded for alignment with/without "-X, ". */
00351         char *dash = poptArgType(opt) == POPT_ARG_MAINCALL ? ""
00352                    : (F_ISSET(opt, ONEDASH) ? "-" : "--");
00353         const char *longName = opt->longName;
00354         const char *toggle;
00355         if (F_ISSET(opt, TOGGLE)) {
00356             toggle = "[no]";
00357             if (longName[0] == 'n' && longName[1] == 'o') {
00358                 longName += sizeof("no") - 1;
00359                 if (longName[0] == '-')
00360                     longName++;
00361             }
00362         } else
00363             toggle = "";
00364         (void) stpcpy(stpcpy(stpcpy(stpcpy(left, "    "), dash), toggle), longName);
00365     }
00366 #undef  prtlong
00367 
00368     if (argDescrip) {
00369         char * le = left + strlen(left);
00370 
00371         if (F_ISSET(opt, OPTIONAL))
00372             *le++ = '[';
00373 
00374         /* Choose type of output */
00375         if (F_ISSET(opt, SHOW_DEFAULT)) {
00376             defs = singleOptionDefaultValue(lineLength, opt, translation_domain);
00377             if (defs) {
00378                 char * t = malloc((help ? strlen(help) : 0) +
00379                                 strlen(defs) + sizeof(" "));
00380                 if (t) {
00381                     char * te = t;
00382                     if (help)
00383                         te = stpcpy(te, help);
00384                     *te++ = ' ';
00385                     strcpy(te, defs);
00386                     defs = _free(defs);
00387                     defs = t;
00388                 }
00389             }
00390         }
00391 
00392         if (opt->argDescrip == NULL) {
00393             switch (poptArgType(opt)) {
00394             case POPT_ARG_NONE:
00395                 break;
00396             case POPT_ARG_VAL:
00397 #ifdef  NOTNOW  /* XXX pug ugly nerdy output */
00398             {   long aLong = opt->val;
00399                 int ops = F_ISSET(opt, LOGICALOPS);
00400                 int negate = F_ISSET(opt, NOT);
00401 
00402                 /* Don't bother displaying typical values */
00403                 if (!ops && (aLong == 0L || aLong == 1L || aLong == -1L))
00404                     break;
00405                 *le++ = '[';
00406                 switch (ops) {
00407                 case POPT_ARGFLAG_OR:
00408                     *le++ = '|';
00409                     /*@innerbreak@*/ break;
00410                 case POPT_ARGFLAG_AND:
00411                     *le++ = '&';
00412                     /*@innerbreak@*/ break;
00413                 case POPT_ARGFLAG_XOR:
00414                     *le++ = '^';
00415                     /*@innerbreak@*/ break;
00416                 default:
00417                     /*@innerbreak@*/ break;
00418                 }
00419                 *le++ = (opt->longName != NULL ? '=' : ' ');
00420                 if (negate) *le++ = '~';
00421                 /*@-formatconst@*/
00422                 le += sprintf(le, (ops ? "0x%lx" : "%ld"), aLong);
00423                 /*@=formatconst@*/
00424                 *le++ = ']';
00425             }
00426 #endif
00427                 break;
00428             case POPT_ARG_INT:
00429             case POPT_ARG_SHORT:
00430             case POPT_ARG_LONG:
00431             case POPT_ARG_LONGLONG:
00432             case POPT_ARG_FLOAT:
00433             case POPT_ARG_DOUBLE:
00434             case POPT_ARG_STRING:
00435                 *le++ = (opt->longName != NULL ? '=' : ' ');
00436                 le = stpcpy(le, argDescrip);
00437                 break;
00438             default:
00439                 break;
00440             }
00441         } else {
00442             char *leo;
00443 
00444             /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */
00445             if (!strchr(" =(", argDescrip[0]))
00446                 *le++ = ((poptArgType(opt) == POPT_ARG_MAINCALL) ? ' ' :
00447                          (poptArgType(opt) == POPT_ARG_ARGV) ? ' ' : '=');
00448             le = stpcpy(leo = le, argDescrip);
00449 
00450             /* Adjust for (possible) wide characters. */
00451             displaypad = (int)((le - leo) - stringDisplayWidth(argDescrip));
00452         }
00453         if (F_ISSET(opt, OPTIONAL))
00454             *le++ = ']';
00455         *le = '\0';
00456     }
00457 
00458     if (help)
00459         xx = POPT_fprintf(fp,"  %-*s   ", (int)(maxLeftCol+displaypad), left);
00460     else {
00461         xx = POPT_fprintf(fp,"  %s\n", left); 
00462         goto out;
00463     }
00464 
00465     left = _free(left);
00466     if (defs)
00467         help = defs;
00468 
00469     helpLength = strlen(help);
00470     while (helpLength > lineLength) {
00471         const char * ch;
00472         char format[16];
00473 
00474         ch = help + lineLength - 1;
00475         while (ch > help && !_isspaceptr(ch))
00476             ch = POPT_prev_char(ch);
00477         if (ch == help) break;          /* give up */
00478         while (ch > (help + 1) && _isspaceptr(ch))
00479             ch = POPT_prev_char (ch);
00480         ch = POPT_next_char(ch);
00481 
00482         /*
00483          *  XXX strdup is necessary to add NUL terminator so that an unknown
00484          *  no. of (possible) multi-byte characters can be displayed.
00485          */
00486         {   char * fmthelp = xstrdup(help);
00487             if (fmthelp) {
00488                 fmthelp[ch - help] = '\0';
00489                 sprintf(format, "%%s\n%%%ds", (int) indentLength);
00490                 /*@-formatconst@*/
00491                 xx = POPT_fprintf(fp, format, fmthelp, " ");
00492                 /*@=formatconst@*/
00493                 free(fmthelp);
00494             }
00495         }
00496 
00497         help = ch;
00498         while (_isspaceptr(help) && *help)
00499             help = POPT_next_char(help);
00500         helpLength = strlen(help);
00501     }
00502 
00503     if (helpLength) fprintf(fp, "%s\n", help);
00504     help = NULL;
00505 
00506 out:
00507     /*@-dependenttrans@*/
00508     defs = _free(defs);
00509     /*@=dependenttrans@*/
00510     left = _free(left);
00511 }
00512 
00519 static size_t maxArgWidth(const struct poptOption * opt,
00520                        /*@null@*/ const char * translation_domain)
00521         /*@*/
00522 {
00523     size_t max = 0;
00524     size_t len = 0;
00525     const char * argDescrip;
00526     
00527     if (opt != NULL)
00528     while (opt->longName || opt->shortName || opt->arg) {
00529         if (poptArgType(opt) == POPT_ARG_INCLUDE_TABLE) {
00530             if (opt->arg)       /* XXX program error */
00531                 len = maxArgWidth(opt->arg, translation_domain);
00532             if (len > max) max = len;
00533         } else if (!F_ISSET(opt, DOC_HIDDEN)) {
00534             len = sizeof("  ")-1;
00535             /* XXX --long always padded for alignment with/without "-X, ". */
00536             len += sizeof("-X, ")-1;
00537             if (opt->longName) {
00538                 len += (F_ISSET(opt, ONEDASH) ? sizeof("-") : sizeof("--")) - 1;
00539                 len += strlen(opt->longName);
00540             }
00541 
00542             argDescrip = getArgDescrip(opt, translation_domain);
00543 
00544             if (argDescrip) {
00545 
00546                 /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */
00547                 if (!strchr(" =(", argDescrip[0])) len += sizeof("=")-1;
00548 
00549                 /* Adjust for (possible) wide characters. */
00550                 len += stringDisplayWidth(argDescrip);
00551             }
00552 
00553             if (F_ISSET(opt, OPTIONAL)) len += sizeof("[]")-1;
00554             if (len > max) max = len;
00555         }
00556         opt++;
00557     }
00558     
00559     return max;
00560 }
00561 
00570 static void itemHelp(FILE * fp,
00571                 /*@null@*/ poptItem items, int nitems,
00572                 columns_t columns,
00573                 /*@null@*/ const char * translation_domain)
00574         /*@globals fileSystem @*/
00575         /*@modifies fp, fileSystem @*/
00576 {
00577     poptItem item;
00578     int i;
00579 
00580     if (items != NULL)
00581     for (i = 0, item = items; i < nitems; i++, item++) {
00582         const struct poptOption * opt;
00583         opt = &item->option;
00584         if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN))
00585             singleOptionHelp(fp, columns, opt, translation_domain);
00586     }
00587 }
00588 
00597 static void singleTableHelp(poptContext con, FILE * fp,
00598                 /*@null@*/ const struct poptOption * table,
00599                 columns_t columns,
00600                 /*@null@*/ const char * translation_domain)
00601         /*@globals fileSystem @*/
00602         /*@modifies fp, columns->cur, fileSystem @*/
00603 {
00604     const struct poptOption * opt;
00605     const char *sub_transdom;
00606     int xx;
00607 
00608     if (con == NULL) return;
00609 
00610     if (table == poptAliasOptions) {
00611         itemHelp(fp, con->aliases, con->numAliases, columns, NULL);
00612         itemHelp(fp, con->execs, con->numExecs, columns, NULL);
00613         return;
00614     }
00615 
00616     if (table != NULL)
00617     for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) {
00618         if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN))
00619             singleOptionHelp(fp, columns, opt, translation_domain);
00620     }
00621 
00622     if (table != NULL)
00623     for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) {
00624         if (poptArgType(opt) != POPT_ARG_INCLUDE_TABLE)
00625             continue;
00626         sub_transdom = getTableTranslationDomain(opt->arg);
00627         if (sub_transdom == NULL)
00628             sub_transdom = translation_domain;
00629             
00630         /* If no popt aliases/execs, skip poptAliasOption processing. */
00631         if (opt->arg == poptAliasOptions && !(con->numAliases || con->numExecs))
00632             continue;
00633         if (opt->descrip)
00634             xx = POPT_fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip));
00635 
00636         singleTableHelp(con, fp, opt->arg, columns, sub_transdom);
00637     }
00638 }
00639 
00644 static size_t showHelpIntro(poptContext con, FILE * fp)
00645         /*@globals fileSystem @*/
00646         /*@modifies fp, fileSystem @*/
00647 {
00648     size_t len = (size_t)6;
00649     int xx;
00650 
00651     xx = POPT_fprintf(fp, POPT_("Usage:"));
00652     if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) {
00653         struct optionStackEntry * os = con->optionStack;
00654         const char * fn = (os->argv ? os->argv[0] : NULL);
00655         if (fn == NULL) return len;
00656         if (strchr(fn, '/')) fn = strrchr(fn, '/') + 1;
00657         /* XXX POPT_fprintf not needed for argv[0] display. */
00658         fprintf(fp, " %s", fn);
00659         len += strlen(fn) + 1;
00660     }
00661 
00662     return len;
00663 }
00664 
00665 void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags))
00666 {
00667     columns_t columns = calloc((size_t)1, sizeof(*columns));
00668     int xx;
00669 
00670     if (con == NULL) return;
00671 
00672     (void) showHelpIntro(con, fp);
00673     if (con->otherHelp)
00674         xx = POPT_fprintf(fp, " %s\n", con->otherHelp);
00675     else
00676         xx = POPT_fprintf(fp, " %s\n", POPT_("[OPTION...]"));
00677 
00678     if (columns) {
00679         columns->cur = maxArgWidth(con->options, NULL);
00680         columns->max = maxColumnWidth(fp);
00681         singleTableHelp(con, fp, con->options, columns, NULL);
00682         free(columns);
00683     }
00684 }
00685 
00693 static size_t singleOptionUsage(FILE * fp, columns_t columns,
00694                 const struct poptOption * opt,
00695                 /*@null@*/ const char *translation_domain)
00696         /*@globals fileSystem @*/
00697         /*@modifies fp, columns->cur, fileSystem @*/
00698 {
00699     size_t len = sizeof(" []")-1;
00700     const char * argDescrip = getArgDescrip(opt, translation_domain);
00701     /* Display shortName iff printable non-space. */
00702     int prtshort = (int)(isprint((int)opt->shortName) && opt->shortName != ' ');
00703 
00704 #define prtlong (opt->longName != NULL) /* XXX splint needs a clue */
00705     if (!(prtshort || prtlong))
00706         return columns->cur;
00707 
00708     len = sizeof(" []")-1;
00709     if (prtshort)
00710         len += sizeof("-c")-1;
00711     if (prtlong) {
00712         if (prtshort) len += sizeof("|")-1;
00713         len += (F_ISSET(opt, ONEDASH) ? sizeof("-") : sizeof("--")) - 1;
00714         len += strlen(opt->longName);
00715     }
00716 
00717     if (argDescrip) {
00718 
00719         /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */
00720         if (!strchr(" =(", argDescrip[0])) len += sizeof("=")-1;
00721 
00722         /* Adjust for (possible) wide characters. */
00723         len += stringDisplayWidth(argDescrip);
00724     }
00725 
00726     if ((columns->cur + len) > columns->max) {
00727         fprintf(fp, "\n       ");
00728         columns->cur = (size_t)7;
00729     } 
00730 
00731     fprintf(fp, " [");
00732     if (prtshort)
00733         fprintf(fp, "-%c", opt->shortName);
00734     if (prtlong)
00735         fprintf(fp, "%s%s%s",
00736                 (prtshort ? "|" : ""),
00737                 (F_ISSET(opt, ONEDASH) ? "-" : "--"),
00738                 opt->longName);
00739 #undef  prtlong
00740 
00741     if (argDescrip) {
00742         /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */
00743         if (!strchr(" =(", argDescrip[0])) fprintf(fp, "=");
00744         fprintf(fp, "%s", argDescrip);
00745     }
00746     fprintf(fp, "]");
00747 
00748     return columns->cur + len + 1;
00749 }
00750 
00759 static size_t itemUsage(FILE * fp, columns_t columns,
00760                 /*@null@*/ poptItem item, int nitems,
00761                 /*@null@*/ const char * translation_domain)
00762         /*@globals fileSystem @*/
00763         /*@modifies fp, columns->cur, fileSystem @*/
00764 {
00765     int i;
00766 
00767     if (item != NULL)
00768     for (i = 0; i < nitems; i++, item++) {
00769         const struct poptOption * opt;
00770         opt = &item->option;
00771         if (poptArgType(opt) == POPT_ARG_INTL_DOMAIN) {
00772             translation_domain = (const char *)opt->arg;
00773         } else
00774         if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN)) {
00775             columns->cur = singleOptionUsage(fp, columns, opt, translation_domain);
00776         }
00777     }
00778 
00779     return columns->cur;
00780 }
00781 
00785 typedef struct poptDone_s {
00786     int nopts;
00787     int maxopts;
00788 /*@null@*/
00789     const void ** opts;
00790 } * poptDone;
00791 
00802 static size_t singleTableUsage(poptContext con, FILE * fp, columns_t columns,
00803                 /*@null@*/ const struct poptOption * opt,
00804                 /*@null@*/ const char * translation_domain,
00805                 /*@null@*/ poptDone done)
00806         /*@globals fileSystem @*/
00807         /*@modifies fp, columns->cur, done, fileSystem @*/
00808 {
00809     if (con != NULL && opt != NULL)
00810     for (; (opt->longName || opt->shortName || opt->arg) ; opt++) {
00811         if (poptArgType(opt) == POPT_ARG_INTL_DOMAIN) {
00812             translation_domain = (const char *)opt->arg;
00813         } else
00814         if (poptArgType(opt) == POPT_ARG_INCLUDE_TABLE) {
00815             if (done) {
00816                 int i = 0;
00817                 if (done->opts != NULL)
00818                 for (i = 0; i < done->nopts; i++) {
00819                     const void * that = done->opts[i];
00820                     if (that == NULL || that != opt->arg)
00821                         /*@innercontinue@*/ continue;
00822                     /*@innerbreak@*/ break;
00823                 }
00824                 /* Skip if this table has already been processed. */
00825                 if (opt->arg == NULL || i < done->nopts)
00826                     continue;
00827                 if (done->opts != NULL && done->nopts < done->maxopts)
00828                     done->opts[done->nopts++] = (const void *) opt->arg;
00829             }
00830             columns->cur = singleTableUsage(con, fp, columns, opt->arg,
00831                         translation_domain, done);
00832         } else
00833         if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN)) {
00834             columns->cur = singleOptionUsage(fp, columns, opt, translation_domain);
00835         }
00836     }
00837 
00838     return columns->cur;
00839 }
00840 
00849 static size_t showShortOptions(const struct poptOption * opt, FILE * fp,
00850                 /*@null@*/ char * str)
00851         /*@globals fileSystem @*/
00852         /*@modifies str, *fp, fileSystem @*/
00853         /*@requires maxRead(str) >= 0 @*/
00854 {
00855     /* bufsize larger then the ascii set, lazy allocation on top level call. */
00856     size_t nb = (size_t)300;
00857     char * s = (str != NULL ? str : calloc((size_t)1, nb));
00858     size_t len = (size_t)0;
00859 
00860     if (s == NULL)
00861         return 0;
00862 
00863     if (opt != NULL)
00864     for (; (opt->longName || opt->shortName || opt->arg); opt++) {
00865         if (!F_ISSET(opt, DOC_HIDDEN) && opt->shortName && !poptArgType(opt))
00866         {
00867             /* Display shortName iff unique printable non-space. */
00868             if (!strchr(s, opt->shortName) && isprint((int)opt->shortName)
00869              && opt->shortName != ' ')
00870                 s[strlen(s)] = opt->shortName;
00871         } else if (poptArgType(opt) == POPT_ARG_INCLUDE_TABLE)
00872             if (opt->arg)       /* XXX program error */
00873                 len = showShortOptions(opt->arg, fp, s);
00874     } 
00875 
00876     /* On return to top level, print the short options, return print length. */
00877     if (s != str && *s != '\0') {
00878         fprintf(fp, " [-%s]", s);
00879         len = strlen(s) + sizeof(" [-]")-1;
00880     }
00881 /*@-temptrans@*/        /* LCL: local s, not str arg, is being freed. */
00882     if (s != str)
00883         free(s);
00884 /*@=temptrans@*/
00885     return len;
00886 }
00887 
00888 void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags))
00889 {
00890     columns_t columns = calloc((size_t)1, sizeof(*columns));
00891     struct poptDone_s done_buf;
00892     poptDone done = &done_buf;
00893 
00894     if (con == NULL) return;
00895 
00896     memset(done, 0, sizeof(*done));
00897     done->nopts = 0;
00898     done->maxopts = 64;
00899   if (columns) {
00900     columns->cur = done->maxopts * sizeof(*done->opts);
00901     columns->max = maxColumnWidth(fp);
00902     done->opts = calloc((size_t)1, columns->cur);
00903     /*@-keeptrans@*/
00904     if (done->opts != NULL)
00905         done->opts[done->nopts++] = (const void *) con->options;
00906     /*@=keeptrans@*/
00907 
00908     columns->cur = showHelpIntro(con, fp);
00909     columns->cur += showShortOptions(con->options, fp, NULL);
00910     columns->cur = singleTableUsage(con, fp, columns, con->options, NULL, done);
00911     columns->cur = itemUsage(fp, columns, con->aliases, con->numAliases, NULL);
00912     columns->cur = itemUsage(fp, columns, con->execs, con->numExecs, NULL);
00913 
00914     if (con->otherHelp) {
00915         columns->cur += strlen(con->otherHelp) + 1;
00916         if (columns->cur > columns->max) fprintf(fp, "\n       ");
00917         fprintf(fp, " %s", con->otherHelp);
00918     }
00919 
00920     fprintf(fp, "\n");
00921     if (done->opts != NULL)
00922         free(done->opts);
00923     free(columns);
00924   }
00925 }
00926 
00927 void poptSetOtherOptionHelp(poptContext con, const char * text)
00928 {
00929     if (con == NULL) return;
00930 
00931     con->otherHelp = _free(con->otherHelp);
00932     con->otherHelp = xstrdup(text);
00933 }

Generated for popt by  doxygen 1.7.6.1