LCOV - code coverage report
Current view: top level - third_party/popt - popthelp.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 4 402 1.0 %
Date: 2024-04-21 15:09:00 Functions: 1 18 5.6 %

          Line data    Source code
       1             : /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
       2             : 
       3             : /** \ingroup popt
       4             :  * \file popt/popthelp.c
       5             :  */
       6             : 
       7             : /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
       8             :    file accompanying popt source distributions, available from 
       9             :    ftp://ftp.rpm.org/pub/rpm/dist. */
      10             : 
      11             : #include "system.h"
      12             : 
      13             : #define        POPT_USE_TIOCGWINSZ
      14             : #ifdef POPT_USE_TIOCGWINSZ
      15             : #include <sys/ioctl.h>
      16             : #endif
      17             : 
      18             : #define POPT_WCHAR_HACK
      19             : #ifdef  POPT_WCHAR_HACK
      20             : #include <wchar.h>                        /* for mbsrtowcs */
      21             : /*@access mbstate_t @*/
      22             : #endif
      23             : #include "poptint.h"
      24             : 
      25             : /*@access poptContext@*/
      26             : 
      27             : /**
      28             :  * Display arguments.
      29             :  * @param con           context
      30             :  * @param foo           (unused)
      31             :  * @param key           option(s)
      32             :  * @param arg           (unused)
      33             :  * @param data          (unused)
      34             :  */
      35             : /*@exits@*/
      36           0 : static void displayArgs(poptContext con,
      37             :                 /*@unused@*/ UNUSED(enum poptCallbackReason foo),
      38             :                 struct poptOption * key, 
      39             :                 /*@unused@*/ UNUSED(const char * arg),
      40             :                 /*@unused@*/ UNUSED(void * data))
      41             :         /*@globals fileSystem@*/
      42             :         /*@modifies fileSystem@*/
      43             : {
      44           0 :     if (key->shortName == '?')
      45           0 :         poptPrintHelp(con, stdout, 0);
      46             :     else
      47           0 :         poptPrintUsage(con, stdout, 0);
      48             : 
      49             : #if !defined(__LCLINT__)        /* XXX keep both splint & valgrind happy */
      50           0 :     con = poptFreeContext(con);
      51             : #endif
      52           0 :     exit(0);
      53             : }
      54             : 
      55             : #ifdef  NOTYET
      56             : /*@unchecked@*/
      57             : static int show_option_defaults = 0;
      58             : #endif
      59             : 
      60             : /**
      61             :  * Empty table marker to enable displaying popt alias/exec options.
      62             :  */
      63             : /*@observer@*/ /*@unchecked@*/
      64             : struct poptOption poptAliasOptions[] = {
      65             :     POPT_TABLEEND
      66             : };
      67             : 
      68             : /**
      69             :  * Auto help table options.
      70             :  */
      71             : /*@-castfcnptr@*/
      72             : /*@observer@*/ /*@unchecked@*/
      73             : struct poptOption poptHelpOptions[] = {
      74             :   { NULL, '\0', POPT_ARG_CALLBACK, (void *)displayArgs, 0, NULL, NULL },
      75             :   { "help", '?', 0, NULL, (int)'?', N_("Show this help message"), NULL },
      76             :   { "usage", '\0', 0, NULL, (int)'u', N_("Display brief usage message"), NULL },
      77             :     POPT_TABLEEND
      78             : } ;
      79             : 
      80             : /*@observer@*/ /*@unchecked@*/
      81             : static struct poptOption poptHelpOptions2[] = {
      82             : /*@-readonlytrans@*/
      83             :   { NULL, '\0', POPT_ARG_INTL_DOMAIN, PACKAGE, 0, NULL, NULL},
      84             : /*@=readonlytrans@*/
      85             :   { NULL, '\0', POPT_ARG_CALLBACK, (void *)displayArgs, 0, NULL, NULL },
      86             :   { "help", '?', 0, NULL, (int)'?', N_("Show this help message"), NULL },
      87             :   { "usage", '\0', 0, NULL, (int)'u', N_("Display brief usage message"), NULL },
      88             : #ifdef  NOTYET
      89             :   { "defaults", '\0', POPT_ARG_NONE, &show_option_defaults, 0,
      90             :         N_("Display option defaults in message"), NULL },
      91             : #endif
      92             :   { "", '\0', 0, NULL, 0, N_("Terminate options"), NULL },
      93             :     POPT_TABLEEND
      94             : } ;
      95             : 
      96             : /*@observer@*/ /*@unchecked@*/
      97             : struct poptOption * poptHelpOptionsI18N = poptHelpOptions2;
      98             : /*@=castfcnptr@*/
      99             : 
     100             : #define        _POPTHELP_MAXLINE       ((size_t)79)
     101             : 
     102             : typedef struct columns_s {
     103             :     size_t cur;
     104             :     size_t max;
     105             : } * columns_t;
     106             : 
     107             : /**
     108             :  * Return no. of columns in output window.
     109             :  * @param fp           FILE
     110             :  * @return             no. of columns
     111             :  */
     112           0 : static size_t maxColumnWidth(FILE *fp)
     113             :         /*@*/
     114             : {
     115           0 :     size_t maxcols = _POPTHELP_MAXLINE;
     116             : #if defined(TIOCGWINSZ)
     117             :     struct winsize ws;
     118           0 :     int fdno = fileno(fp ? fp : stdout);
     119             : 
     120           0 :     memset(&ws, 0, sizeof(ws));
     121           0 :     if (fdno >= 0 && !ioctl(fdno, (unsigned long)TIOCGWINSZ, &ws)) {
     122           0 :         size_t ws_col = (size_t)ws.ws_col;
     123           0 :         if (ws_col > maxcols && ws_col < (size_t)256)
     124           0 :             maxcols = ws_col - 1;
     125             :     }
     126             : #endif
     127           0 :     return maxcols;
     128             : }
     129             : 
     130             : /**
     131             :  * Determine number of display characters in a string.
     132             :  * @param s             string
     133             :  * @return              no. of display characters.
     134             :  */
     135           0 : static inline size_t stringDisplayWidth(const char *s)
     136             :         /*@*/
     137             : {
     138           0 :     size_t n = strlen(s);
     139             : #ifdef  POPT_WCHAR_HACK
     140             :     mbstate_t t;
     141             : 
     142           0 :     memset ((void *)&t, 0, sizeof (t));     /* In initial state.  */
     143             :     /* Determine number of display characters.  */
     144           0 :     n = mbsrtowcs (NULL, &s, n, &t);
     145             : #else
     146             :     n = 0;
     147             :     for (; *s; s = POPT_next_char(s))
     148             :         n++;
     149             : #endif
     150             : 
     151           0 :     return n;
     152             : }
     153             : 
     154             : /**
     155             :  * @param opt           option(s)
     156             :  */
     157             : /*@observer@*/ /*@null@*/ static const char *
     158           0 : getTableTranslationDomain(/*@null@*/ const struct poptOption *opt)
     159             :         /*@*/
     160             : {
     161           0 :     if (opt != NULL)
     162           0 :     for (; opt->longName || opt->shortName || opt->arg; opt++) {
     163           0 :         if (opt->argInfo == POPT_ARG_INTL_DOMAIN)
     164           0 :             return opt->arg;
     165             :     }
     166           0 :     return NULL;
     167             : }
     168             : 
     169             : /**
     170             :  * @param opt           option(s)
     171             :  * @param translation_domain    translation domain
     172             :  */
     173             : /*@observer@*/ /*@null@*/ static const char *
     174           0 : getArgDescrip(const struct poptOption * opt,
     175             :                 /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */
     176             :                 /*@null@*/ const char * translation_domain)
     177             :                 /*@=paramuse@*/
     178             :         /*@*/
     179             : {
     180           0 :     if (!poptArgType(opt)) return NULL;
     181             : 
     182           0 :     if (poptArgType(opt) == POPT_ARG_MAINCALL)
     183           0 :         return opt->argDescrip;
     184           0 :     if (poptArgType(opt) == POPT_ARG_ARGV)
     185           0 :         return opt->argDescrip;
     186             : 
     187           0 :     if (opt->argDescrip) {
     188             :         /* Some strings need popt library, not application, i18n domain. */
     189           0 :         if (opt == (poptHelpOptions + 1)
     190           0 :          || opt == (poptHelpOptions + 2)
     191           0 :          || !strcmp(opt->argDescrip, N_("Help options:"))
     192           0 :          || !strcmp(opt->argDescrip, N_("Options implemented via popt alias/exec:")))
     193           0 :             return POPT_(opt->argDescrip);
     194             : 
     195             :         /* Use the application i18n domain. */
     196           0 :         return D_(translation_domain, opt->argDescrip);
     197             :     }
     198             : 
     199           0 :     switch (poptArgType(opt)) {
     200           0 :     case POPT_ARG_NONE:         return POPT_("NONE");
     201             : #ifdef  DYING
     202             :     case POPT_ARG_VAL:          return POPT_("VAL");
     203             : #else
     204           0 :     case POPT_ARG_VAL:          return NULL;
     205             : #endif
     206           0 :     case POPT_ARG_INT:          return POPT_("INT");
     207           0 :     case POPT_ARG_SHORT:        return POPT_("SHORT");
     208           0 :     case POPT_ARG_LONG:         return POPT_("LONG");
     209           0 :     case POPT_ARG_LONGLONG:     return POPT_("LONGLONG");
     210           0 :     case POPT_ARG_STRING:       return POPT_("STRING");
     211           0 :     case POPT_ARG_FLOAT:        return POPT_("FLOAT");
     212           0 :     case POPT_ARG_DOUBLE:       return POPT_("DOUBLE");
     213           0 :     case POPT_ARG_MAINCALL:     return NULL;
     214           0 :     case POPT_ARG_ARGV:         return NULL;
     215           0 :     default:                    return POPT_("ARG");
     216             :     }
     217             : }
     218             : 
     219             : /**
     220             :  * Display default value for an option.
     221             :  * @param lineLength    display positions remaining
     222             :  * @param opt           option(s)
     223             :  * @param translation_domain    translation domain
     224             :  * @return
     225             :  */
     226             : static /*@only@*/ /*@null@*/ char *
     227           0 : singleOptionDefaultValue(size_t lineLength,
     228             :                 const struct poptOption * opt,
     229             :                 /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */
     230             :                 /*@null@*/ const char * translation_domain)
     231             :                 /*@=paramuse@*/
     232             :         /*@*/
     233             : {
     234           0 :     const char * defstr = D_(translation_domain, "default");
     235           0 :     char * le = malloc(4*lineLength + 1);
     236           0 :     char * l = le;
     237             : 
     238           0 :     if (le == NULL) return NULL;        /* XXX can't happen */
     239           0 :     *le = '\0';
     240           0 :     *le++ = '(';
     241           0 :     le = stpcpy(le, defstr);
     242           0 :     *le++ = ':';
     243           0 :     *le++ = ' ';
     244           0 :   if (opt->arg) {    /* XXX programmer error */
     245           0 :     poptArg arg = { .ptr = opt->arg };
     246           0 :     switch (poptArgType(opt)) {
     247           0 :     case POPT_ARG_VAL:
     248             :     case POPT_ARG_INT:
     249           0 :         le += sprintf(le, "%d", arg.intp[0]);
     250           0 :         break;
     251           0 :     case POPT_ARG_SHORT:
     252           0 :         le += sprintf(le, "%hd", arg.shortp[0]);
     253           0 :         break;
     254           0 :     case POPT_ARG_LONG:
     255           0 :         le += sprintf(le, "%ld", arg.longp[0]);
     256           0 :         break;
     257           0 :     case POPT_ARG_LONGLONG:
     258           0 :         le += sprintf(le, "%lld", arg.longlongp[0]);
     259           0 :         break;
     260           0 :     case POPT_ARG_FLOAT:
     261           0 :     {   double aDouble = (double) arg.floatp[0];
     262           0 :         le += sprintf(le, "%g", aDouble);
     263           0 :     }   break;
     264           0 :     case POPT_ARG_DOUBLE:
     265           0 :         le += sprintf(le, "%g", arg.doublep[0]);
     266           0 :         break;
     267           0 :     case POPT_ARG_MAINCALL:
     268           0 :         le += sprintf(le, "%p", opt->arg);
     269           0 :         break;
     270           0 :     case POPT_ARG_ARGV:
     271           0 :         le += sprintf(le, "%p", opt->arg);
     272           0 :         break;
     273           0 :     case POPT_ARG_STRING:
     274           0 :     {   const char * s = arg.argv[0];
     275           0 :         if (s == NULL)
     276           0 :             le = stpcpy(le, "null");
     277             :         else {
     278           0 :             size_t limit = 4*lineLength - (le - l) - sizeof("\"\")");
     279             :             size_t slen;
     280           0 :             *le++ = '"';
     281           0 :             strncpy(le, s, limit); le[limit] = '\0'; le += (slen = strlen(le));
     282           0 :             if (slen == limit && s[limit])
     283           0 :                 le[-1] = le[-2] = le[-3] = '.';
     284           0 :             *le++ = '"';
     285             :         }
     286           0 :     }   break;
     287           0 :     case POPT_ARG_NONE:
     288             :     default:
     289           0 :         l = _free(l);
     290           0 :         return NULL;
     291             :         /*@notreached@*/ break;
     292             :     }
     293             :   }
     294           0 :     *le++ = ')';
     295           0 :     *le = '\0';
     296             : 
     297           0 :     return l;
     298             : }
     299             : 
     300             : /**
     301             :  * Display help text for an option.
     302             :  * @param fp            output file handle
     303             :  * @param columns       output display width control
     304             :  * @param opt           option(s)
     305             :  * @param translation_domain    translation domain
     306             :  */
     307           0 : static void singleOptionHelp(FILE * fp, columns_t columns,
     308             :                 const struct poptOption * opt,
     309             :                 /*@null@*/ const char * translation_domain)
     310             :         /*@globals fileSystem @*/
     311             :         /*@modifies fp, fileSystem @*/
     312             : {
     313           0 :     size_t maxLeftCol = columns->cur;
     314           0 :     size_t indentLength = maxLeftCol + 5;
     315           0 :     size_t lineLength = columns->max - indentLength;
     316           0 :     const char * help = D_(translation_domain, opt->descrip);
     317           0 :     const char * argDescrip = getArgDescrip(opt, translation_domain);
     318             :     /* Display shortName iff printable non-space. */
     319           0 :     int prtshort = (int)(isprint((int)opt->shortName) && opt->shortName != ' ');
     320             :     size_t helpLength;
     321           0 :     char * defs = NULL;
     322             :     char * left;
     323           0 :     size_t nb = maxLeftCol + 1;
     324           0 :     int displaypad = 0;
     325             :     int xx;
     326             : 
     327             :     /* Make sure there's more than enough room in target buffer. */
     328           0 :     if (opt->longName)       nb += strlen(opt->longName);
     329           0 :     if (F_ISSET(opt, TOGGLE)) nb += sizeof("[no]") - 1;
     330           0 :     if (argDescrip)     nb += strlen(argDescrip);
     331             : 
     332           0 :     left = malloc(nb);
     333           0 :     if (left == NULL) return;   /* XXX can't happen */
     334           0 :     left[0] = '\0';
     335           0 :     left[maxLeftCol] = '\0';
     336             : 
     337             : #define prtlong (opt->longName != NULL)      /* XXX splint needs a clue */
     338           0 :     if (!(prtshort || prtlong))
     339           0 :         goto out;
     340           0 :     if (prtshort && prtlong) {
     341           0 :         char *dash = F_ISSET(opt, ONEDASH) ? "-" : "--";
     342           0 :         left[0] = '-';
     343           0 :         left[1] = opt->shortName;
     344           0 :         (void) stpcpy(stpcpy(stpcpy(left+2, ", "), dash), opt->longName);
     345           0 :     } else if (prtshort) {
     346           0 :         left[0] = '-';
     347           0 :         left[1] = opt->shortName;
     348           0 :         left[2] = '\0';
     349           0 :     } else if (prtlong) {
     350             :         /* XXX --long always padded for alignment with/without "-X, ". */
     351           0 :         char *dash = poptArgType(opt) == POPT_ARG_MAINCALL ? ""
     352           0 :                    : (F_ISSET(opt, ONEDASH) ? "-" : "--");
     353           0 :         const char *longName = opt->longName;
     354             :         const char *toggle;
     355           0 :         if (F_ISSET(opt, TOGGLE)) {
     356           0 :             toggle = "[no]";
     357           0 :             if (longName[0] == 'n' && longName[1] == 'o') {
     358           0 :                 longName += sizeof("no") - 1;
     359           0 :                 if (longName[0] == '-')
     360           0 :                     longName++;
     361             :             }
     362             :         } else
     363           0 :             toggle = "";
     364           0 :         (void) stpcpy(stpcpy(stpcpy(stpcpy(left, "    "), dash), toggle), longName);
     365             :     }
     366             : #undef  prtlong
     367             : 
     368           0 :     if (argDescrip) {
     369           0 :         char * le = left + strlen(left);
     370             : 
     371           0 :         if (F_ISSET(opt, OPTIONAL))
     372           0 :             *le++ = '[';
     373             : 
     374             :         /* Choose type of output */
     375           0 :         if (F_ISSET(opt, SHOW_DEFAULT)) {
     376           0 :             defs = singleOptionDefaultValue(lineLength, opt, translation_domain);
     377           0 :             if (defs) {
     378           0 :                 char * t = malloc((help ? strlen(help) : 0) +
     379           0 :                                 strlen(defs) + sizeof(" "));
     380           0 :                 if (t) {
     381           0 :                     char * te = t;
     382           0 :                     if (help)
     383           0 :                         te = stpcpy(te, help);
     384           0 :                     *te++ = ' ';
     385           0 :                     strcpy(te, defs);
     386           0 :                     defs = _free(defs);
     387           0 :                     defs = t;
     388             :                 }
     389             :             }
     390             :         }
     391             : 
     392           0 :         if (opt->argDescrip == NULL) {
     393           0 :             switch (poptArgType(opt)) {
     394           0 :             case POPT_ARG_NONE:
     395           0 :                 break;
     396           0 :             case POPT_ARG_VAL:
     397             : #ifdef  NOTNOW  /* XXX pug ugly nerdy output */
     398             :             {   long aLong = opt->val;
     399             :                 int ops = F_ISSET(opt, LOGICALOPS);
     400             :                 int negate = F_ISSET(opt, NOT);
     401             : 
     402             :                 /* Don't bother displaying typical values */
     403             :                 if (!ops && (aLong == 0L || aLong == 1L || aLong == -1L))
     404             :                     break;
     405             :                 *le++ = '[';
     406             :                 switch (ops) {
     407             :                 case POPT_ARGFLAG_OR:
     408             :                     *le++ = '|';
     409             :                     /*@innerbreak@*/ break;
     410             :                 case POPT_ARGFLAG_AND:
     411             :                     *le++ = '&';
     412             :                     /*@innerbreak@*/ break;
     413             :                 case POPT_ARGFLAG_XOR:
     414             :                     *le++ = '^';
     415             :                     /*@innerbreak@*/ break;
     416             :                 default:
     417             :                     /*@innerbreak@*/ break;
     418             :                 }
     419             :                 *le++ = (opt->longName != NULL ? '=' : ' ');
     420             :                 if (negate) *le++ = '~';
     421             :                 /*@-formatconst@*/
     422             :                 le += sprintf(le, (ops ? "0x%lx" : "%ld"), aLong);
     423             :                 /*@=formatconst@*/
     424             :                 *le++ = ']';
     425             :             }
     426             : #endif
     427           0 :                 break;
     428           0 :             case POPT_ARG_INT:
     429             :             case POPT_ARG_SHORT:
     430             :             case POPT_ARG_LONG:
     431             :             case POPT_ARG_LONGLONG:
     432             :             case POPT_ARG_FLOAT:
     433             :             case POPT_ARG_DOUBLE:
     434             :             case POPT_ARG_STRING:
     435           0 :                 *le++ = (opt->longName != NULL ? '=' : ' ');
     436           0 :                 le = stpcpy(le, argDescrip);
     437           0 :                 break;
     438           0 :             default:
     439           0 :                 break;
     440             :             }
     441             :         } else {
     442             :             char *leo;
     443             : 
     444             :             /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */
     445           0 :             if (!strchr(" =(", argDescrip[0]))
     446           0 :                 *le++ = ((poptArgType(opt) == POPT_ARG_MAINCALL) ? ' ' :
     447           0 :                          (poptArgType(opt) == POPT_ARG_ARGV) ? ' ' : '=');
     448           0 :             le = stpcpy(leo = le, argDescrip);
     449             : 
     450             :             /* Adjust for (possible) wide characters. */
     451           0 :             displaypad = (int)((le - leo) - stringDisplayWidth(argDescrip));
     452             :         }
     453           0 :         if (F_ISSET(opt, OPTIONAL))
     454           0 :             *le++ = ']';
     455           0 :         *le = '\0';
     456             :     }
     457             : 
     458           0 :     if (help)
     459           0 :         xx = POPT_fprintf(fp,"  %-*s   ", (int)(maxLeftCol+displaypad), left);
     460             :     else {
     461           0 :         xx = POPT_fprintf(fp,"  %s\n", left);
     462           0 :         goto out;
     463             :     }
     464             : 
     465           0 :     left = _free(left);
     466           0 :     if (defs)
     467           0 :         help = defs;
     468             : 
     469           0 :     helpLength = strlen(help);
     470           0 :     while (helpLength > lineLength) {
     471             :         const char * ch;
     472             :         char format[16];
     473             : 
     474           0 :         ch = help + lineLength - 1;
     475           0 :         while (ch > help && !_isspaceptr(ch))
     476           0 :             ch = POPT_prev_char(ch);
     477           0 :         if (ch == help) break;          /* give up */
     478           0 :         while (ch > (help + 1) && _isspaceptr(ch))
     479           0 :             ch = POPT_prev_char (ch);
     480           0 :         ch = POPT_next_char(ch);
     481             : 
     482             :         /*
     483             :          *  XXX strdup is necessary to add NUL terminator so that an unknown
     484             :          *  no. of (possible) multi-byte characters can be displayed.
     485             :          */
     486           0 :         {   char * fmthelp = xstrdup(help);
     487           0 :             if (fmthelp) {
     488           0 :                 fmthelp[ch - help] = '\0';
     489           0 :                 sprintf(format, "%%s\n%%%ds", (int) indentLength);
     490             :                 /*@-formatconst@*/
     491           0 :                 xx = POPT_fprintf(fp, format, fmthelp, " ");
     492             :                 /*@=formatconst@*/
     493           0 :                 free(fmthelp);
     494             :             }
     495             :         }
     496             : 
     497           0 :         help = ch;
     498           0 :         while (_isspaceptr(help) && *help)
     499           0 :             help = POPT_next_char(help);
     500           0 :         helpLength = strlen(help);
     501             :     }
     502             : 
     503           0 :     if (helpLength) fprintf(fp, "%s\n", help);
     504           0 :     help = NULL;
     505             : 
     506           0 : out:
     507             :     /*@-dependenttrans@*/
     508           0 :     defs = _free(defs);
     509             :     /*@=dependenttrans@*/
     510           0 :     left = _free(left);
     511             : }
     512             : 
     513             : /**
     514             :  * Find display width for longest argument string.
     515             :  * @param opt           option(s)
     516             :  * @param translation_domain    translation domain
     517             :  * @return              display width
     518             :  */
     519           0 : static size_t maxArgWidth(const struct poptOption * opt,
     520             :                        /*@null@*/ const char * translation_domain)
     521             :         /*@*/
     522             : {
     523           0 :     size_t max = 0;
     524           0 :     size_t len = 0;
     525             :     const char * argDescrip;
     526             :     
     527           0 :     if (opt != NULL)
     528           0 :     while (opt->longName || opt->shortName || opt->arg) {
     529           0 :         if (poptArgType(opt) == POPT_ARG_INCLUDE_TABLE) {
     530           0 :             if (opt->arg)    /* XXX program error */
     531           0 :                 len = maxArgWidth(opt->arg, translation_domain);
     532           0 :             if (len > max) max = len;
     533           0 :         } else if (!F_ISSET(opt, DOC_HIDDEN)) {
     534           0 :             len = sizeof("  ")-1;
     535             :             /* XXX --long always padded for alignment with/without "-X, ". */
     536           0 :             len += sizeof("-X, ")-1;
     537           0 :             if (opt->longName) {
     538           0 :                 len += (F_ISSET(opt, ONEDASH) ? sizeof("-") : sizeof("--")) - 1;
     539           0 :                 len += strlen(opt->longName);
     540             :             }
     541             : 
     542           0 :             argDescrip = getArgDescrip(opt, translation_domain);
     543             : 
     544           0 :             if (argDescrip) {
     545             : 
     546             :                 /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */
     547           0 :                 if (!strchr(" =(", argDescrip[0])) len += sizeof("=")-1;
     548             : 
     549             :                 /* Adjust for (possible) wide characters. */
     550           0 :                 len += stringDisplayWidth(argDescrip);
     551             :             }
     552             : 
     553           0 :             if (F_ISSET(opt, OPTIONAL)) len += sizeof("[]")-1;
     554           0 :             if (len > max) max = len;
     555             :         }
     556           0 :         opt++;
     557             :     }
     558             :     
     559           0 :     return max;
     560             : }
     561             : 
     562             : /**
     563             :  * Display popt alias and exec help.
     564             :  * @param fp            output file handle
     565             :  * @param items         alias/exec array
     566             :  * @param nitems        no. of alias/exec entries
     567             :  * @param columns       output display width control
     568             :  * @param translation_domain    translation domain
     569             :  */
     570           0 : static void itemHelp(FILE * fp,
     571             :                 /*@null@*/ poptItem items, int nitems,
     572             :                 columns_t columns,
     573             :                 /*@null@*/ const char * translation_domain)
     574             :         /*@globals fileSystem @*/
     575             :         /*@modifies fp, fileSystem @*/
     576             : {
     577             :     poptItem item;
     578             :     int i;
     579             : 
     580           0 :     if (items != NULL)
     581           0 :     for (i = 0, item = items; i < nitems; i++, item++) {
     582             :         const struct poptOption * opt;
     583           0 :         opt = &item->option;
     584           0 :         if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN))
     585           0 :             singleOptionHelp(fp, columns, opt, translation_domain);
     586             :     }
     587           0 : }
     588             : 
     589             : /**
     590             :  * Display help text for a table of options.
     591             :  * @param con           context
     592             :  * @param fp            output file handle
     593             :  * @param table         option(s)
     594             :  * @param columns       output display width control
     595             :  * @param translation_domain    translation domain
     596             :  */
     597           0 : static void singleTableHelp(poptContext con, FILE * fp,
     598             :                 /*@null@*/ const struct poptOption * table,
     599             :                 columns_t columns,
     600             :                 /*@null@*/ const char * translation_domain)
     601             :         /*@globals fileSystem @*/
     602             :         /*@modifies fp, columns->cur, fileSystem @*/
     603             : {
     604             :     const struct poptOption * opt;
     605             :     const char *sub_transdom;
     606             :     int xx;
     607             : 
     608           0 :     if (table == poptAliasOptions) {
     609           0 :         itemHelp(fp, con->aliases, con->numAliases, columns, NULL);
     610           0 :         itemHelp(fp, con->execs, con->numExecs, columns, NULL);
     611           0 :         return;
     612             :     }
     613             : 
     614           0 :     if (table != NULL)
     615           0 :     for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) {
     616           0 :         if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN))
     617           0 :             singleOptionHelp(fp, columns, opt, translation_domain);
     618             :     }
     619             : 
     620           0 :     if (table != NULL)
     621           0 :     for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) {
     622           0 :         if (poptArgType(opt) != POPT_ARG_INCLUDE_TABLE)
     623           0 :             continue;
     624           0 :         sub_transdom = getTableTranslationDomain(opt->arg);
     625           0 :         if (sub_transdom == NULL)
     626           0 :             sub_transdom = translation_domain;
     627             :             
     628             :         /* If no popt aliases/execs, skip poptAliasOption processing. */
     629           0 :         if (opt->arg == poptAliasOptions && !(con->numAliases || con->numExecs))
     630           0 :             continue;
     631           0 :         if (opt->descrip)
     632           0 :             xx = POPT_fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip));
     633             : 
     634           0 :         singleTableHelp(con, fp, opt->arg, columns, sub_transdom);
     635             :     }
     636             : }
     637             : 
     638             : /**
     639             :  * @param con           context
     640             :  * @param fp            output file handle
     641             :  */
     642           0 : static size_t showHelpIntro(poptContext con, FILE * fp)
     643             :         /*@globals fileSystem @*/
     644             :         /*@modifies fp, fileSystem @*/
     645             : {
     646           0 :     size_t len = (size_t)6;
     647             :     int xx;
     648             : 
     649           0 :     xx = POPT_fprintf(fp, POPT_("Usage:"));
     650           0 :     if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) {
     651           0 :         struct optionStackEntry * os = con->optionStack;
     652           0 :         const char * fn = (os->argv ? os->argv[0] : NULL);
     653           0 :         if (fn == NULL) return len;
     654           0 :         if (strchr(fn, '/')) fn = strrchr(fn, '/') + 1;
     655             :         /* XXX POPT_fprintf not needed for argv[0] display. */
     656           0 :         fprintf(fp, " %s", fn);
     657           0 :         len += strlen(fn) + 1;
     658             :     }
     659             : 
     660           0 :     return len;
     661             : }
     662             : 
     663           0 : void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags))
     664             : {
     665           0 :     columns_t columns = calloc((size_t)1, sizeof(*columns));
     666             :     int xx;
     667             : 
     668           0 :     (void) showHelpIntro(con, fp);
     669           0 :     if (con->otherHelp)
     670           0 :         xx = POPT_fprintf(fp, " %s\n", con->otherHelp);
     671             :     else
     672           0 :         xx = POPT_fprintf(fp, " %s\n", POPT_("[OPTION...]"));
     673             : 
     674           0 :     if (columns) {
     675           0 :         columns->cur = maxArgWidth(con->options, NULL);
     676           0 :         columns->max = maxColumnWidth(fp);
     677           0 :         singleTableHelp(con, fp, con->options, columns, NULL);
     678           0 :         free(columns);
     679             :     }
     680           0 : }
     681             : 
     682             : /**
     683             :  * Display usage text for an option.
     684             :  * @param fp            output file handle
     685             :  * @param columns       output display width control
     686             :  * @param opt           option(s)
     687             :  * @param translation_domain    translation domain
     688             :  */
     689           0 : static size_t singleOptionUsage(FILE * fp, columns_t columns,
     690             :                 const struct poptOption * opt,
     691             :                 /*@null@*/ const char *translation_domain)
     692             :         /*@globals fileSystem @*/
     693             :         /*@modifies fp, columns->cur, fileSystem @*/
     694             : {
     695           0 :     size_t len = sizeof(" []")-1;
     696           0 :     const char * argDescrip = getArgDescrip(opt, translation_domain);
     697             :     /* Display shortName iff printable non-space. */
     698           0 :     int prtshort = (int)(isprint((int)opt->shortName) && opt->shortName != ' ');
     699             : 
     700             : #define prtlong (opt->longName != NULL)      /* XXX splint needs a clue */
     701           0 :     if (!(prtshort || prtlong))
     702           0 :         return columns->cur;
     703             : 
     704           0 :     len = sizeof(" []")-1;
     705           0 :     if (prtshort)
     706           0 :         len += sizeof("-c")-1;
     707           0 :     if (prtlong) {
     708           0 :         if (prtshort) len += sizeof("|")-1;
     709           0 :         len += (F_ISSET(opt, ONEDASH) ? sizeof("-") : sizeof("--")) - 1;
     710           0 :         len += strlen(opt->longName);
     711             :     }
     712             : 
     713           0 :     if (argDescrip) {
     714             : 
     715             :         /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */
     716           0 :         if (!strchr(" =(", argDescrip[0])) len += sizeof("=")-1;
     717             : 
     718             :         /* Adjust for (possible) wide characters. */
     719           0 :         len += stringDisplayWidth(argDescrip);
     720             :     }
     721             : 
     722           0 :     if ((columns->cur + len) > columns->max) {
     723           0 :         fprintf(fp, "\n       ");
     724           0 :         columns->cur = (size_t)7;
     725             :     } 
     726             : 
     727           0 :     fprintf(fp, " [");
     728           0 :     if (prtshort)
     729           0 :         fprintf(fp, "-%c", opt->shortName);
     730           0 :     if (prtlong)
     731           0 :         fprintf(fp, "%s%s%s",
     732             :                 (prtshort ? "|" : ""),
     733           0 :                 (F_ISSET(opt, ONEDASH) ? "-" : "--"),
     734           0 :                 opt->longName);
     735             : #undef  prtlong
     736             : 
     737           0 :     if (argDescrip) {
     738             :         /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */
     739           0 :         if (!strchr(" =(", argDescrip[0])) fprintf(fp, "=");
     740           0 :         fprintf(fp, "%s", argDescrip);
     741             :     }
     742           0 :     fprintf(fp, "]");
     743             : 
     744           0 :     return columns->cur + len + 1;
     745             : }
     746             : 
     747             : /**
     748             :  * Display popt alias and exec usage.
     749             :  * @param fp            output file handle
     750             :  * @param columns       output display width control
     751             :  * @param item          alias/exec array
     752             :  * @param nitems        no. of ara/exec entries
     753             :  * @param translation_domain    translation domain
     754             :  */
     755           0 : static size_t itemUsage(FILE * fp, columns_t columns,
     756             :                 /*@null@*/ poptItem item, int nitems,
     757             :                 /*@null@*/ const char * translation_domain)
     758             :         /*@globals fileSystem @*/
     759             :         /*@modifies fp, columns->cur, fileSystem @*/
     760             : {
     761             :     int i;
     762             : 
     763           0 :     if (item != NULL)
     764           0 :     for (i = 0; i < nitems; i++, item++) {
     765             :         const struct poptOption * opt;
     766           0 :         opt = &item->option;
     767           0 :         if (poptArgType(opt) == POPT_ARG_INTL_DOMAIN) {
     768           0 :             translation_domain = (const char *)opt->arg;
     769             :         } else
     770           0 :         if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN)) {
     771           0 :             columns->cur = singleOptionUsage(fp, columns, opt, translation_domain);
     772             :         }
     773             :     }
     774             : 
     775           0 :     return columns->cur;
     776             : }
     777             : 
     778             : /**
     779             :  * Keep track of option tables already processed.
     780             :  */
     781             : typedef struct poptDone_s {
     782             :     int nopts;
     783             :     int maxopts;
     784             : /*@null@*/
     785             :     const void ** opts;
     786             : } * poptDone;
     787             : 
     788             : /**
     789             :  * Display usage text for a table of options.
     790             :  * @param con           context
     791             :  * @param fp            output file handle
     792             :  * @param columns       output display width control
     793             :  * @param opt           option(s)
     794             :  * @param translation_domain    translation domain
     795             :  * @param done          tables already processed
     796             :  * @return
     797             :  */
     798           0 : static size_t singleTableUsage(poptContext con, FILE * fp, columns_t columns,
     799             :                 /*@null@*/ const struct poptOption * opt,
     800             :                 /*@null@*/ const char * translation_domain,
     801             :                 /*@null@*/ poptDone done)
     802             :         /*@globals fileSystem @*/
     803             :         /*@modifies fp, columns->cur, done, fileSystem @*/
     804             : {
     805           0 :     if (opt != NULL)
     806           0 :     for (; (opt->longName || opt->shortName || opt->arg) ; opt++) {
     807           0 :         if (poptArgType(opt) == POPT_ARG_INTL_DOMAIN) {
     808           0 :             translation_domain = (const char *)opt->arg;
     809             :         } else
     810           0 :         if (poptArgType(opt) == POPT_ARG_INCLUDE_TABLE) {
     811           0 :             if (done) {
     812           0 :                 int i = 0;
     813           0 :                 if (done->opts != NULL)
     814           0 :                 for (i = 0; i < done->nopts; i++) {
     815           0 :                     const void * that = done->opts[i];
     816           0 :                     if (that == NULL || that != opt->arg)
     817           0 :                         /*@innercontinue@*/ continue;
     818           0 :                     /*@innerbreak@*/ break;
     819             :                 }
     820             :                 /* Skip if this table has already been processed. */
     821           0 :                 if (opt->arg == NULL || i < done->nopts)
     822           0 :                     continue;
     823           0 :                 if (done->opts != NULL && done->nopts < done->maxopts)
     824           0 :                     done->opts[done->nopts++] = (const void *) opt->arg;
     825             :             }
     826           0 :             columns->cur = singleTableUsage(con, fp, columns, opt->arg,
     827             :                         translation_domain, done);
     828             :         } else
     829           0 :         if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN)) {
     830           0 :             columns->cur = singleOptionUsage(fp, columns, opt, translation_domain);
     831             :         }
     832             :     }
     833             : 
     834           0 :     return columns->cur;
     835             : }
     836             : 
     837             : /**
     838             :  * Return concatenated short options for display.
     839             :  * @todo Sub-tables should be recursed.
     840             :  * @param opt           option(s)
     841             :  * @param fp            output file handle
     842             :  * @retval str          concatenation of short options
     843             :  * @return              length of display string
     844             :  */
     845           0 : static size_t showShortOptions(const struct poptOption * opt, FILE * fp,
     846             :                 /*@null@*/ char * str)
     847             :         /*@globals fileSystem @*/
     848             :         /*@modifies str, *fp, fileSystem @*/
     849             :         /*@requires maxRead(str) >= 0 @*/
     850             : {
     851             :     /* bufsize larger then the ascii set, lazy allocation on top level call. */
     852           0 :     size_t nb = (size_t)300;
     853           0 :     char * s = (str != NULL ? str : calloc((size_t)1, nb));
     854           0 :     size_t len = (size_t)0;
     855             : 
     856           0 :     if (s == NULL)
     857           0 :         return 0;
     858             : 
     859           0 :     if (opt != NULL)
     860           0 :     for (; (opt->longName || opt->shortName || opt->arg); opt++) {
     861           0 :         if (!F_ISSET(opt, DOC_HIDDEN) && opt->shortName && !poptArgType(opt))
     862             :         {
     863             :             /* Display shortName iff unique printable non-space. */
     864           0 :             if (!strchr(s, opt->shortName) && isprint((int)opt->shortName)
     865           0 :              && opt->shortName != ' ')
     866           0 :                 s[strlen(s)] = opt->shortName;
     867           0 :         } else if (poptArgType(opt) == POPT_ARG_INCLUDE_TABLE)
     868           0 :             if (opt->arg)    /* XXX program error */
     869           0 :                 len = showShortOptions(opt->arg, fp, s);
     870             :     } 
     871             : 
     872             :     /* On return to top level, print the short options, return print length. */
     873           0 :     if (s != str && *s != '\0') {
     874           0 :         fprintf(fp, " [-%s]", s);
     875           0 :         len = strlen(s) + sizeof(" [-]")-1;
     876             :     }
     877             : /*@-temptrans@*/        /* LCL: local s, not str arg, is being freed. */
     878           0 :     if (s != str)
     879           0 :         free(s);
     880             : /*@=temptrans@*/
     881           0 :     return len;
     882             : }
     883             : 
     884           0 : void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags))
     885             : {
     886           0 :     columns_t columns = calloc((size_t)1, sizeof(*columns));
     887             :     struct poptDone_s done_buf;
     888           0 :     poptDone done = &done_buf;
     889             : 
     890           0 :     memset(done, 0, sizeof(*done));
     891           0 :     done->nopts = 0;
     892           0 :     done->maxopts = 64;
     893           0 :   if (columns) {
     894           0 :     columns->cur = done->maxopts * sizeof(*done->opts);
     895           0 :     columns->max = maxColumnWidth(fp);
     896           0 :     done->opts = calloc((size_t)1, columns->cur);
     897             :     /*@-keeptrans@*/
     898           0 :     if (done->opts != NULL)
     899           0 :         done->opts[done->nopts++] = (const void *) con->options;
     900             :     /*@=keeptrans@*/
     901             : 
     902           0 :     columns->cur = showHelpIntro(con, fp);
     903           0 :     columns->cur += showShortOptions(con->options, fp, NULL);
     904           0 :     columns->cur = singleTableUsage(con, fp, columns, con->options, NULL, done);
     905           0 :     columns->cur = itemUsage(fp, columns, con->aliases, con->numAliases, NULL);
     906           0 :     columns->cur = itemUsage(fp, columns, con->execs, con->numExecs, NULL);
     907             : 
     908           0 :     if (con->otherHelp) {
     909           0 :         columns->cur += strlen(con->otherHelp) + 1;
     910           0 :         if (columns->cur > columns->max) fprintf(fp, "\n       ");
     911           0 :         fprintf(fp, " %s", con->otherHelp);
     912             :     }
     913             : 
     914           0 :     fprintf(fp, "\n");
     915           0 :     if (done->opts != NULL)
     916           0 :         free(done->opts);
     917           0 :     free(columns);
     918             :   }
     919           0 : }
     920             : 
     921          15 : void poptSetOtherOptionHelp(poptContext con, const char * text)
     922             : {
     923          15 :     con->otherHelp = _free(con->otherHelp);
     924          15 :     con->otherHelp = xstrdup(text);
     925          15 : }

Generated by: LCOV version 1.14