# popt/popthelp.c

Go to the documentation of this file.

    00001 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
    00002
    00003 /*@-type@*/
    00008 /* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING
    00009    file accompanying popt source distributions, available from
    00010    ftp://ftp.rpm.org/pub/rpm/dist. */
    00011
    00012 #include "system.h"
    00013 #include "poptint.h"
    00014
    00019 static void displayArgs(poptContext con,
    00020                 /*@unused@*/ enum poptCallbackReason foo,
    00021                 struct poptOption * key,
    00022                 /*@unused@*/ const char * arg, /*@unused@*/ void * data)
    00023         /*@globals fileSystem@*/
    00024         /*@modifies fileSystem@*/
    00025 {
    00026     if (key->shortName == '?')
    00027         poptPrintHelp(con, stdout, 0);
    00028     else
    00029         poptPrintUsage(con, stdout, 0);
    00030     exit(0);
    00031 }
    00032
    00033 #ifdef  NOTYET
    00034 /*@unchecked@*/
    00035 static int show_option_defaults = 0;
    00036 #endif
    00037
    00041 /*@observer@*/ /*@unchecked@*/
    00042 struct poptOption poptAliasOptions[] = {
    00043     POPT_TABLEEND
    00044 };
    00045
    00049 /*@-castfcnptr@*/
    00050 /*@observer@*/ /*@unchecked@*/
    00051 struct poptOption poptHelpOptions[] = {
    00052   { NULL, '\0', POPT_ARG_CALLBACK, (void *)&displayArgs, '\0', NULL, NULL },
    00053   { "help", '?', 0, NULL, '?', N_("Show this help message"), NULL },
    00054   { "usage", '\0', 0, NULL, 'u', N_("Display brief usage message"), NULL },
    00055 #ifdef  NOTYET
    00056   { "defaults", '\0', POPT_ARG_NONE, &show_option_defaults, 0,
    00057         N_("Display option defaults in message"), NULL },
    00058 #endif
    00059     POPT_TABLEEND
    00060 } ;
    00061 /*@=castfcnptr@*/
    00062
    00066 /*@observer@*/ /*@null@*/ static const char *const
    00067 getTableTranslationDomain(/*@null@*/ const struct poptOption *table)
    00068         /*@*/
    00069 {
    00070     const struct poptOption *opt;
    00071
    00072     if (table != NULL)
    00073     for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) {
    00074         if (opt->argInfo == POPT_ARG_INTL_DOMAIN)
    00075             return opt->arg;
    00076     }
    00077     return NULL;
    00078 }
    00079
    00084 /*@observer@*/ /*@null@*/ static const char *const
    00085 getArgDescrip(const struct poptOption * opt,
    00086                 /*@-paramuse@*/         /* FIX: wazzup? */
    00087                 /*@null@*/ const char * translation_domain)
    00088                 /*@=paramuse@*/
    00089         /*@*/
    00090 {
    00091     if (!(opt->argInfo & POPT_ARG_MASK)) return NULL;
    00092
    00093     if (opt == (poptHelpOptions + 1) || opt == (poptHelpOptions + 2))
    00094         if (opt->argDescrip) return POPT_(opt->argDescrip);
    00095
    00096     if (opt->argDescrip) return D_(translation_domain, opt->argDescrip);
    00097
    00098     switch (opt->argInfo & POPT_ARG_MASK) {
    00099     case POPT_ARG_NONE:         return POPT_("NONE");
    00100     case POPT_ARG_VAL:          return POPT_("VAL");
    00101     case POPT_ARG_INT:          return POPT_("INT");
    00102     case POPT_ARG_LONG:         return POPT_("LONG");
    00103     case POPT_ARG_STRING:       return POPT_("STRING");
    00104     case POPT_ARG_FLOAT:        return POPT_("FLOAT");
    00105     case POPT_ARG_DOUBLE:       return POPT_("DOUBLE");
    00106     default:                    return POPT_("ARG");
    00107     }
    00108 }
    00109
    00114 static /*@only@*/ /*@null@*/ char *
    00115 singleOptionDefaultValue(int lineLength,
    00116                 const struct poptOption * opt,
    00117                 /*@-paramuse@*/ /* FIX: i18n macros disable with lclint */
    00118                 /*@null@*/ const char * translation_domain)
    00119                 /*@=paramuse@*/
    00120         /*@*/
    00121 {
    00122     const char * defstr = D_(translation_domain, "default");
    00123     char * le = malloc(4*lineLength + 1);
    00124     char * l = le;
    00125
    00126     if (le == NULL) return NULL;        /* XXX can't happen */
    00127     *le = '\0';
    00128     *le++ = '(';
    00129     strcpy(le, defstr); le += strlen(le);
    00130     *le++ = ':';
    00131     *le++ = ' ';
    00132     if (opt->arg)       /* XXX programmer error */
    00133     switch (opt->argInfo & POPT_ARG_MASK) {
    00134     case POPT_ARG_VAL:
    00135     case POPT_ARG_INT:
    00136     {   long aLong = *((int *)opt->arg);
    00137         le += sprintf(le, "%ld", aLong);
    00138     }   break;
    00139     case POPT_ARG_LONG:
    00140     {   long aLong = *((long *)opt->arg);
    00141         le += sprintf(le, "%ld", aLong);
    00142     }   break;
    00143     case POPT_ARG_FLOAT:
    00144     {   double aDouble = *((float *)opt->arg);
    00145         le += sprintf(le, "%g", aDouble);
    00146     }   break;
    00147     case POPT_ARG_DOUBLE:
    00148     {   double aDouble = *((double *)opt->arg);
    00149         le += sprintf(le, "%g", aDouble);
    00150     }   break;
    00151     case POPT_ARG_STRING:
    00152     {   const char * s = *(const char **)opt->arg;
    00153         if (s == NULL) {
    00154             strcpy(le, "null"); le += strlen(le);
    00155         } else {
    00156             size_t slen = 4*lineLength - (le - l) - sizeof("\"...\")");
    00157             *le++ = '"';
    00158             strncpy(le, s, slen); le[slen] = '\0'; le += strlen(le);
    00159             if (slen < strlen(s)) {
    00160                 strcpy(le, "...");      le += strlen(le);
    00161             }
    00162             *le++ = '"';
    00163         }
    00164     }   break;
    00165     case POPT_ARG_NONE:
    00166     default:
    00167         l = _free(l);
    00168         return NULL;
    00169         /*@notreached@*/ break;
    00170     }
    00171     *le++ = ')';
    00172     *le = '\0';
    00173
    00174     return l;
    00175 }
    00176
    00182 static void singleOptionHelp(FILE * fp, int maxLeftCol,
    00183                 const struct poptOption * opt,
    00184                 /*@null@*/ const char * translation_domain)
    00185         /*@globals fileSystem @*/
    00186         /*@modifies *fp, fileSystem @*/
    00187 {
    00188     int indentLength = maxLeftCol + 5;
    00189     int lineLength = 79 - indentLength;
    00190     const char * help = D_(translation_domain, opt->descrip);
    00191     const char * argDescrip = getArgDescrip(opt, translation_domain);
    00192     int helpLength;
    00193     char * defs = NULL;
    00194     char * left;
    00195     int nb = maxLeftCol + 1;
    00196
    00197     /* Make sure there's more than enough room in target buffer. */
    00198     if (opt->longName)  nb += strlen(opt->longName);
    00199     if (argDescrip)     nb += strlen(argDescrip);
    00200
    00201     left = malloc(nb);
    00202     if (left == NULL) return;   /* XXX can't happen */
    00203     left[0] = '\0';
    00204     left[maxLeftCol] = '\0';
    00205
    00206     if (opt->longName && opt->shortName)
    00207         sprintf(left, "-%c, %s%s", opt->shortName,
    00208                 ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
    00209                 opt->longName);
    00210     else if (opt->shortName != '\0')
    00211         sprintf(left, "-%c", opt->shortName);
    00212     else if (opt->longName)
    00213         sprintf(left, "%s%s",
    00214                 ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
    00215                 opt->longName);
    00216     if (!*left) goto out;
    00217     if (argDescrip) {
    00218         char * le = left + strlen(left);
    00219
    00220         if (opt->argInfo & POPT_ARGFLAG_OPTIONAL)
    00221             *le++ = '[';
    00222
    00223         /* Choose type of output */
    00224         /*@-branchstate@*/
    00225         if (opt->argInfo & POPT_ARGFLAG_SHOW_DEFAULT) {
    00226             defs = singleOptionDefaultValue(lineLength, opt, translation_domain);
    00227             if (defs) {
    00228                 char * t = malloc((help ? strlen(help) : 0) +
    00229                                 strlen(defs) + sizeof(" "));
    00230                 if (t) {
    00231                     char * te = t;
    00232                     *te = '\0';
    00233                     if (help) {
    00234                         strcpy(te, help);       te += strlen(te);
    00235                     }
    00236                     *te++ = ' ';
    00237                     strcpy(te, defs);
    00238                     defs = _free(defs);
    00239                 }
    00240                 defs = t;
    00241             }
    00242         }
    00243         /*@=branchstate@*/
    00244
    00245         if (opt->argDescrip == NULL) {
    00246             switch (opt->argInfo & POPT_ARG_MASK) {
    00247             case POPT_ARG_NONE:
    00248                 break;
    00249             case POPT_ARG_VAL:
    00250             {   long aLong = opt->val;
    00251                 int ops = (opt->argInfo & POPT_ARGFLAG_LOGICALOPS);
    00252                 int negate = (opt->argInfo & POPT_ARGFLAG_NOT);
    00253
    00254                 /* Don't bother displaying typical values */
    00255                 if (!ops && (aLong == 0L || aLong == 1L || aLong == -1L))
    00256                     break;
    00257                 *le++ = '[';
    00258                 switch (ops) {
    00259                 case POPT_ARGFLAG_OR:
    00260                     *le++ = '|';
    00261                     /*@innerbreak@*/ break;
    00262                 case POPT_ARGFLAG_AND:
    00263                     *le++ = '&';
    00264                     /*@innerbreak@*/ break;
    00265                 case POPT_ARGFLAG_XOR:
    00266                     *le++ = '^';
    00267                     /*@innerbreak@*/ break;
    00268                 default:
    00269                     /*@innerbreak@*/ break;
    00270                 }
    00271                 *le++ = '=';
    00272                 if (negate) *le++ = '~';
    00273                 /*@-formatconst@*/
    00274                 le += sprintf(le, (ops ? "0x%lx" : "%ld"), aLong);
    00275                 /*@=formatconst@*/
    00276                 *le++ = ']';
    00277             }   break;
    00278             case POPT_ARG_INT:
    00279             case POPT_ARG_LONG:
    00280             case POPT_ARG_FLOAT:
    00281             case POPT_ARG_DOUBLE:
    00282             case POPT_ARG_STRING:
    00283                 *le++ = '=';
    00284                 strcpy(le, argDescrip);         le += strlen(le);
    00285                 break;
    00286             default:
    00287                 break;
    00288             }
    00289         } else {
    00290             *le++ = '=';
    00291             strcpy(le, argDescrip);             le += strlen(le);
    00292         }
    00293         if (opt->argInfo & POPT_ARGFLAG_OPTIONAL)
    00294             *le++ = ']';
    00295         *le = '\0';
    00296     }
    00297
    00298     if (help)
    00299         fprintf(fp,"  %-*s   ", maxLeftCol, left);
    00300     else {
    00301         fprintf(fp,"  %s\n", left);
    00302         goto out;
    00303     }
    00304
    00305     left = _free(left);
    00306     if (defs) {
    00307         help = defs; defs = NULL;
    00308     }
    00309
    00310     helpLength = strlen(help);
    00311     while (helpLength > lineLength) {
    00312         const char * ch;
    00313         char format[10];
    00314
    00315         ch = help + lineLength - 1;
    00316         while (ch > help && !isspace(*ch)) ch--;
    00317         if (ch == help) break;          /* give up */
    00318         while (ch > (help + 1) && isspace(*ch)) ch--;
    00319         ch++;
    00320
    00321         sprintf(format, "%%.%ds\n%%%ds", (int) (ch - help), indentLength);
    00322         /*@-formatconst@*/
    00323         fprintf(fp, format, help, " ");
    00324         /*@=formatconst@*/
    00325         help = ch;
    00326         while (isspace(*help) && *help) help++;
    00327         helpLength = strlen(help);
    00328     }
    00329
    00330     if (helpLength) fprintf(fp, "%s\n", help);
    00331
    00332 out:
    00333     /*@-dependenttrans@*/
    00334     defs = _free(defs);
    00335     /*@=dependenttrans@*/
    00336     left = _free(left);
    00337 }
    00338
    00343 static int maxArgWidth(const struct poptOption * opt,
    00344                        /*@null@*/ const char * translation_domain)
    00345         /*@*/
    00346 {
    00347     int max = 0;
    00348     int len = 0;
    00349     const char * s;
    00350
    00351     if (opt != NULL)
    00352     while (opt->longName || opt->shortName || opt->arg) {
    00353         if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
    00354             if (opt->arg)       /* XXX program error */
    00355             len = maxArgWidth(opt->arg, translation_domain);
    00356             if (len > max) max = len;
    00357         } else if (!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
    00358             len = sizeof("  ")-1;
    00359             if (opt->shortName != '\0') len += sizeof("-X")-1;
    00360             if (opt->shortName != '\0' && opt->longName) len += sizeof(", ")-1;
    00361             if (opt->longName) {
    00362                 len += ((opt->argInfo & POPT_ARGFLAG_ONEDASH)
    00363                         ? sizeof("-")-1 : sizeof("--")-1);
    00364                 len += strlen(opt->longName);
    00365             }
    00366
    00367             s = getArgDescrip(opt, translation_domain);
    00368             if (s)
    00369                 len += sizeof("=")-1 + strlen(s);
    00370             if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) len += sizeof("[]")-1;
    00371             if (len > max) max = len;
    00372         }
    00373
    00374         opt++;
    00375     }
    00376
    00377     return max;
    00378 }
    00379
    00387 static void itemHelp(FILE * fp,
    00388                 /*@null@*/ poptItem items, int nitems, int left,
    00389                 /*@null@*/ const char * translation_domain)
    00390         /*@globals fileSystem @*/
    00391         /*@modifies *fp, fileSystem @*/
    00392 {
    00393     poptItem item;
    00394     int i;
    00395
    00396     if (items != NULL)
    00397     for (i = 0, item = items; i < nitems; i++, item++) {
    00398         const struct poptOption * opt;
    00399         opt = &item->option;
    00400         if ((opt->longName || opt->shortName) &&
    00401             !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
    00402             singleOptionHelp(fp, left, opt, translation_domain);
    00403     }
    00404 }
    00405
    00411 static void singleTableHelp(poptContext con, FILE * fp,
    00412                 /*@null@*/ const struct poptOption * table, int left,
    00413                 /*@null@*/ const char * translation_domain)
    00414         /*@globals fileSystem @*/
    00415         /*@modifies *fp, fileSystem @*/
    00416 {
    00417     const struct poptOption * opt;
    00418     const char *sub_transdom;
    00419
    00420     if (table == poptAliasOptions) {
    00421         itemHelp(fp, con->aliases, con->numAliases, left, NULL);
    00422         itemHelp(fp, con->execs, con->numExecs, left, NULL);
    00423         return;
    00424     }
    00425
    00426     if (table != NULL)
    00427     for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) {
    00428         if ((opt->longName || opt->shortName) &&
    00429             !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
    00430             singleOptionHelp(fp, left, opt, translation_domain);
    00431     }
    00432
    00433     if (table != NULL)
    00434     for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) {
    00435         if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_INCLUDE_TABLE)
    00436             continue;
    00437         sub_transdom = getTableTranslationDomain(opt->arg);
    00438         if (sub_transdom == NULL)
    00439             sub_transdom = translation_domain;
    00440
    00441         if (opt->descrip)
    00442             fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip));
    00443
    00444         singleTableHelp(con, fp, opt->arg, left, sub_transdom);
    00445     }
    00446 }
    00447
    00452 static int showHelpIntro(poptContext con, FILE * fp)
    00453         /*@globals fileSystem @*/
    00454         /*@modifies *fp, fileSystem @*/
    00455 {
    00456     int len = 6;
    00457     const char * fn;
    00458
    00459     fprintf(fp, POPT_("Usage:"));
    00460     if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) {
    00461         /*@-nullderef@*/        /* LCL: wazzup? */
    00462         fn = con->optionStack->argv[0];
    00463         /*@=nullderef@*/
    00464         if (fn == NULL) return len;
    00465         if (strchr(fn, '/')) fn = strrchr(fn, '/') + 1;
    00466         fprintf(fp, " %s", fn);
    00467         len += strlen(fn) + 1;
    00468     }
    00469
    00470     return len;
    00471 }
    00472
    00473 void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ int flags)
    00474 {
    00475     int leftColWidth;
    00476
    00477     (void) showHelpIntro(con, fp);
    00478     if (con->otherHelp)
    00479         fprintf(fp, " %s\n", con->otherHelp);
    00480     else
    00481         fprintf(fp, " %s\n", POPT_("[OPTION...]"));
    00482
    00483     leftColWidth = maxArgWidth(con->options, NULL);
    00484     singleTableHelp(con, fp, con->options, leftColWidth, NULL);
    00485 }
    00486
    00492 static int singleOptionUsage(FILE * fp, int cursor,
    00493                 const struct poptOption * opt,
    00494                 /*@null@*/ const char *translation_domain)
    00495         /*@globals fileSystem @*/
    00496         /*@modifies *fp, fileSystem @*/
    00497 {
    00498     int len = 3;
    00499     char shortStr[2] = { '\0', '\0' };
    00500     const char * item = shortStr;
    00501     const char * argDescrip = getArgDescrip(opt, translation_domain);
    00502
    00503     if (opt->shortName!= '\0' ) {
    00504         if (!(opt->argInfo & POPT_ARG_MASK))
    00505             return cursor;      /* we did these already */
    00506         len++;
    00507         shortStr[0] = opt->shortName;
    00508         shortStr[1] = '\0';
    00509     } else if (opt->longName) {
    00510         len += 1 + strlen(opt->longName);
    00511         item = opt->longName;
    00512     }
    00513
    00514     if (len == 3) return cursor;
    00515
    00516     if (argDescrip)
    00517         len += strlen(argDescrip) + 1;
    00518
    00519     if ((cursor + len) > 79) {
    00520         fprintf(fp, "\n       ");
    00521         cursor = 7;
    00522     }
    00523
    00524     fprintf(fp, " [-%s%s%s%s]",
    00525         ((opt->shortName || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) ? "" : "-"),
    00526         item,
    00527         (argDescrip ? (opt->shortName != '\0' ? " " : "=") : ""),
    00528         (argDescrip ? argDescrip : ""));
    00529
    00530     return cursor + len + 1;
    00531 }
    00532
    00540 static int itemUsage(FILE * fp, int cursor, poptItem item, int nitems,
    00541                 /*@null@*/ const char * translation_domain)
    00542         /*@globals fileSystem @*/
    00543         /*@modifies *fp, fileSystem @*/
    00544 {
    00545     int i;
    00546
    00547     /*@-branchstate@*/          /* FIX: W2DO? */
    00548     if (item != NULL)
    00549     for (i = 0; i < nitems; i++, item++) {
    00550         const struct poptOption * opt;
    00551         opt = &item->option;
    00552         if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) {
    00553             translation_domain = (const char *)opt->arg;
    00554         } else if ((opt->longName || opt->shortName) &&
    00555                  !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
    00556             cursor = singleOptionUsage(fp, cursor, opt, translation_domain);
    00557         }
    00558     }
    00559     /*@=branchstate@*/
    00560
    00561     return cursor;
    00562 }
    00563
    00569 static int singleTableUsage(poptContext con, FILE * fp,
    00570                 int cursor, const struct poptOption * opt,
    00571                 /*@null@*/ const char * translation_domain)
    00572         /*@globals fileSystem @*/
    00573         /*@modifies *fp, fileSystem @*/
    00574 {
    00575     /*@-branchstate@*/          /* FIX: W2DO? */
    00576     if (opt != NULL)
    00577     for (; (opt->longName || opt->shortName || opt->arg) ; opt++) {
    00578         if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) {
    00579             translation_domain = (const char *)opt->arg;
    00580         } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
    00581             if (opt->arg)       /* XXX program error */
    00582             cursor = singleTableUsage(con, fp, cursor, opt->arg,
    00583                         translation_domain);
    00584         } else if ((opt->longName || opt->shortName) &&
    00585                  !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
    00586             cursor = singleOptionUsage(fp, cursor, opt, translation_domain);
    00587         }
    00588     }
    00589     /*@=branchstate@*/
    00590
    00591     return cursor;
    00592 }
    00593
    00601 static int showShortOptions(const struct poptOption * opt, FILE * fp,
    00602                 /*@null@*/ char * str)
    00603         /*@globals fileSystem @*/
    00604         /*@modifies *str, *fp, fileSystem @*/
    00605 {
    00606     char * s = alloca(300);     /* larger then the ascii set */
    00607
    00608     s[0] = '\0';
    00609     /*@-branchstate@*/          /* FIX: W2DO? */
    00610     if (str == NULL) {
    00611         memset(s, 0, sizeof(s));
    00612         str = s;
    00613     }
    00614     /*@=branchstate@*/
    00615
    00616     if (opt != NULL)
    00617     for (; (opt->longName || opt->shortName || opt->arg); opt++) {
    00618         if (opt->shortName && !(opt->argInfo & POPT_ARG_MASK))
    00619             str[strlen(str)] = opt->shortName;
    00620         else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE)
    00621             if (opt->arg)       /* XXX program error */
    00622                 (void) showShortOptions(opt->arg, fp, str);
    00623     }
    00624
    00625     if (s != str || *s != '\0')
    00626         return 0;
    00627
    00628     fprintf(fp, " [-%s]", s);
    00629     return strlen(s) + 4;
    00630 }
    00631
    00632 void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ int flags)
    00633 {
    00634     int cursor;
    00635
    00636     cursor = showHelpIntro(con, fp);
    00637     cursor += showShortOptions(con->options, fp, NULL);
    00638     (void) singleTableUsage(con, fp, cursor, con->options, NULL);
    00639     (void) itemUsage(fp, cursor, con->aliases, con->numAliases, NULL);
    00640     (void) itemUsage(fp, cursor, con->execs, con->numExecs, NULL);
    00641
    00642     if (con->otherHelp) {
    00643         cursor += strlen(con->otherHelp) + 1;
    00644         if (cursor > 79) fprintf(fp, "\n       ");
    00645         fprintf(fp, " %s", con->otherHelp);
    00646     }
    00647
    00648     fprintf(fp, "\n");
    00649 }
    00650
    00651 void poptSetOtherOptionHelp(poptContext con, const char * text)
    00652 {
    00653     con->otherHelp = _free(con->otherHelp);
    00654     con->otherHelp = xstrdup(text);
    00655 }
    00656 /*@=type@*/