Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

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

Generated at Wed Mar 27 03:56:51 2002 for rpm by doxygen1.2.8.1 written by Dimitri van Heesch, © 1997-2001