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@*/

Generated on Sat Mar 18 05:00:37 2006 for rpm by  doxygen 1.4.6