(linenum→info "unix/slp.c:2238")

glibc/2.7/argp/argp-help.c

    1: /* Hierarchial argument parsing help output
    2:    Copyright (C) 1995-2003, 2004, 2005, 2006, 2007
    3:    Free Software Foundation, Inc.
    4:    This file is part of the GNU C Library.
    5:    Written by Miles Bader <miles@gnu.ai.mit.edu>.
    6: 
    7:    The GNU C Library is free software; you can redistribute it and/or
    8:    modify it under the terms of the GNU Lesser General Public
    9:    License as published by the Free Software Foundation; either
   10:    version 2.1 of the License, or (at your option) any later version.
   11: 
   12:    The GNU C Library is distributed in the hope that it will be useful,
   13:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   14:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   15:    Lesser General Public License for more details.
   16: 
   17:    You should have received a copy of the GNU Lesser General Public
   18:    License along with the GNU C Library; if not, write to the Free
   19:    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   20:    02111-1307 USA.  */
   21: 
   22: #ifndef _GNU_SOURCE
   23: # define _GNU_SOURCE    1
   24: #endif
   25: 
   26: #ifdef HAVE_CONFIG_H
   27: #include <config.h>
   28: #endif
   29: 
   30: /* AIX requires this to be the first thing in the file.  */
   31: #ifndef __GNUC__
   32: # if HAVE_ALLOCA_H || defined _LIBC
   33: #  include <alloca.h>
   34: # else
   35: #  ifdef _AIX
   36: #pragma alloca
   37: #  else
   38: #   ifndef alloca /* predefined by HP cc +Olibcalls */
   39: char *alloca ();
   40: #   endif
   41: #  endif
   42: # endif
   43: #endif
   44: 
   45: #include <stddef.h>
   46: #include <stdlib.h>
   47: #include <string.h>
   48: #include <assert.h>
   49: #include <stdarg.h>
   50: #include <ctype.h>
   51: #include <limits.h>
   52: #ifdef _LIBC
   53: # include <../libio/libioP.h>
   54: # include <wchar.h>
   55: #endif
   56: 
   57: #ifndef _
   58: /* This is for other GNU distributions with internationalized messages.  */
   59: # if defined HAVE_LIBINTL_H || defined _LIBC
   60: #  include <libintl.h>
   61: #  ifdef _LIBC
   62: #   undef dgettext
   63: #   define dgettext(domain, msgid) \
   64:   INTUSE(__dcgettext) (domain, msgid, LC_MESSAGES)
   65: #  endif
   66: # else
   67: #  define dgettext(domain, msgid) (msgid)
   68: # endif
   69: #endif
   70: 
   71: #ifndef _LIBC
   72: # if HAVE_STRERROR_R
   73: #  if !HAVE_DECL_STRERROR_R
   74: char *strerror_r (int errnum, char *buf, size_t buflen);
   75: #  endif
   76: # else
   77: #  if !HAVE_DECL_STRERROR
   78: char *strerror (int errnum);
   79: #  endif
   80: # endif
   81: #endif
   82: 
   83: #include "argp.h"
   84: #include "argp-fmtstream.h"
   85: #include "argp-namefrob.h"
   86: 
   87: #ifndef SIZE_MAX
   88: # define SIZE_MAX ((size_t) -1)
   89: #endif
   90: ^L
   91: /* User-selectable (using an environment variable) formatting parameters.
   92: 
   93:    These may be specified in an environment variable called `ARGP_HELP_FMT',
   94:    with a contents like:  VAR1=VAL1,VAR2=VAL2,BOOLVAR2,no-BOOLVAR2
   95:    Where VALn must be a positive integer.  The list of variables is in the
   96:    UPARAM_NAMES vector, below.  */
   97: 
   98: /* Default parameters.  */
   99: #define DUP_ARGS      0         /* True if option argument can be duplicated. */
  100: #define DUP_ARGS_NOTE 1         /* True to print a note about duplicate args. */
  101: #define SHORT_OPT_COL 2         /* column in which short options start */
  102: #define LONG_OPT_COL  6         /* column in which long options start */
  103: #define DOC_OPT_COL   2         /* column in which doc options start */
  104: #define OPT_DOC_COL  29         /* column in which option text starts */
  105: #define HEADER_COL    1         /* column in which group headers are printed */
  106: #define USAGE_INDENT 12         /* indentation of wrapped usage lines */
  107: #define RMARGIN      79         /* right margin used for wrapping */
  108: 
  109: /* User-selectable (using an environment variable) formatting parameters.
  110:    They must all be of type `int' for the parsing code to work.  */
  111: struct uparams
  112: {
  113:   /* If true, arguments for an option are shown with both short and long
  114:      options, even when a given option has both, e.g. `-x ARG, --longx=ARG'.
  115:      If false, then if an option has both, the argument is only shown with
  116:      the long one, e.g., `-x, --longx=ARG', and a message indicating that
  117:      this really means both is printed below the options.  */
  118:   int dup_args;
  119: 
  120:   /* This is true if when DUP_ARGS is false, and some duplicate arguments have
  121:      been suppressed, an explanatory message should be printed.  */
  122:   int dup_args_note;
  123: 
  124:   /* Various output columns.  */
  125:   int short_opt_col;
  126:   int long_opt_col;
  127:   int doc_opt_col;
  128:   int opt_doc_col;
  129:   int header_col;
  130:   int usage_indent;
  131:   int rmargin;
  132: };
  133: 
  134: /* This is a global variable, as user options are only ever read once.  */
  135: static struct uparams uparams = {
  136:   DUP_ARGS, DUP_ARGS_NOTE,
  137:   SHORT_OPT_COL, LONG_OPT_COL, DOC_OPT_COL, OPT_DOC_COL, HEADER_COL,
  138:   USAGE_INDENT, RMARGIN
  139: };
  140: 
  141: /* A particular uparam, and what the user name is.  */
  142: struct uparam_name
  143: {
  144:   const char name[14];          /* User name.  */
  145:   bool is_bool;                 /* Whether it's `boolean'.  */
  146:   uint8_t uparams_offs;         /* Location of the (int) field in UPARAMS.  */
  147: };
  148: 
  149: /* The name-field mappings we know about.  */
  150: static const struct uparam_name uparam_names[] =
  151: {
  152:   { "dup-args",       true, offsetof (struct uparams, dup_args) },
  153:   { "dup-args-note",  true, offsetof (struct uparams, dup_args_note) },
  154:   { "short-opt-col",  false, offsetof (struct uparams, short_opt_col) },
  155:   { "long-opt-col",   false, offsetof (struct uparams, long_opt_col) },
  156:   { "doc-opt-col",    false, offsetof (struct uparams, doc_opt_col) },
  157:   { "opt-doc-col",    false, offsetof (struct uparams, opt_doc_col) },
  158:   { "header-col",     false, offsetof (struct uparams, header_col) },
  159:   { "usage-indent",   false, offsetof (struct uparams, usage_indent) },
  160:   { "rmargin",        false, offsetof (struct uparams, rmargin) }
  161: };
  162: #define nuparam_names (sizeof (uparam_names) / sizeof (uparam_names[0]))
  163: 
  164: /* Read user options from the environment, and fill in UPARAMS appropiately.  */
  165: static void
  166: fill_in_uparams (const struct argp_state *state)
  167: {
  168:   const char *var = getenv ("ARGP_HELP_FMT");
  169: 
  170: #define SKIPWS(p) do { while (isspace (*p)) p++; } while (0);
  171: 
  172:   if (var)
  173:     /* Parse var. */
  174:     while (*var)
  175:       {
  176:         SKIPWS (var);
  177: 
  178:         if (isalpha (*var))
  179:           {
  180:             size_t var_len;
  181:             const struct uparam_name *un;
  182:             int unspec = 0, val = 0;
  183:             const char *arg = var;
  184: 
  185:             while (isalnum (*arg) || *arg == '-' || *arg == '_')
  186:               arg++;
  187:             var_len = arg - var;
  188: 
  189:             SKIPWS (arg);
  190: 
  191:             if (*arg == '\0' || *arg == ',')
  192:               unspec = 1;
  193:             else if (*arg == '=')
  194:               {
  195:                 arg++;
  196:                 SKIPWS (arg);
  197:               }
  198: 
  199:             if (unspec)
  200:               {
  201:                 if (var[0] == 'n' && var[1] == 'o' && var[2] == '-')
  202:                   {
  203:                     val = 0;
  204:                     var += 3;
  205:                     var_len -= 3;
  206:                   }
  207:                 else
  208:                   val = 1;
  209:               }
  210:             else if (isdigit (*arg))
  211:               {
  212:                 val = atoi (arg);
  213:                 while (isdigit (*arg))
  214:                   arg++;
  215:                 SKIPWS (arg);
  216:               }
  217: 
  218:             un = uparam_names;
  219:             size_t u;
  220:             for (u = 0; u < nuparam_names; ++un, ++u)
  221:               if (strlen (un->name) == var_len
  222:                   && strncmp (var, un->name, var_len) == 0)
  223:                 {
  224:                   if (unspec && !un->is_bool)
  225:                     __argp_failure (state, 0, 0,
  226:                                     dgettext (state == NULL ? NULL
  227:                                               : state->root_argp->argp_domain,
  228:                                               "\
  229: %.*s: ARGP_HELP_FMT parameter requires a value"),
  230:                                     (int) var_len, var);
  231:                   else
  232:                     *(int *)((char *)&uparams + un->uparams_offs) = val;
  233:                   break;
  234:                 }
  235:             if (u == nuparam_names)
  236:               __argp_failure (state, 0, 0,
  237:                               dgettext (state == NULL ? NULL
  238:                                         : state->root_argp->argp_domain, "\
  239: %.*s: Unknown ARGP_HELP_FMT parameter"),
  240:                               (int) var_len, var);
  241: 
  242:             var = arg;
  243:             if (*var == ',')
  244:               var++;
  245:           }
  246:         else if (*var)
  247:           {
  248:             __argp_failure (state, 0, 0,
  249:                             dgettext (state == NULL ? NULL
  250:                                       : state->root_argp->argp_domain,
  251:                                       "Garbage in ARGP_HELP_FMT: %s"), var);
  252:             break;
  253:           }
  254:       }
  255: }
  256: ^L
  257: /* Returns true if OPT hasn't been marked invisible.  Visibility only affects
  258:    whether OPT is displayed or used in sorting, not option shadowing.  */
  259: #define ovisible(opt) (! ((opt)->flags & OPTION_HIDDEN))
  260: 
  261: /* Returns true if OPT is an alias for an earlier option.  */
  262: #define oalias(opt) ((opt)->flags & OPTION_ALIAS)
  263: 
  264: /* Returns true if OPT is an documentation-only entry.  */
  265: #define odoc(opt) ((opt)->flags & OPTION_DOC)
  266: 
  267: /* Returns true if OPT is the end-of-list marker for a list of options.  */
  268: #define oend(opt) __option_is_end (opt)
  269: 
  270: /* Returns true if OPT has a short option.  */
  271: #define oshort(opt) __option_is_short (opt)
  272: ^L
  273: /*
  274:    The help format for a particular option is like:
  275: 
  276:      -xARG, -yARG, --long1=ARG, --long2=ARG        Documentation...
  277: 
  278:    Where ARG will be omitted if there's no argument, for this option, or
  279:    will be surrounded by "[" and "]" appropiately if the argument is
  280:    optional.  The documentation string is word-wrapped appropiately, and if
  281:    the list of options is long enough, it will be started on a separate line.
  282:    If there are no short options for a given option, the first long option is
  283:    indented slighly in a way that's supposed to make most long options appear
  284:    to be in a separate column.
  285: 
  286:    For example, the following output (from ps):
  287: 
  288:      -p PID, --pid=PID          List the process PID
  289:          --pgrp=PGRP            List processes in the process group PGRP
  290:      -P, -x, --no-parent        Include processes without parents
  291:      -Q, --all-fields           Don't elide unusable fields (normally if there's
  292:                                 some reason ps can't print a field for any
  293:                                 process, it's removed from the output entirely)
  294:      -r, --reverse, --gratuitously-long-reverse-option
  295:                                 Reverse the order of any sort
  296:          --session[=SID]        Add the processes from the session SID (which
  297:                                 defaults to the sid of the current process)
  298: 
  299:     Here are some more options:
  300:      -f ZOT, --foonly=ZOT       Glork a foonly
  301:      -z, --zaza                 Snit a zar
  302: 
  303:      -?, --help                 Give this help list
  304:          --usage                Give a short usage message
  305:      -V, --version              Print program version
  306: 
  307:    The struct argp_option array for the above could look like:
  308: 
  309:    {
  310:      {"pid",       'p',      "PID",  0, "List the process PID"},
  311:      {"pgrp",      OPT_PGRP, "PGRP", 0, "List processes in the process group PGRP"},
  312:      {"no-parent", 'P',       0,     0, "Include processes without parents"},
  313:      {0,           'x',       0,     OPTION_ALIAS},
  314:      {"all-fields",'Q',       0,     0, "Don't elide unusable fields (normally"
  315:                                         " if there's some reason ps can't"
  316:                                         " print a field for any process, it's"
  317:                                         " removed from the output entirely)" },
  318:      {"reverse",   'r',       0,     0, "Reverse the order of any sort"},
  319:      {"gratuitously-long-reverse-option", 0, 0, OPTION_ALIAS},
  320:      {"session",   OPT_SESS,  "SID", OPTION_ARG_OPTIONAL,
  321:                                         "Add the processes from the session"
  322:                                         " SID (which defaults to the sid of"
  323:                                         " the current process)" },
  324: 
  325:      {0,0,0,0, "Here are some more options:"},
  326:      {"foonly", 'f', "ZOT", 0, "Glork a foonly"},
  327:      {"zaza", 'z', 0, 0, "Snit a zar"},
  328: 
  329:      {0}
  330:    }
  331: 
  332:    Note that the last three options are automatically supplied by argp_parse,
  333:    unless you tell it not to with ARGP_NO_HELP.
  334: 
  335: */
  336: ^L
  337: /* Returns true if CH occurs between BEG and END.  */
  338: static int
  339: find_char (char ch, char *beg, char *end)
  340: {
  341:   while (beg < end)
  342:     if (*beg == ch)
  343:       return 1;
  344:     else
  345:       beg++;
  346:   return 0;
  347: }
  348: ^L
  349: struct hol_cluster;             /* fwd decl */
  350: 
  351: struct hol_entry
  352: {
  353:   /* First option.  */
  354:   const struct argp_option *opt;
  355:   /* Number of options (including aliases).  */
  356:   unsigned num;
  357: 
  358:   /* A pointers into the HOL's short_options field, to the first short option
  359:      letter for this entry.  The order of the characters following this point
  360:      corresponds to the order of options pointed to by OPT, and there are at
  361:      most NUM.  A short option recorded in a option following OPT is only
  362:      valid if it occurs in the right place in SHORT_OPTIONS (otherwise it's
  363:      probably been shadowed by some other entry).  */
  364:   char *short_options;
  365: 
  366:   /* Entries are sorted by their group first, in the order:
  367:        1, 2, ..., n, 0, -m, ..., -2, -1
  368:      and then alphabetically within each group.  The default is 0.  */
  369:   int group;
  370: 
  371:   /* The cluster of options this entry belongs to, or 0 if none.  */
  372:   struct hol_cluster *cluster;
  373: 
  374:   /* The argp from which this option came.  */
  375:   const struct argp *argp;
  376: };
  377: 
  378: /* A cluster of entries to reflect the argp tree structure.  */
  379: struct hol_cluster
  380: {
  381:   /* A descriptive header printed before options in this cluster.  */
  382:   const char *header;
  383: 
  384:   /* Used to order clusters within the same group with the same parent,
  385:      according to the order in which they occurred in the parent argp's child
  386:      list.  */
  387:   int index;
  388: 
  389:   /* How to sort this cluster with respect to options and other clusters at the
  390:      same depth (clusters always follow options in the same group).  */
  391:   int group;
  392: 
  393:   /* The cluster to which this cluster belongs, or 0 if it's at the base
  394:      level.  */
  395:   struct hol_cluster *parent;
  396: 
  397:   /* The argp from which this cluster is (eventually) derived.  */
  398:   const struct argp *argp;
  399: 
  400:   /* The distance this cluster is from the root.  */
  401:   int depth;
  402: 
  403:   /* Clusters in a given hol are kept in a linked list, to make freeing them
  404:      possible.  */
  405:   struct hol_cluster *next;
  406: };
  407: 
  408: /* A list of options for help.  */
  409: struct hol
  410: {
  411:   /* An array of hol_entry's.  */
  412:   struct hol_entry *entries;
  413:   /* The number of entries in this hol.  If this field is zero, the others
  414:      are undefined.  */
  415:   unsigned num_entries;
  416: 
  417:   /* A string containing all short options in this HOL.  Each entry contains
  418:      pointers into this string, so the order can't be messed with blindly.  */
  419:   char *short_options;
  420: 
  421:   /* Clusters of entries in this hol.  */
  422:   struct hol_cluster *clusters;
  423: };
  424: ^L
  425: /* Create a struct hol from the options in ARGP.  CLUSTER is the
  426:    hol_cluster in which these entries occur, or 0, if at the root.  */
  427: static struct hol *
  428: make_hol (const struct argp *argp, struct hol_cluster *cluster)
  429: {
  430:   char *so;
  431:   const struct argp_option *o;
  432:   const struct argp_option *opts = argp->options;
  433:   struct hol_entry *entry;
  434:   unsigned num_short_options = 0;
  435:   struct hol *hol = malloc (sizeof (struct hol));
  436: 
  437:   assert (hol);
  438: 
  439:   hol->num_entries = 0;
  440:   hol->clusters = 0;
  441: 
  442:   if (opts)
  443:     {
  444:       int cur_group = 0;
  445: 
  446:       /* The first option must not be an alias.  */
  447:       assert (! oalias (opts));
  448: 
  449:       /* Calculate the space needed.  */
  450:       for (o = opts; ! oend (o); o++)
  451:         {
  452:           if (! oalias (o))
  453:             hol->num_entries++;
  454:           if (oshort (o))
  455:             num_short_options++;       /* This is an upper bound.  */
  456:         }
  457: 
  458:       hol->entries = malloc (sizeof (struct hol_entry) * hol->num_entries);
  459:       hol->short_options = malloc (num_short_options + 1);
  460: 
  461:       assert (hol->entries && hol->short_options);
  462: #if SIZE_MAX <= UINT_MAX
  463:       assert (hol->num_entries <= SIZE_MAX / sizeof (struct hol_entry));
  464: #endif
  465: 
  466:       /* Fill in the entries.  */
  467:       so = hol->short_options;
  468:       for (o = opts, entry = hol->entries; ! oend (o); entry++)
  469:         {
  470:           entry->opt = o;
  471:           entry->num = 0;
  472:           entry->short_options = so;
  473:           entry->group = cur_group =
  474:             o->group
  475:             ? o->group
  476:             : ((!o->name && !o->key)
  477:                ? cur_group + 1
  478:                : cur_group);
  479:           entry->cluster = cluster;
  480:           entry->argp = argp;
  481: 
  482:           do
  483:             {
  484:               entry->num++;
  485:               if (oshort (o) && ! find_char (o->key, hol->short_options, so))
  486:                 /* O has a valid short option which hasn't already been used.*/
  487:                 *so++ = o->key;
  488:               o++;
  489:             }
  490:           while (! oend (o) && oalias (o));
  491:         }
  492:       *so = '\0';               /* null terminated so we can find the length */
  493:     }
  494: 
  495:   return hol;
  496: }
  497: ^L
  498: /* Add a new cluster to HOL, with the given GROUP and HEADER (taken from the
  499:    associated argp child list entry), INDEX, and PARENT, and return a pointer
  500:    to it.  ARGP is the argp that this cluster results from.  */
  501: static struct hol_cluster *
  502: hol_add_cluster (struct hol *hol, int group, const char *header, int index,
  503:                  struct hol_cluster *parent, const struct argp *argp)
  504: {
  505:   struct hol_cluster *cl = malloc (sizeof (struct hol_cluster));
  506:   if (cl)
  507:     {
  508:       cl->group = group;
  509:       cl->header = header;
  510: 
  511:       cl->index = index;
  512:       cl->parent = parent;
  513:       cl->argp = argp;
  514:       cl->depth = parent ? parent->depth + 1 : 0;
  515: 
  516:       cl->next = hol->clusters;
  517:       hol->clusters = cl;
  518:     }
  519:   return cl;
  520: }
  521: ^L
  522: /* Free HOL and any resources it uses.  */
  523: static void
  524: hol_free (struct hol *hol)
  525: {
  526:   struct hol_cluster *cl = hol->clusters;
  527: 
  528:   while (cl)
  529:     {
  530:       struct hol_cluster *next = cl->next;
  531:       free (cl);
  532:       cl = next;
  533:     }
  534: 
  535:   if (hol->num_entries > 0)
  536:     {
  537:       free (hol->entries);
  538:       free (hol->short_options);
  539:     }
  540: 
  541:   free (hol);
  542: }
  543: ^L
  544: static int
  545: hol_entry_short_iterate (const struct hol_entry *entry,
  546:                          int (*func)(const struct argp_option *opt,
  547:                                      const struct argp_option *real,
  548:                                      const char *domain, void *cookie),
  549:                          const char *domain, void *cookie)
  550: {
  551:   unsigned nopts;
  552:   int val = 0;
  553:   const struct argp_option *opt, *real = entry->opt;
  554:   char *so = entry->short_options;
  555: 
  556:   for (opt = real, nopts = entry->num; nopts > 0 && !val; opt++, nopts--)
  557:     if (oshort (opt) && *so == opt->key)
  558:       {
  559:         if (!oalias (opt))
  560:           real = opt;
  561:         if (ovisible (opt))
  562:           val = (*func)(opt, real, domain, cookie);
  563:         so++;
  564:       }
  565: 
  566:   return val;
  567: }
  568: 
  569: static inline int
  570: __attribute__ ((always_inline))