root/lib/popt/popthelp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. displayArgs
  2. getTableTranslationDomain
  3. getArgDescrip
  4. singleOptionDefaultValue
  5. singleOptionHelp
  6. maxArgWidth
  7. itemHelp
  8. singleTableHelp
  9. showHelpIntro
  10. poptPrintHelp
  11. singleOptionUsage
  12. itemUsage
  13. singleTableUsage
  14. showShortOptions
  15. poptPrintUsage
  16. poptSetOtherOptionHelp

   1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
   2 
   3 /*@-type@*/
   4 /** \ingroup popt
   5  * \file popt/popthelp.c
   6  */
   7 
   8 /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
   9    file accompanying popt source distributions, available from 
  10    ftp://ftp.rpm.org/pub/rpm/dist. */
  11 
  12 #include "system.h"
  13 #include "poptint.h"
  14 
  15 /**
  16  * Display arguments.
  17  * @param con           context
  18  * @param foo           (unused)
  19  * @param key           option(s)
  20  * @param arg           (unused)
  21  * @param data          (unused)
  22  */
  23 static void displayArgs(poptContext con,
     /* [<][>][^][v][top][bottom][index][help] */
  24                 /*@unused@*/ enum poptCallbackReason foo,
  25                 struct poptOption * key, 
  26                 /*@unused@*/ const char * arg, /*@unused@*/ void * data)
  27         /*@globals fileSystem@*/
  28         /*@modifies fileSystem@*/
  29 {
  30     if (key->shortName == '?')
  31         poptPrintHelp(con, stdout, 0);
  32     else
  33         poptPrintUsage(con, stdout, 0);
  34     exit(0);
  35 }
  36 
  37 #ifdef  NOTYET
  38 /*@unchecked@*/
  39 static int show_option_defaults = 0;
  40 #endif
  41 
  42 /**
  43  * Empty table marker to enable displaying popt alias/exec options.
  44  */
  45 /*@observer@*/ /*@unchecked@*/
  46 struct poptOption poptAliasOptions[] = {
  47     POPT_TABLEEND
  48 };
  49 
  50 /**
  51  * Auto help table options.
  52  */
  53 /*@-castfcnptr@*/
  54 /*@observer@*/ /*@unchecked@*/
  55 struct poptOption poptHelpOptions[] = {
  56   { NULL, '\0', POPT_ARG_CALLBACK, (void *)&displayArgs, '\0', NULL, NULL },
  57   { "help", '?', 0, NULL, '?', N_("Show this help message"), NULL },
  58   { "usage", '\0', 0, NULL, 'u', N_("Display brief usage message"), NULL },
  59 #ifdef  NOTYET
  60   { "defaults", '\0', POPT_ARG_NONE, &show_option_defaults, 0,
  61         N_("Display option defaults in message"), NULL },
  62 #endif
  63     POPT_TABLEEND
  64 } ;
  65 /*@=castfcnptr@*/
  66 
  67 /**
  68  * @param table         option(s)
  69  */
  70 /*@observer@*/ /*@null@*/ static const char *
  71 getTableTranslationDomain(/*@null@*/ const struct poptOption *table)
     /* [<][>][^][v][top][bottom][index][help] */
  72         /*@*/
  73 {
  74     const struct poptOption *opt;
  75 
  76     if (table != NULL)
  77     for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) {
  78         if (opt->argInfo == POPT_ARG_INTL_DOMAIN)
  79             return (char *)opt->arg;
  80     }
  81     return NULL;
  82 }
  83 
  84 /**
  85  * @param opt           option(s)
  86  * @param translation_domain    translation domain
  87  */
  88 /*@observer@*/ /*@null@*/ static const char *
  89 getArgDescrip(const struct poptOption * opt,
     /* [<][>][^][v][top][bottom][index][help] */
  90                 /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */
  91                 /*@null@*/ const char * translation_domain)
  92                 /*@=paramuse@*/
  93         /*@*/
  94 {
  95     if (!(opt->argInfo & POPT_ARG_MASK)) return NULL;
  96 
  97     if (opt == (poptHelpOptions + 1) || opt == (poptHelpOptions + 2))
  98         if (opt->argDescrip) return POPT_(opt->argDescrip);
  99 
 100     if (opt->argDescrip) return D_(translation_domain, opt->argDescrip);
 101 
 102     switch (opt->argInfo & POPT_ARG_MASK) {
 103     case POPT_ARG_NONE:         return POPT_("NONE");
 104 #ifdef  DYING
 105     case POPT_ARG_VAL:          return POPT_("VAL");
 106 #else
 107     case POPT_ARG_VAL:          return NULL;
 108 #endif
 109     case POPT_ARG_INT:          return POPT_("INT");
 110     case POPT_ARG_LONG:         return POPT_("LONG");
 111     case POPT_ARG_STRING:       return POPT_("STRING");
 112     case POPT_ARG_FLOAT:        return POPT_("FLOAT");
 113     case POPT_ARG_DOUBLE:       return POPT_("DOUBLE");
 114     default:                    return POPT_("ARG");
 115     }
 116 }
 117 
 118 /**
 119  * Display default value for an option.
 120  * @param lineLength
 121  * @param opt           option(s)
 122  * @param translation_domain    translation domain
 123  * @return
 124  */
 125 static /*@only@*/ /*@null@*/ char *
 126 singleOptionDefaultValue(int lineLength,
     /* [<][>][^][v][top][bottom][index][help] */
 127                 const struct poptOption * opt,
 128                 /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */
 129                 /*@null@*/ const char * translation_domain)
 130                 /*@=paramuse@*/
 131         /*@*/
 132 {
 133     const char * defstr = D_(translation_domain, "default");
 134     char * le = (char *)malloc(4*lineLength + 1);
 135     char * l = le;
 136 
 137     if (le == NULL) return NULL;        /* XXX can't happen */
 138 /*@-boundswrite@*/
 139     *le = '\0';
 140     *le++ = '(';
 141     strcpy(le, defstr); le += strlen(le);
 142     *le++ = ':';
 143     *le++ = ' ';
 144     if (opt->arg)       /* XXX programmer error */
 145     switch (opt->argInfo & POPT_ARG_MASK) {
 146     case POPT_ARG_VAL:
 147     case POPT_ARG_INT:
 148     {   long aLong = *((int *)opt->arg);
 149         le += sprintf(le, "%ld", aLong);
 150     }   break;
 151     case POPT_ARG_LONG:
 152     {   long aLong = *((long *)opt->arg);
 153         le += sprintf(le, "%ld", aLong);
 154     }   break;
 155     case POPT_ARG_FLOAT:
 156     {   double aDouble = *((float *)opt->arg);
 157         le += sprintf(le, "%g", aDouble);
 158     }   break;
 159     case POPT_ARG_DOUBLE:
 160     {   double aDouble = *((double *)opt->arg);
 161         le += sprintf(le, "%g", aDouble);
 162     }   break;
 163     case POPT_ARG_STRING:
 164     {   const char * s = *(const char **)opt->arg;
 165         if (s == NULL) {
 166             strcpy(le, "null"); le += strlen(le);
 167         } else {
 168             size_t slen = 4*lineLength - (le - l) - sizeof("\"...\")");
 169             *le++ = '"';
 170             strncpy(le, s, slen); le[slen] = '\0'; le += strlen(le);
 171             if (slen < strlen(s)) {
 172                 strcpy(le, "...");      le += strlen(le);
 173             }
 174             *le++ = '"';
 175         }
 176     }   break;
 177     case POPT_ARG_NONE:
 178     default:
 179         l = (char *)_free(l);
 180         return NULL;
 181         /*@notreached@*/ break;
 182     }
 183     *le++ = ')';
 184     *le = '\0';
 185 /*@=boundswrite@*/
 186 
 187     return l;
 188 }
 189 
 190 /**
 191  * Display help text for an option.
 192  * @param fp            output file handle
 193  * @param maxLeftCol
 194  * @param opt           option(s)
 195  * @param translation_domain    translation domain
 196  */
 197 static void singleOptionHelp(FILE * fp, int maxLeftCol,
     /* [<][>][^][v][top][bottom][index][help] */
 198                 const struct poptOption * opt,
 199                 /*@null@*/ const char * translation_domain)
 200         /*@globals fileSystem @*/
 201         /*@modifies *fp, fileSystem @*/
 202 {
 203     int indentLength = maxLeftCol + 5;
 204     int lineLength = 79 - indentLength;
 205     const char * help = D_(translation_domain, opt->descrip);
 206     const char * argDescrip = getArgDescrip(opt, translation_domain);
 207     int helpLength;
 208     char * defs = NULL;
 209     char * left;
 210     int nb = maxLeftCol + 1;
 211 
 212     /* Make sure there's more than enough room in target buffer. */
 213     if (opt->longName)  nb += strlen(opt->longName);
 214     if (argDescrip)     nb += strlen(argDescrip);
 215 
 216 /*@-boundswrite@*/
 217     left = (char *)malloc(nb);
 218     if (left == NULL) return;   /* XXX can't happen */
 219     left[0] = '\0';
 220     left[maxLeftCol] = '\0';
 221 
 222     if (opt->longName && opt->shortName)
 223         sprintf(left, "-%c, %s%s", opt->shortName,
 224                 ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
 225                 opt->longName);
 226     else if (opt->shortName != '\0')
 227         sprintf(left, "-%c", opt->shortName);
 228     else if (opt->longName)
 229         sprintf(left, "%s%s",
 230                 ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
 231                 opt->longName);
 232     if (!*left) goto out;
 233 
 234     if (argDescrip) {
 235         char * le = left + strlen(left);
 236 
 237         if (opt->argInfo & POPT_ARGFLAG_OPTIONAL)
 238             *le++ = '[';
 239 
 240         /* Choose type of output */
 241         /*@-branchstate@*/
 242         if (opt->argInfo & POPT_ARGFLAG_SHOW_DEFAULT) {
 243             defs = singleOptionDefaultValue(lineLength, opt, translation_domain);
 244             if (defs) {
 245                 char * t = (char *)malloc((help ? strlen(help) : 0) +
 246                                 strlen(defs) + sizeof(" "));
 247                 if (t) {
 248                     char * te = t;
 249                     *te = '\0';
 250                     if (help) {
 251                         strcpy(te, help);       te += strlen(te);
 252                     }
 253                     *te++ = ' ';
 254                     strcpy(te, defs);
 255                     defs = (char *)_free(defs);
 256                 }
 257                 defs = t;
 258             }
 259         }
 260         /*@=branchstate@*/
 261 
 262         if (opt->argDescrip == NULL) {
 263             switch (opt->argInfo & POPT_ARG_MASK) {
 264             case POPT_ARG_NONE:
 265                 break;
 266             case POPT_ARG_VAL:
 267 #ifdef  NOTNOW  /* XXX pug ugly nerdy output */
 268             {   long aLong = opt->val;
 269                 int ops = (opt->argInfo & POPT_ARGFLAG_LOGICALOPS);
 270                 int negate = (opt->argInfo & POPT_ARGFLAG_NOT);
 271 
 272                 /* Don't bother displaying typical values */
 273                 if (!ops && (aLong == 0L || aLong == 1L || aLong == -1L))
 274                     break;
 275                 *le++ = '[';
 276                 switch (ops) {
 277                 case POPT_ARGFLAG_OR:
 278                     *le++ = '|';
 279                     /*@innerbreak@*/ break;
 280                 case POPT_ARGFLAG_AND:
 281                     *le++ = '&';
 282                     /*@innerbreak@*/ break;
 283                 case POPT_ARGFLAG_XOR:
 284                     *le++ = '^';
 285                     /*@innerbreak@*/ break;
 286                 default:
 287                     /*@innerbreak@*/ break;
 288                 }
 289                 *le++ = '=';
 290                 if (negate) *le++ = '~';
 291                 /*@-formatconst@*/
 292                 le += sprintf(le, (ops ? "0x%lx" : "%ld"), aLong);
 293                 /*@=formatconst@*/
 294                 *le++ = ']';
 295             }
 296 #endif
 297                 break;
 298             case POPT_ARG_INT:
 299             case POPT_ARG_LONG:
 300             case POPT_ARG_FLOAT:
 301             case POPT_ARG_DOUBLE:
 302             case POPT_ARG_STRING:
 303                 *le++ = '=';
 304                 strcpy(le, argDescrip);         le += strlen(le);
 305                 break;
 306             default:
 307                 break;
 308             }
 309         } else {
 310             *le++ = '=';
 311             strcpy(le, argDescrip);             le += strlen(le);
 312         }
 313         if (opt->argInfo & POPT_ARGFLAG_OPTIONAL)
 314             *le++ = ']';
 315         *le = '\0';
 316     }
 317 /*@=boundswrite@*/
 318 
 319     if (help)
 320         fprintf(fp,"  %-*s   ", maxLeftCol, left);
 321     else {
 322         fprintf(fp,"  %s\n", left);
 323         goto out;
 324     }
 325 
 326     left = (char *)_free(left);
 327     if (defs) {
 328         help = defs; defs = NULL;
 329     }
 330 
 331     helpLength = strlen(help);
 332 /*@-boundsread@*/
 333     while (helpLength > lineLength) {
 334         const char * ch;
 335         char format[16];
 336 
 337         ch = help + lineLength - 1;
 338         while (ch > help && !isspace(*ch)) ch--;
 339         if (ch == help) break;          /* give up */
 340         while (ch > (help + 1) && isspace(*ch)) ch--;
 341         ch++;
 342 
 343         sprintf(format, "%%.%ds\n%%%ds", (int) (ch - help), indentLength);
 344         /*@-formatconst@*/
 345         fprintf(fp, format, help, " ");
 346         /*@=formatconst@*/
 347         help = ch;
 348         while (isspace(*help) && *help) help++;
 349         helpLength = strlen(help);
 350     }
 351 /*@=boundsread@*/
 352 
 353     if (helpLength) fprintf(fp, "%s\n", help);
 354 
 355 out:
 356     /*@-dependenttrans@*/
 357     defs = (char *)_free(defs);
 358     /*@=dependenttrans@*/
 359     left = (char *)_free(left);
 360 }
 361 
 362 /**
 363  * @param opt           option(s)
 364  * @param translation_domain    translation domain
 365  */
 366 static int maxArgWidth(const struct poptOption * opt,
     /* [<][>][^][v][top][bottom][index][help] */
 367                        /*@null@*/ const char * translation_domain)
 368         /*@*/
 369 {
 370     int max = 0;
 371     int len = 0;
 372     const char * s;
 373     
 374     if (opt != NULL)
 375     while (opt->longName || opt->shortName || opt->arg) {
 376         if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
 377             if (opt->arg)       /* XXX program error */
 378             len = maxArgWidth((const struct poptOption *)opt->arg, translation_domain);
 379             if (len > max) max = len;
 380         } else if (!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
 381             len = sizeof("  ")-1;
 382             if (opt->shortName != '\0') len += sizeof("-X")-1;
 383             if (opt->shortName != '\0' && opt->longName) len += sizeof(", ")-1;
 384             if (opt->longName) {
 385                 len += ((opt->argInfo & POPT_ARGFLAG_ONEDASH)
 386                         ? sizeof("-")-1 : sizeof("--")-1);
 387                 len += strlen(opt->longName);
 388             }
 389 
 390             s = getArgDescrip(opt, translation_domain);
 391             if (s)
 392                 len += sizeof("=")-1 + strlen(s);
 393             if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) len += sizeof("[]")-1;
 394             if (len > max) max = len;
 395         }
 396 
 397         opt++;
 398     }
 399     
 400     return max;
 401 }
 402 
 403 /**
 404  * Display popt alias and exec help.
 405  * @param fp            output file handle
 406  * @param items         alias/exec array
 407  * @param nitems        no. of alias/exec entries
 408  * @param left
 409  * @param translation_domain    translation domain
 410  */
 411 static void itemHelp(FILE * fp,
     /* [<][>][^][v][top][bottom][index][help] */
 412                 /*@null@*/ poptItem items, int nitems, int left,
 413                 /*@null@*/ const char * translation_domain)
 414         /*@globals fileSystem @*/
 415         /*@modifies *fp, fileSystem @*/
 416 {
 417     poptItem item;
 418     int i;
 419 
 420     if (items != NULL)
 421     for (i = 0, item = items; i < nitems; i++, item++) {
 422         const struct poptOption * opt;
 423         opt = &item->option;
 424         if ((opt->longName || opt->shortName) &&
 425             !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
 426             singleOptionHelp(fp, left, opt, translation_domain);
 427     }
 428 }
 429 
 430 /**
 431  * Display help text for a table of options.
 432  * @param con           context
 433  * @param fp            output file handle
 434  * @param table         option(s)
 435  * @param left
 436  * @param translation_domain    translation domain
 437  */
 438 static void singleTableHelp(poptContext con, FILE * fp,
     /* [<][>][^][v][top][bottom][index][help] */
 439                 /*@null@*/ const struct poptOption * table, int left,
 440                 /*@null@*/ const char * translation_domain)
 441         /*@globals fileSystem @*/
 442         /*@modifies *fp, fileSystem @*/
 443 {
 444     const struct poptOption * opt;
 445     const char *sub_transdom;
 446 
 447     if (table == poptAliasOptions) {
 448         itemHelp(fp, con->aliases, con->numAliases, left, NULL);
 449         itemHelp(fp, con->execs, con->numExecs, left, NULL);
 450         return;
 451     }
 452 
 453     if (table != NULL)
 454     for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) {
 455         if ((opt->longName || opt->shortName) && 
 456             !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
 457             singleOptionHelp(fp, left, opt, translation_domain);
 458     }
 459 
 460     if (table != NULL)
 461     for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) {
 462         if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_INCLUDE_TABLE)
 463             continue;
 464         sub_transdom = getTableTranslationDomain(
 465             (const struct poptOption *)opt->arg);
 466         if (sub_transdom == NULL)
 467             sub_transdom = translation_domain;
 468             
 469         if (opt->descrip)
 470             fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip));
 471 
 472         singleTableHelp(con, fp, (const struct poptOption *)opt->arg, left, sub_transdom);
 473     }
 474 }
 475 
 476 /**
 477  * @param con           context
 478  * @param fp            output file handle
 479  */
 480 static int showHelpIntro(poptContext con, FILE * fp)
     /* [<][>][^][v][top][bottom][index][help] */
 481         /*@globals fileSystem @*/
 482         /*@modifies *fp, fileSystem @*/
 483 {
 484     int len = 6;
 485     const char * fn;
 486 
 487     fprintf(fp, POPT_("Usage:"));
 488     if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) {
 489 /*@-boundsread@*/
 490         /*@-nullderef@*/        /* LCL: wazzup? */
 491         fn = con->optionStack->argv[0];
 492         /*@=nullderef@*/
 493 /*@=boundsread@*/
 494         if (fn == NULL) return len;
 495         if (strchr(fn, '/')) fn = strrchr(fn, '/') + 1;
 496         fprintf(fp, " %s", fn);
 497         len += strlen(fn) + 1;
 498     }
 499 
 500     return len;
 501 }
 502 
 503 void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ int flags)
     /* [<][>][^][v][top][bottom][index][help] */
 504 {
 505     int leftColWidth;
 506 
 507     (void) showHelpIntro(con, fp);
 508     if (con->otherHelp)
 509         fprintf(fp, " %s\n", con->otherHelp);
 510     else
 511         fprintf(fp, " %s\n", POPT_("[OPTION...]"));
 512 
 513     leftColWidth = maxArgWidth(con->options, NULL);
 514     singleTableHelp(con, fp, con->options, leftColWidth, NULL);
 515 }
 516 
 517 /**
 518  * @param fp            output file handle
 519  * @param cursor
 520  * @param opt           option(s)
 521  * @param translation_domain    translation domain
 522  */
 523 static int singleOptionUsage(FILE * fp, int cursor,
     /* [<][>][^][v][top][bottom][index][help] */
 524                 const struct poptOption * opt,
 525                 /*@null@*/ const char *translation_domain)
 526         /*@globals fileSystem @*/
 527         /*@modifies *fp, fileSystem @*/
 528 {
 529     int len = 4;
 530     char shortStr[2] = { '\0', '\0' };
 531     const char * item = shortStr;
 532     const char * argDescrip = getArgDescrip(opt, translation_domain);
 533 
 534     if (opt->shortName != '\0' && opt->longName != NULL) {
 535         len += 2;
 536         if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++;
 537         len += strlen(opt->longName);
 538     } else if (opt->shortName != '\0') {
 539         len++;
 540         shortStr[0] = opt->shortName;
 541         shortStr[1] = '\0';
 542     } else if (opt->longName) {
 543         len += strlen(opt->longName);
 544         if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++;
 545         item = opt->longName;
 546     }
 547 
 548     if (len == 4) return cursor;
 549 
 550     if (argDescrip) 
 551         len += strlen(argDescrip) + 1;
 552 
 553     if ((cursor + len) > 79) {
 554         fprintf(fp, "\n       ");
 555         cursor = 7;
 556     } 
 557 
 558     if (opt->longName && opt->shortName) {
 559         fprintf(fp, " [-%c|-%s%s%s%s]",
 560             opt->shortName, ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "" : "-"),
 561             opt->longName,
 562             (argDescrip ? " " : ""),
 563             (argDescrip ? argDescrip : ""));
 564     } else {
 565         fprintf(fp, " [-%s%s%s%s]",
 566             ((opt->shortName || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) ? "" : "-"),
 567             item,
 568             (argDescrip ? (opt->shortName != '\0' ? " " : "=") : ""),
 569             (argDescrip ? argDescrip : ""));
 570     }
 571 
 572     return cursor + len + 1;
 573 }
 574 
 575 /**
 576  * Display popt alias and exec usage.
 577  * @param fp            output file handle
 578  * @param cursor
 579  * @param item          alias/exec array
 580  * @param nitems        no. of ara/exec entries
 581  * @param translation_domain    translation domain
 582  */
 583 static int itemUsage(FILE * fp, int cursor, poptItem item, int nitems,
     /* [<][>][^][v][top][bottom][index][help] */
 584                 /*@null@*/ const char * translation_domain)
 585         /*@globals fileSystem @*/
 586         /*@modifies *fp, fileSystem @*/
 587 {
 588     int i;
 589 
 590     /*@-branchstate@*/          /* FIX: W2DO? */
 591     if (item != NULL)
 592     for (i = 0; i < nitems; i++, item++) {
 593         const struct poptOption * opt;
 594         opt = &item->option;
 595         if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) {
 596             translation_domain = (const char *)opt->arg;
 597         } else if ((opt->longName || opt->shortName) &&
 598                  !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
 599             cursor = singleOptionUsage(fp, cursor, opt, translation_domain);
 600         }
 601     }
 602     /*@=branchstate@*/
 603 
 604     return cursor;
 605 }
 606 
 607 /**
 608  * Keep track of option tables already processed.
 609  */
 610 typedef struct poptDone_s {
 611     int nopts;
 612     int maxopts;
 613     const void ** opts;
 614 } * poptDone;
 615 
 616 /**
 617  * Display usage text for a table of options.
 618  * @param con           context
 619  * @param fp            output file handle
 620  * @param cursor
 621  * @param opt           option(s)
 622  * @param translation_domain    translation domain
 623  * @param done          tables already processed
 624  * @return
 625  */
 626 static int singleTableUsage(poptContext con, FILE * fp, int cursor,
     /* [<][>][^][v][top][bottom][index][help] */
 627                 /*@null@*/ const struct poptOption * opt,
 628                 /*@null@*/ const char * translation_domain,
 629                 /*@null@*/ poptDone done)
 630         /*@globals fileSystem @*/
 631         /*@modifies *fp, done, fileSystem @*/
 632 {
 633     /*@-branchstate@*/          /* FIX: W2DO? */
 634     if (opt != NULL)
 635     for (; (opt->longName || opt->shortName || opt->arg) ; opt++) {
 636         if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) {
 637             translation_domain = (const char *)opt->arg;
 638         } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
 639             if (done) {
 640                 int i = 0;
 641                 for (i = 0; i < done->nopts; i++) {
 642 /*@-boundsread@*/
 643                     const void * that = done->opts[i];
 644 /*@=boundsread@*/
 645                     if (that == NULL || that != opt->arg)
 646                         /*@innercontinue@*/ continue;
 647                     /*@innerbreak@*/ break;
 648                 }
 649                 /* Skip if this table has already been processed. */
 650                 if (opt->arg == NULL || i < done->nopts)
 651                     continue;
 652 /*@-boundswrite@*/
 653                 if (done->nopts < done->maxopts)
 654                     done->opts[done->nopts++] = (const void *) opt->arg;
 655 /*@=boundswrite@*/
 656             }
 657             cursor = singleTableUsage(con, fp, cursor, (const struct poptOption *)opt->arg,
 658                         translation_domain, done);
 659         } else if ((opt->longName || opt->shortName) &&
 660                  !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
 661             cursor = singleOptionUsage(fp, cursor, opt, translation_domain);
 662         }
 663     }
 664     /*@=branchstate@*/
 665 
 666     return cursor;
 667 }
 668 
 669 /**
 670  * Return concatenated short options for display.
 671  * @todo Sub-tables should be recursed.
 672  * @param opt           option(s)
 673  * @param fp            output file handle
 674  * @retval str          concatenation of short options
 675  * @return              length of display string
 676  */
 677 static int showShortOptions(const struct poptOption * opt, FILE * fp,
     /* [<][>][^][v][top][bottom][index][help] */
 678                 /*@null@*/ char * str)
 679         /*@globals fileSystem @*/
 680         /*@modifies *str, *fp, fileSystem @*/
 681         /*@requires maxRead(str) >= 0 @*/
 682 {
 683     /* bufsize larger then the ascii set, lazy alloca on top level call. */
 684     char * s = (str != NULL ? str : (char *)memset(alloca(300), 0, 300));
 685     int len = 0;
 686 
 687 /*@-boundswrite@*/
 688     if (opt != NULL)
 689     for (; (opt->longName || opt->shortName || opt->arg); opt++) {
 690         if (opt->shortName && !(opt->argInfo & POPT_ARG_MASK))
 691             s[strlen(s)] = opt->shortName;
 692         else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE)
 693             if (opt->arg)       /* XXX program error */
 694                 len = showShortOptions(
 695                     (const struct poptOption *)opt->arg, fp, s);
 696     } 
 697 /*@=boundswrite@*/
 698 
 699     /* On return to top level, print the short options, return print length. */
 700     if (s == str && *s != '\0') {
 701         fprintf(fp, " [-%s]", s);
 702         len = strlen(s) + sizeof(" [-]")-1;
 703     }
 704     return len;
 705 }
 706 
 707 void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ int flags)
     /* [<][>][^][v][top][bottom][index][help] */
 708 {
 709     poptDone done = (poptDone)memset(alloca(sizeof(*done)), 0, sizeof(*done));
 710     int cursor;
 711 
 712     done->nopts = 0;
 713     done->maxopts = 64;
 714     cursor = done->maxopts * sizeof(*done->opts);
 715 /*@-boundswrite@*/
 716     done->opts = (const void **)memset(alloca(cursor), 0, cursor);
 717     done->opts[done->nopts++] = (const void *) con->options;
 718 /*@=boundswrite@*/
 719 
 720     cursor = showHelpIntro(con, fp);
 721     cursor += showShortOptions(con->options, fp, NULL);
 722     cursor = singleTableUsage(con, fp, cursor, con->options, NULL, done);
 723     cursor = itemUsage(fp, cursor, con->aliases, con->numAliases, NULL);
 724     cursor = itemUsage(fp, cursor, con->execs, con->numExecs, NULL);
 725 
 726     if (con->otherHelp) {
 727         cursor += strlen(con->otherHelp) + 1;
 728         if (cursor > 79) fprintf(fp, "\n       ");
 729         fprintf(fp, " %s", con->otherHelp);
 730     }
 731 
 732     fprintf(fp, "\n");
 733 }
 734 
 735 void poptSetOtherOptionHelp(poptContext con, const char * text)
     /* [<][>][^][v][top][bottom][index][help] */
 736 {
 737     con->otherHelp = (const char *)_free(con->otherHelp);
 738     con->otherHelp = xstrdup(text);
 739 }
 740 /*@=type@*/

/* [<][>][^][v][top][bottom][index][help] */