1 /* Hierarchical argument parsing help output
2    Copyright (C) 1995-2020 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Written by Miles Bader <miles@gnu.ai.mit.edu>.
5 
6    This program is free software: you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
18 
19 #ifndef _GNU_SOURCE
20 # define _GNU_SOURCE    1
21 #endif
22 
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif
26 
27 #include <alloca.h>
28 #include <errno.h>
29 #include <stdbool.h>
30 #include <stddef.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <assert.h>
34 #include <stdarg.h>
35 #include <ctype.h>
36 #include <limits.h>
37 #ifdef _LIBC
38 # include <../libio/libioP.h>
39 # include <wchar.h>
40 #endif
41 
42 #ifdef _LIBC
43 # include <libintl.h>
44 # undef dgettext
45 # define dgettext(domain, msgid) \
46    __dcgettext (domain, msgid, LC_MESSAGES)
47 #else
48 # include "gettext.h"
49 #endif
50 
51 #include "argp.h"
52 #include "argp-fmtstream.h"
53 #include "argp-namefrob.h"
54 
55 #ifndef SIZE_MAX
56 # define SIZE_MAX ((size_t) -1)
57 #endif
58 
59 /* User-selectable (using an environment variable) formatting parameters.
60 
61    These may be specified in an environment variable called 'ARGP_HELP_FMT',
62    with a contents like:  VAR1=VAL1,VAR2=VAL2,BOOLVAR2,no-BOOLVAR2
63    Where VALn must be a positive integer.  The list of variables is in the
64    UPARAM_NAMES vector, below.  */
65 
66 /* Default parameters.  */
67 #define DUP_ARGS      0         /* True if option argument can be duplicated. */
68 #define DUP_ARGS_NOTE 1         /* True to print a note about duplicate args. */
69 #define SHORT_OPT_COL 2         /* column in which short options start */
70 #define LONG_OPT_COL  6         /* column in which long options start */
71 #define DOC_OPT_COL   2         /* column in which doc options start */
72 #define OPT_DOC_COL  29         /* column in which option text starts */
73 #define HEADER_COL    1         /* column in which group headers are printed */
74 #define USAGE_INDENT 12         /* indentation of wrapped usage lines */
75 #define RMARGIN      79         /* right margin used for wrapping */
76 
77 /* User-selectable (using an environment variable) formatting parameters.
78    They must all be of type 'int' for the parsing code to work.  */
79 struct uparams
80 {
81   /* If true, arguments for an option are shown with both short and long
82      options, even when a given option has both, e.g. '-x ARG, --longx=ARG'.
83      If false, then if an option has both, the argument is only shown with
84      the long one, e.g., '-x, --longx=ARG', and a message indicating that
85      this really means both is printed below the options.  */
86   int dup_args;
87 
88   /* This is true if when DUP_ARGS is false, and some duplicate arguments have
89      been suppressed, an explanatory message should be printed.  */
90   int dup_args_note;
91 
92   /* Various output columns.  */
93   int short_opt_col;      /* column in which short options start */
94   int long_opt_col;       /* column in which long options start */
95   int doc_opt_col;        /* column in which doc options start */
96   int opt_doc_col;        /* column in which option text starts */
97   int header_col;         /* column in which group headers are printed */
98   int usage_indent;       /* indentation of wrapped usage lines */
99   int rmargin;            /* right margin used for wrapping */
100 
101   int valid;              /* True when the values in here are valid.  */
102 };
103 
104 /* This is a global variable, as user options are only ever read once.  */
105 static struct uparams uparams = {
106   DUP_ARGS, DUP_ARGS_NOTE,
107   SHORT_OPT_COL, LONG_OPT_COL, DOC_OPT_COL, OPT_DOC_COL, HEADER_COL,
108   USAGE_INDENT, RMARGIN
109 };
110 
111 /* A particular uparam, and what the user name is.  */
112 struct uparam_name
113 {
114   const char name[14];          /* User name.  */
115   bool is_bool;                 /* Whether it's 'boolean'.  */
116   unsigned char uparams_offs;   /* Location of the (int) field in UPARAMS.  */
117 };
118 
119 /* The name-field mappings we know about.  */
120 static const struct uparam_name uparam_names[] =
121 {
122   { "dup-args",       true, offsetof (struct uparams, dup_args) },
123   { "dup-args-note",  true, offsetof (struct uparams, dup_args_note) },
124   { "short-opt-col",  false, offsetof (struct uparams, short_opt_col) },
125   { "long-opt-col",   false, offsetof (struct uparams, long_opt_col) },
126   { "doc-opt-col",    false, offsetof (struct uparams, doc_opt_col) },
127   { "opt-doc-col",    false, offsetof (struct uparams, opt_doc_col) },
128   { "header-col",     false, offsetof (struct uparams, header_col) },
129   { "usage-indent",   false, offsetof (struct uparams, usage_indent) },
130   { "rmargin",        false, offsetof (struct uparams, rmargin) }
131 };
132 #define nuparam_names (sizeof (uparam_names) / sizeof (uparam_names[0]))
133 
134 static void
validate_uparams(const struct argp_state * state,struct uparams * upptr)135 validate_uparams (const struct argp_state *state, struct uparams *upptr)
136 {
137   const struct uparam_name *up;
138 
139   for (up = uparam_names; up < uparam_names + nuparam_names; up++)
140     {
141       if (up->is_bool
142           || up->uparams_offs == offsetof (struct uparams, rmargin))
143         continue;
144       if (*(int *)((char *)upptr + up->uparams_offs) >= upptr->rmargin)
145         {
146           __argp_failure (state, 0, 0,
147                           dgettext (state->root_argp->argp_domain,
148                                     "\
149 ARGP_HELP_FMT: %s value is less than or equal to %s"),
150                           "rmargin", up->name);
151           return;
152         }
153     }
154   uparams = *upptr;
155   uparams.valid = 1;
156 }
157 
158 /* Read user options from the environment, and fill in UPARAMS appropriately.  */
159 static void
fill_in_uparams(const struct argp_state * state)160 fill_in_uparams (const struct argp_state *state)
161 {
162   const char *var = getenv ("ARGP_HELP_FMT");
163   struct uparams new_params = uparams;
164 
165 #define SKIPWS(p) do { while (isspace ((unsigned char) *p)) p++; } while (0);
166 
167   if (var)
168     {
169       /* Parse var. */
170       while (*var)
171         {
172           SKIPWS (var);
173 
174           if (isalpha ((unsigned char) *var))
175             {
176               size_t var_len;
177               const struct uparam_name *un;
178               int unspec = 0, val = 0;
179               const char *arg = var;
180 
181               while (isalnum ((unsigned char) *arg) || *arg == '-' || *arg == '_')
182                 arg++;
183               var_len = arg - var;
184 
185               SKIPWS (arg);
186 
187               if (*arg == '\0' || *arg == ',')
188                 unspec = 1;
189               else if (*arg == '=')
190                 {
191                   arg++;
192                   SKIPWS (arg);
193                 }
194 
195               if (unspec)
196                 {
197                   if (var[0] == 'n' && var[1] == 'o' && var[2] == '-')
198                     {
199                       val = 0;
200                       var += 3;
201                       var_len -= 3;
202                     }
203                   else
204                     val = 1;
205                 }
206               else if (isdigit ((unsigned char) *arg))
207                 {
208                   val = atoi (arg);
209                   while (isdigit ((unsigned char) *arg))
210                     arg++;
211                   SKIPWS (arg);
212                 }
213 
214               for (un = uparam_names;
215                    un < uparam_names + nuparam_names;
216                    un++)
217                 if (strlen (un->name) == var_len
218                     && strncmp (var, un->name, var_len) == 0)
219                   {
220                     if (unspec && !un->is_bool)
221                       __argp_failure (state, 0, 0,
222                                       dgettext (state == NULL ? NULL
223                                                 : state->root_argp->argp_domain,
224                                                 "\
225 %.*s: ARGP_HELP_FMT parameter requires a value"),
226                                       (int) var_len, var);
227                     else
228                       *(int *)((char *)&new_params + un->uparams_offs) = val;
229                     break;
230                   }
231               if (un == uparam_names + nuparam_names)
232                 __argp_failure (state, 0, 0,
233                                 dgettext (state == NULL ? NULL
234                                           : state->root_argp->argp_domain, "\
235 %.*s: Unknown ARGP_HELP_FMT parameter"),
236                                 (int) var_len, var);
237 
238               var = arg;
239               if (*var == ',')
240                 var++;
241             }
242           else if (*var)
243             {
244               __argp_failure (state, 0, 0,
245                               dgettext (state == NULL ? NULL
246                                         : state->root_argp->argp_domain,
247                                         "Garbage in ARGP_HELP_FMT: %s"), var);
248               break;
249             }
250         }
251       validate_uparams (state, &new_params);
252     }
253 }
254 
255 /* Returns true if OPT hasn't been marked invisible.  Visibility only affects
256    whether OPT is displayed or used in sorting, not option shadowing.  */
257 #define ovisible(opt) (! ((opt)->flags & OPTION_HIDDEN))
258 
259 /* Returns true if OPT is an alias for an earlier option.  */
260 #define oalias(opt) ((opt)->flags & OPTION_ALIAS)
261 
262 /* Returns true if OPT is a documentation-only entry.  */
263 #define odoc(opt) ((opt)->flags & OPTION_DOC)
264 
265 /* Returns true if OPT should not be translated */
266 #define onotrans(opt) ((opt)->flags & OPTION_NO_TRANS)
267 
268 /* Returns true if OPT is the end-of-list marker for a list of options.  */
269 #define oend(opt) __option_is_end (opt)
270 
271 /* Returns true if OPT has a short option.  */
272 #define oshort(opt) __option_is_short (opt)
273 
274 /*
275    The help format for a particular option is like:
276 
277      -xARG, -yARG, --long1=ARG, --long2=ARG        Documentation...
278 
279    Where ARG will be omitted if there's no argument, for this option, or
280    will be surrounded by "[" and "]" appropriately if the argument is
281    optional.  The documentation string is word-wrapped appropriately, and if
282    the list of options is long enough, it will be started on a separate line.
283    If there are no short options for a given option, the first long option is
284    indented slightly in a way that's supposed to make most long options appear
285    to be in a separate column.
286 
287    For example, the following output (from ps):
288 
289      -p PID, --pid=PID          List the process PID
290          --pgrp=PGRP            List processes in the process group PGRP
291      -P, -x, --no-parent        Include processes without parents
292      -Q, --all-fields           Don't elide unusable fields (normally if there's
293                                 some reason ps can't print a field for any
294                                 process, it's removed from the output entirely)
295      -r, --reverse, --gratuitously-long-reverse-option
296                                 Reverse the order of any sort
297          --session[=SID]        Add the processes from the session SID (which
298                                 defaults to the sid of the current process)
299 
300     Here are some more options:
301      -f ZOT, --foonly=ZOT       Glork a foonly
302      -z, --zaza                 Snit a zar
303 
304      -?, --help                 Give this help list
305          --usage                Give a short usage message
306      -V, --version              Print program version
307 
308    The struct argp_option array for the above could look like:
309 
310    {
311      {"pid",       'p',      "PID",  0, "List the process PID"},
312      {"pgrp",      OPT_PGRP, "PGRP", 0, "List processes in the process group PGRP"},
313      {"no-parent", 'P',       0,     0, "Include processes without parents"},
314      {0,           'x',       0,     OPTION_ALIAS},
315      {"all-fields",'Q',       0,     0, "Don't elide unusable fields (normally"
316                                         " if there's some reason ps can't"
317                                         " print a field for any process, it's"
318                                         " removed from the output entirely)" },
319      {"reverse",   'r',       0,     0, "Reverse the order of any sort"},
320      {"gratuitously-long-reverse-option", 0, 0, OPTION_ALIAS},
321      {"session",   OPT_SESS,  "SID", OPTION_ARG_OPTIONAL,
322                                         "Add the processes from the session"
323                                         " SID (which defaults to the sid of"
324                                         " the current process)" },
325 
326      {0,0,0,0, "Here are some more options:"},
327      {"foonly", 'f', "ZOT", 0, "Glork a foonly"},
328      {"zaza", 'z', 0, 0, "Snit a zar"},
329 
330      {0}
331    }
332 
333    Note that the last three options are automatically supplied by argp_parse,
334    unless you tell it not to with ARGP_NO_HELP.
335 
336 */
337 
338 /* Returns true if CH occurs between BEG and END.  */
339 static int
find_char(char ch,char * beg,char * end)340 find_char (char ch, char *beg, char *end)
341 {
342   while (beg < end)
343     if (*beg == ch)
344       return 1;
345     else
346       beg++;
347   return 0;
348 }
349 
350 struct hol_cluster;             /* fwd decl */
351 
352 struct hol_entry
353 {
354   /* First option.  */
355   const struct argp_option *opt;
356   /* Number of options (including aliases).  */
357   unsigned num;
358 
359   /* A pointers into the HOL's short_options field, to the first short option
360      letter for this entry.  The order of the characters following this point
361      corresponds to the order of options pointed to by OPT, and there are at
362      most NUM.  A short option recorded in an option following OPT is only
363      valid if it occurs in the right place in SHORT_OPTIONS (otherwise it's
364      probably been shadowed by some other entry).  */
365   char *short_options;
366 
367   /* Entries are sorted by their group first, in the order:
368        1, 2, ..., n, 0, -m, ..., -2, -1
369      and then alphabetically within each group.  The default is 0.  */
370   int group;
371 
372   /* The cluster of options this entry belongs to, or 0 if none.  */
373   struct hol_cluster *cluster;
374 
375   /* The argp from which this option came.  */
376   const struct argp *argp;
377 
378   /* Position in the array */
379   unsigned ord;
380 };
381 
382 /* A cluster of entries to reflect the argp tree structure.  */
383 struct hol_cluster
384 {
385   /* A descriptive header printed before options in this cluster.  */
386   const char *header;
387 
388   /* Used to order clusters within the same group with the same parent,
389      according to the order in which they occurred in the parent argp's child
390      list.  */
391   int index;
392 
393   /* How to sort this cluster with respect to options and other clusters at the
394      same depth (clusters always follow options in the same group).  */
395   int group;
396 
397   /* The cluster to which this cluster belongs, or 0 if it's at the base
398      level.  */
399   struct hol_cluster *parent;
400 
401   /* The argp from which this cluster is (eventually) derived.  */
402   const struct argp *argp;
403 
404   /* The distance this cluster is from the root.  */
405   int depth;
406 
407   /* Clusters in a given hol are kept in a linked list, to make freeing them
408      possible.  */
409   struct hol_cluster *next;
410 };
411 
412 /* A list of options for help.  */
413 struct hol
414 {
415   /* An array of hol_entry's.  */
416   struct hol_entry *entries;
417   /* The number of entries in this hol.  If this field is zero, the others
418      are undefined.  */
419   unsigned num_entries;
420 
421   /* A string containing all short options in this HOL.  Each entry contains
422      pointers into this string, so the order can't be messed with blindly.  */
423   char *short_options;
424 
425   /* Clusters of entries in this hol.  */
426   struct hol_cluster *clusters;
427 };
428 
429 /* Create a struct hol from the options in ARGP.  CLUSTER is the
430    hol_cluster in which these entries occur, or 0, if at the root.  */
431 static struct hol *
make_hol(const struct argp * argp,struct hol_cluster * cluster)432 make_hol (const struct argp *argp, struct hol_cluster *cluster)
433 {
434   char *so;
435   const struct argp_option *o;
436   const struct argp_option *opts = argp->options;
437   struct hol_entry *entry;
438   unsigned num_short_options = 0;
439   struct hol *hol = malloc (sizeof (struct hol));
440 
441   assert (hol);
442 
443   hol->num_entries = 0;
444   hol->clusters = 0;
445 
446   if (opts)
447     {
448       int cur_group = 0;
449 
450       /* The first option must not be an alias.  */
451       assert (! oalias (opts));
452 
453       /* Calculate the space needed.  */
454       for (o = opts; ! oend (o); o++)
455         {
456           if (! oalias (o))
457             hol->num_entries++;
458           if (oshort (o))
459             num_short_options++;        /* This is an upper bound.  */
460         }
461 
462       hol->entries = malloc (sizeof (struct hol_entry) * hol->num_entries);
463       hol->short_options = malloc (num_short_options + 1);
464 
465       assert (hol->entries && hol->short_options);
466       if (SIZE_MAX <= UINT_MAX)
467         assert (hol->num_entries <= SIZE_MAX / sizeof (struct hol_entry));
468 
469       /* Fill in the entries.  */
470       so = hol->short_options;
471       for (o = opts, entry = hol->entries; ! oend (o); entry++)
472         {
473           entry->opt = o;
474           entry->num = 0;
475           entry->short_options = so;
476           entry->group = cur_group =
477             o->group
478             ? o->group
479             : ((!o->name && !o->key)
480                ? cur_group + 1
481                : cur_group);
482           entry->cluster = cluster;
483           entry->argp = argp;
484 
485           do
486             {
487               entry->num++;
488               if (oshort (o) && ! find_char (o->key, hol->short_options, so))
489                 /* O has a valid short option which hasn't already been used.*/
490                 *so++ = o->key;
491               o++;
492             }
493           while (! oend (o) && oalias (o));
494         }
495       *so = '\0';               /* null terminated so we can find the length */
496     }
497 
498   return hol;
499 }
500 
501 /* Add a new cluster to HOL, with the given GROUP and HEADER (taken from the
502    associated argp child list entry), INDEX, and PARENT, and return a pointer
503    to it.  ARGP is the argp that this cluster results from.  */
504 static struct hol_cluster *
hol_add_cluster(struct hol * hol,int group,const char * header,int index,struct hol_cluster * parent,const struct argp * argp)505 hol_add_cluster (struct hol *hol, int group, const char *header, int index,
506                  struct hol_cluster *parent, const struct argp *argp)
507 {
508   struct hol_cluster *cl = malloc (sizeof (struct hol_cluster));
509   if (cl)
510     {
511       cl->group = group;
512       cl->header = header;
513 
514       cl->index = index;
515       cl->parent = parent;
516       cl->argp = argp;
517       cl->depth = parent ? parent->depth + 1 : 0;
518 
519       cl->next = hol->clusters;
520       hol->clusters = cl;
521     }
522   return cl;
523 }
524 
525 /* Free HOL and any resources it uses.  */
526 static void
hol_free(struct hol * hol)527 hol_free (struct hol *hol)
528 {
529   struct hol_cluster *cl = hol->clusters;
530 
531   while (cl)
532     {
533       struct hol_cluster *next = cl->next;
534       free (cl);
535       cl = next;
536     }
537 
538   if (hol->num_entries > 0)
539     {
540       free (hol->entries);
541       free (hol->short_options);
542     }
543 
544   free (hol);
545 }
546 
547 static int
hol_entry_short_iterate(const struct hol_entry * entry,int (* func)(const struct argp_option * opt,const struct argp_option * real,const char * domain,void * cookie),const char * domain,void * cookie)548 hol_entry_short_iterate (const struct hol_entry *entry,
549                          int (*func)(const struct argp_option *opt,
550                                      const struct argp_option *real,
551                                      const char *domain, void *cookie),
552                          const char *domain, void *cookie)
553 {
554   unsigned nopts;
555   int val = 0;
556   const struct argp_option *opt, *real = entry->opt;
557   char *so = entry->short_options;
558 
559   for (opt = real, nopts = entry->num; nopts > 0 && !val; opt++, nopts--)
560     if (oshort (opt) && *so == opt->key)
561       {
562         if (!oalias (opt))
563           real = opt;
564         if (ovisible (opt))
565           val = (*func)(opt, real, domain, cookie);
566         so++;
567       }
568 
569   return val;
570 }
571 
572 static inline int
573 #if (__GNUC__ >= 3) || (__clang_major__ >= 4)
574 __attribute__ ((always_inline))
575 #endif
hol_entry_long_iterate(const struct hol_entry * entry,int (* func)(const struct argp_option * opt,const struct argp_option * real,const char * domain,void * cookie),const char * domain,void * cookie)576 hol_entry_long_iterate (const struct hol_entry *entry,
577                         int (*func)(const struct argp_option *opt,
578                                     const struct argp_option *real,
579                                     const char *domain, void *cookie),
580                         const char *domain, void *cookie)
581 {
582   unsigned nopts;
583   int val = 0;
584   const struct argp_option *opt, *real = entry->opt;
585 
586   for (opt = real, nopts = entry->num; nopts > 0 && !val; opt++, nopts--)
587     if (opt->name)
588       {
589         if (!oalias (opt))
590           real = opt;
591         if (ovisible (opt))
592           val = (*func)(opt, real, domain, cookie);
593       }
594 
595   return val;
596 }
597 
598 /* Iterator that returns true for the first short option.  */
599 static int
until_short(const struct argp_option * opt,const struct argp_option * real,const char * domain,void * cookie)600 until_short (const struct argp_option *opt, const struct argp_option *real,
601              const char *domain, void *cookie)
602 {
603   return oshort (opt) ? opt->key : 0;
604 }
605 
606 /* Returns the first valid short option in ENTRY, or 0 if there is none.  */
607 static char
hol_entry_first_short(const struct hol_entry * entry)608 hol_entry_first_short (const struct hol_entry *entry)
609 {
610   return hol_entry_short_iterate (entry, until_short,
611                                   entry->argp->argp_domain, 0);
612 }
613 
614 /* Returns the first valid long option in ENTRY, or 0 if there is none.  */
615 static const char *
hol_entry_first_long(const struct hol_entry * entry)616 hol_entry_first_long (const struct hol_entry *entry)
617 {
618   const struct argp_option *opt;
619   unsigned num;
620   for (opt = entry->opt, num = entry->num; num > 0; opt++, num--)
621     if (opt->name && ovisible (opt))
622       return opt->name;
623   return 0;
624 }
625 
626 /* Returns the entry in HOL with the long option name NAME, or 0 if there is
627    none.  */
628 static struct hol_entry *
hol_find_entry(struct hol * hol,const char * name)629 hol_find_entry (struct hol *hol, const char *name)
630 {
631   struct hol_entry *entry = hol->entries;
632   unsigned num_entries = hol->num_entries;
633 
634   while (num_entries-- > 0)
635     {
636       const struct argp_option *opt = entry->opt;
637       unsigned num_opts = entry->num;
638 
639       while (num_opts-- > 0)
640         if (opt->name && ovisible (opt) && strcmp (opt->name, name) == 0)
641           return entry;
642         else
643           opt++;
644 
645       entry++;
646     }
647 
648   return 0;
649 }
650 
651 /* If an entry with the long option NAME occurs in HOL, set its special
652    sort position to GROUP.  */
653 static void
hol_set_group(struct hol * hol,const char * name,int group)654 hol_set_group (struct hol *hol, const char *name, int group)
655 {
656   struct hol_entry *entry = hol_find_entry (hol, name);
657   if (entry)
658     entry->group = group;
659 }
660 
661 /* Order by group:  0, 1, 2, ..., n, -m, ..., -2, -1.
662    EQ is what to return if GROUP1 and GROUP2 are the same.  */
663 static int
group_cmp(int group1,int group2,int eq)664 group_cmp (int group1, int group2, int eq)
665 {
666   if (group1 == group2)
667     return eq;
668   else if ((group1 < 0 && group2 < 0) || (group1 >= 0 && group2 >= 0))
669     return group1 - group2;
670   else
671     return group2 - group1;
672 }
673 
674 /* Compare clusters CL1 & CL2 by the order that they should appear in
675    output.  */
676 static int
hol_cluster_cmp(const struct hol_cluster * cl1,const struct hol_cluster * cl2)677 hol_cluster_cmp (const struct hol_cluster *cl1, const struct hol_cluster *cl2)
678 {
679   /* If one cluster is deeper than the other, use its ancestor at the same
680      level, so that finding the common ancestor is straightforward.  */
681   while (cl1->depth > cl2->depth)
682     cl1 = cl1->parent;
683   while (cl2->depth > cl1->depth)
684     cl2 = cl2->parent;
685 
686   /* Now reduce both clusters to their ancestors at the point where both have
687      a common parent; these can be directly compared.  */
688   while (cl1->parent != cl2->parent)
689     cl1 = cl1->parent, cl2 = cl2->parent;
690 
691   return group_cmp (cl1->group, cl2->group, cl2->index - cl1->index);
692 }
693 
694 /* Return the ancestor of CL that's just below the root (i.e., has a parent
695    of 0).  */
696 static struct hol_cluster *
hol_cluster_base(struct hol_cluster * cl)697 hol_cluster_base (struct hol_cluster *cl)
698 {
699   while (cl->parent)
700     cl = cl->parent;
701   return cl;
702 }
703 
704 /* Return true if CL1 is a child of CL2.  */
705 static int
hol_cluster_is_child(const struct hol_cluster * cl1,const struct hol_cluster * cl2)706 hol_cluster_is_child (const struct hol_cluster *cl1,
707                       const struct hol_cluster *cl2)
708 {
709   while (cl1 && cl1 != cl2)
710     cl1 = cl1->parent;
711   return cl1 == cl2;
712 }
713 
714 /* Given the name of an OPTION_DOC option, modifies NAME to start at the tail
715    that should be used for comparisons, and returns true iff it should be
716    treated as a non-option.  */
717 static int
canon_doc_option(const char ** name)718 canon_doc_option (const char **name)
719 {
720   int non_opt;
721   /* Skip initial whitespace.  */
722   while (isspace (**name))
723     (*name)++;
724   /* Decide whether this looks like an option (leading '-') or not.  */
725   non_opt = (**name != '-');
726   /* Skip until part of name used for sorting.  */
727   while (**name && !isalnum (**name))
728     (*name)++;
729   return non_opt;
730 }
731 
732 #define HOL_ENTRY_PTRCMP(a,b) ((a)->ord < (b)->ord ? -1 : 1)
733 
734 /* Order ENTRY1 & ENTRY2 by the order which they should appear in a help
735    listing.  */
736 static int
hol_entry_cmp(const struct hol_entry * entry1,const struct hol_entry * entry2)737 hol_entry_cmp (const struct hol_entry *entry1,
738                const struct hol_entry *entry2)
739 {
740   /* The group numbers by which the entries should be ordered; if either is
741      in a cluster, then this is just the group within the cluster.  */
742   int group1 = entry1->group, group2 = entry2->group;
743 
744   if (entry1->cluster != entry2->cluster)
745     {
746       /* The entries are not within the same cluster, so we can't compare them
747          directly, we have to use the appropriate clustering level too.  */
748       if (! entry1->cluster)
749         /* ENTRY1 is at the 'base level', not in a cluster, so we have to
750            compare it's group number with that of the base cluster in which
751            ENTRY2 resides.  Note that if they're in the same group, the
752            clustered option always comes last.  */
753         return group_cmp (group1, hol_cluster_base (entry2->cluster)->group, -1);
754       else if (! entry2->cluster)
755         /* Likewise, but ENTRY2's not in a cluster.  */
756         return group_cmp (hol_cluster_base (entry1->cluster)->group, group2, 1);
757       else
758         /* Both entries are in clusters, we can just compare the clusters.  */
759         return hol_cluster_cmp (entry1->cluster, entry2->cluster);
760     }
761   else if (group1 == group2)
762     /* The entries are both in the same cluster and group, so compare them
763        alphabetically.  */
764     {
765       int short1 = hol_entry_first_short (entry1);
766       int short2 = hol_entry_first_short (entry2);
767       int doc1 = odoc (entry1->opt);
768       int doc2 = odoc (entry2->opt);
769       const char *long1 = hol_entry_first_long (entry1);
770       const char *long2 = hol_entry_first_long (entry2);
771 
772       if (doc1)
773         doc1 = long1 != NULL && canon_doc_option (&long1);
774       if (doc2)
775         doc2 = long2 != NULL && canon_doc_option (&long2);
776 
777       if (doc1 != doc2)
778         /* 'documentation' options always follow normal options (or
779            documentation options that *look* like normal options).  */
780         return doc1 - doc2;
781       else if (!short1 && !short2 && long1 && long2)
782         /* Only long options.  */
783         return __strcasecmp (long1, long2);
784       else
785         /* Compare short/short, long/short, short/long, using the first
786            character of long options.  Entries without *any* valid
787            options (such as options with OPTION_HIDDEN set) will be put
788            first, but as they're not displayed, it doesn't matter where
789            they are.  */
790         {
791           char first1 = short1 ? short1 : long1 ? *long1 : 0;
792           char first2 = short2 ? short2 : long2 ? *long2 : 0;
793 #ifdef _tolower
794           int lower_cmp = _tolower (first1) - _tolower (first2);
795 #else
796           int lower_cmp = tolower (first1) - tolower (first2);
797 #endif
798           /* Compare ignoring case, except when the options are both the
799              same letter, in which case lower-case always comes first.  */
800           return lower_cmp ? lower_cmp : first2 - first1;
801         }
802     }
803   else
804     /* Within the same cluster, but not the same group, so just compare
805        groups.  */
806     return group_cmp (group1, group2, 0);
807 }
808 
809 /* Version of hol_entry_cmp with correct signature for qsort.  */
810 static int
hol_entry_qcmp(const void * entry1_v,const void * entry2_v)811 hol_entry_qcmp (const void *entry1_v, const void *entry2_v)
812 {
813   return hol_entry_cmp (entry1_v, entry2_v);
814 }
815 
816 /* Sort HOL by group and alphabetically by option name (with short options
817    taking precedence over long).  Since the sorting is for display purposes
818    only, the shadowing of options isn't effected.  */
819 static void
hol_sort(struct hol * hol)820 hol_sort (struct hol *hol)
821 {
822   if (hol->num_entries > 0)
823     {
824       unsigned i;
825       struct hol_entry *e;
826       for (i = 0, e = hol->entries; i < hol->num_entries; i++, e++)
827         e->ord = i;
828       qsort (hol->entries, hol->num_entries, sizeof (struct hol_entry),
829              hol_entry_qcmp);
830     }
831 }
832 
833 /* Append MORE to HOL, destroying MORE in the process.  Options in HOL shadow
834    any in MORE with the same name.  */
835 static void
hol_append(struct hol * hol,struct hol * more)836 hol_append (struct hol *hol, struct hol *more)
837 {
838   struct hol_cluster **cl_end = &hol->clusters;
839 
840   /* Steal MORE's cluster list, and add it to the end of HOL's.  */
841   while (*cl_end)
842     cl_end = &(*cl_end)->next;
843   *cl_end = more->clusters;
844   more->clusters = 0;
845 
846   /* Merge entries.  */
847   if (more->num_entries > 0)
848     {
849       if (hol->num_entries == 0)
850         {
851           hol->num_entries = more->num_entries;
852           hol->entries = more->entries;
853           hol->short_options = more->short_options;
854           more->num_entries = 0;        /* Mark MORE's fields as invalid.  */
855         }
856       else
857         /* Append the entries in MORE to those in HOL, taking care to only add
858            non-shadowed SHORT_OPTIONS values.  */
859         {
860           unsigned left;
861           char *so, *more_so;
862           struct hol_entry *e;
863           unsigned num_entries = hol->num_entries + more->num_entries;
864           struct hol_entry *entries =
865             malloc (num_entries * sizeof (struct hol_entry));
866           unsigned hol_so_len = strlen (hol->short_options);
867           char *short_options =
868             malloc (hol_so_len + strlen (more->short_options) + 1);
869 
870           assert (entries && short_options);
871           if (SIZE_MAX <= UINT_MAX)
872             assert (num_entries <= SIZE_MAX / sizeof (struct hol_entry));
873 
874           __mempcpy (__mempcpy (entries, hol->entries,
875                                 hol->num_entries * sizeof (struct hol_entry)),
876                      more->entries,
877                      more->num_entries * sizeof (struct hol_entry));
878 
879           __mempcpy (short_options, hol->short_options, hol_so_len);
880 
881           /* Fix up the short options pointers from HOL.  */
882           for (e = entries, left = hol->num_entries; left > 0; e++, left--)
883             e->short_options
884               = short_options + (e->short_options - hol->short_options);
885 
886           /* Now add the short options from MORE, fixing up its entries
887              too.  */
888           so = short_options + hol_so_len;
889           more_so = more->short_options;
890           for (left = more->num_entries; left > 0; e++, left--)
891             {
892               int opts_left;
893               const struct argp_option *opt;
894 
895               e->short_options = so;
896 
897               for (opts_left = e->num, opt = e->opt; opts_left; opt++, opts_left--)
898                 {
899                   int ch = *more_so;
900                   if (oshort (opt) && ch == opt->key)
901                     /* The next short option in MORE_SO, CH, is from OPT.  */
902                     {
903                       if (! find_char (ch, short_options,
904                                        short_options + hol_so_len))
905                         /* The short option CH isn't shadowed by HOL's options,
906                            so add it to the sum.  */
907                         *so++ = ch;
908                       more_so++;
909                     }
910                 }
911             }
912 
913           *so = '\0';
914 
915           free (hol->entries);
916           free (hol->short_options);
917 
918           hol->entries = entries;
919           hol->num_entries = num_entries;
920           hol->short_options = short_options;
921         }
922     }
923 
924   hol_free (more);
925 }
926 
927 /* Inserts enough spaces to make sure STREAM is at column COL.  */
928 static void
indent_to(argp_fmtstream_t stream,unsigned col)929 indent_to (argp_fmtstream_t stream, unsigned col)
930 {
931   int needed = col - __argp_fmtstream_point (stream);
932   while (needed-- > 0)
933     __argp_fmtstream_putc (stream, ' ');
934 }
935 
936 /* Output to STREAM either a space, or a newline if there isn't room for at
937    least ENSURE characters before the right margin.  */
938 static void
space(argp_fmtstream_t stream,size_t ensure)939 space (argp_fmtstream_t stream, size_t ensure)
940 {
941   if (__argp_fmtstream_point (stream) + ensure
942       >= __argp_fmtstream_rmargin (stream))
943     __argp_fmtstream_putc (stream, '\n');
944   else
945     __argp_fmtstream_putc (stream, ' ');
946 }
947 
948 /* If the option REAL has an argument, we print it in using the printf
949    format REQ_FMT or OPT_FMT depending on whether it's a required or
950    optional argument.  */
951 static void
arg(const struct argp_option * real,const char * req_fmt,const char * opt_fmt,const char * domain,argp_fmtstream_t stream)952 arg (const struct argp_option *real, const char *req_fmt, const char *opt_fmt,
953      const char *domain, argp_fmtstream_t stream)
954 {
955   if (real->arg)
956     {
957       if (real->flags & OPTION_ARG_OPTIONAL)
958         __argp_fmtstream_printf (stream, opt_fmt,
959                                  dgettext (domain, real->arg));
960       else
961         __argp_fmtstream_printf (stream, req_fmt,
962                                  dgettext (domain, real->arg));
963     }
964 }
965 
966 /* Helper functions for hol_entry_help.  */
967 
968 /* State used during the execution of hol_help.  */
969 struct hol_help_state
970 {
971   /* PREV_ENTRY should contain the previous entry printed, or 0.  */
972   struct hol_entry *prev_entry;
973 
974   /* If an entry is in a different group from the previous one, and SEP_GROUPS
975      is true, then a blank line will be printed before any output. */
976   int sep_groups;
977 
978   /* True if a duplicate option argument was suppressed (only ever set if
979      UPARAMS.dup_args is false).  */
980   int suppressed_dup_arg;
981 };
982 
983 /* Some state used while printing a help entry (used to communicate with
984    helper functions).  See the doc for hol_entry_help for more info, as most
985    of the fields are copied from its arguments.  */
986 struct pentry_state
987 {
988   const struct hol_entry *entry;
989   argp_fmtstream_t stream;
990   struct hol_help_state *hhstate;
991 
992   /* True if nothing's been printed so far.  */
993   int first;
994 
995   /* If non-zero, the state that was used to print this help.  */
996   const struct argp_state *state;
997 };
998 
999 /* If a user doc filter should be applied to DOC, do so.  */
1000 static const char *
filter_doc(const char * doc,int key,const struct argp * argp,const struct argp_state * state)1001 filter_doc (const char *doc, int key, const struct argp *argp,
1002             const struct argp_state *state)
1003 {
1004   if (argp && argp->help_filter)
1005     /* We must apply a user filter to this output.  */
1006     {
1007       void *input = __argp_input (argp, state);
1008       return (*argp->help_filter) (key, doc, input);
1009     }
1010   else
1011     /* No filter.  */
1012     return doc;
1013 }
1014 
1015 /* Prints STR as a header line, with the margin lines set appropriately, and
1016    notes the fact that groups should be separated with a blank line.  ARGP is
1017    the argp that should dictate any user doc filtering to take place.  Note
1018    that the previous wrap margin isn't restored, but the left margin is reset
1019    to 0.  */
1020 static void
print_header(const char * str,const struct argp * argp,struct pentry_state * pest)1021 print_header (const char *str, const struct argp *argp,
1022               struct pentry_state *pest)
1023 {
1024   const char *tstr = str ? dgettext (argp->argp_domain, str) : NULL;
1025   const char *fstr = filter_doc (tstr, ARGP_KEY_HELP_HEADER, argp, pest->state);
1026 
1027   if (fstr)
1028     {
1029       if (*fstr)
1030         {
1031           if (pest->hhstate->prev_entry)
1032             /* Precede with a blank line.  */
1033             __argp_fmtstream_putc (pest->stream, '\n');
1034           indent_to (pest->stream, uparams.header_col);
1035           __argp_fmtstream_set_lmargin (pest->stream, uparams.header_col);
1036           __argp_fmtstream_set_wmargin (pest->stream, uparams.header_col);
1037           __argp_fmtstream_puts (pest->stream, fstr);
1038           __argp_fmtstream_set_lmargin (pest->stream, 0);
1039           __argp_fmtstream_putc (pest->stream, '\n');
1040         }
1041 
1042       pest->hhstate->sep_groups = 1; /* Separate subsequent groups. */
1043     }
1044 
1045   if (fstr != tstr)
1046     free ((char *) fstr);
1047 }
1048 
1049 /* Inserts a comma if this isn't the first item on the line, and then makes
1050    sure we're at least to column COL.  If this *is* the first item on a line,
1051    prints any pending whitespace/headers that should precede this line. Also
1052    clears FIRST.  */
1053 static void
comma(unsigned col,struct pentry_state * pest)1054 comma (unsigned col, struct pentry_state *pest)
1055 {
1056   if (pest->first)
1057     {
1058       const struct hol_entry *pe = pest->hhstate->prev_entry;
1059       const struct hol_cluster *cl = pest->entry->cluster;
1060 
1061       if (pest->hhstate->sep_groups && pe && pest->entry->group != pe->group)
1062         __argp_fmtstream_putc (pest->stream, '\n');
1063 
1064       if (cl && cl->header && *cl->header
1065           && (!pe
1066               || (pe->cluster != cl
1067                   && !hol_cluster_is_child (pe->cluster, cl))))
1068         /* If we're changing clusters, then this must be the start of the
1069            ENTRY's cluster unless that is an ancestor of the previous one
1070            (in which case we had just popped into a sub-cluster for a bit).
1071            If so, then print the cluster's header line.  */
1072         {
1073           int old_wm = __argp_fmtstream_wmargin (pest->stream);
1074           print_header (cl->header, cl->argp, pest);
1075           __argp_fmtstream_set_wmargin (pest->stream, old_wm);
1076         }
1077 
1078       pest->first = 0;
1079     }
1080   else
1081     __argp_fmtstream_puts (pest->stream, ", ");
1082 
1083   indent_to (pest->stream, col);
1084 }
1085 
1086 /* Print help for ENTRY to STREAM.  */
1087 static void
hol_entry_help(struct hol_entry * entry,const struct argp_state * state,argp_fmtstream_t stream,struct hol_help_state * hhstate)1088 hol_entry_help (struct hol_entry *entry, const struct argp_state *state,
1089                 argp_fmtstream_t stream, struct hol_help_state *hhstate)
1090 {
1091   unsigned num;
1092   const struct argp_option *real = entry->opt, *opt;
1093   char *so = entry->short_options;
1094   int have_long_opt = 0;        /* We have any long options.  */
1095   /* Saved margins.  */
1096   int old_lm = __argp_fmtstream_set_lmargin (stream, 0);
1097   int old_wm = __argp_fmtstream_wmargin (stream);
1098   /* PEST is a state block holding some of our variables that we'd like to
1099      share with helper functions.  */
1100   struct pentry_state pest = { entry, stream, hhstate, 1, state };
1101 
1102   if (! odoc (real))
1103     for (opt = real, num = entry->num; num > 0; opt++, num--)
1104       if (opt->name && ovisible (opt))
1105         {
1106           have_long_opt = 1;
1107           break;
1108         }
1109 
1110   /* First emit short options.  */
1111   __argp_fmtstream_set_wmargin (stream, uparams.short_opt_col); /* For truly bizarre cases. */
1112   for (opt = real, num = entry->num; num > 0; opt++, num--)
1113     if (oshort (opt) && opt->key == *so)
1114       /* OPT has a valid (non shadowed) short option.  */
1115       {
1116         if (ovisible (opt))
1117           {
1118             comma (uparams.short_opt_col, &pest);
1119             __argp_fmtstream_putc (stream, '-');
1120             __argp_fmtstream_putc (stream, *so);
1121             if (!have_long_opt || uparams.dup_args)
1122               arg (real, " %s", "[%s]",
1123                    state == NULL ? NULL : state->root_argp->argp_domain,
1124                    stream);
1125             else if (real->arg)
1126               hhstate->suppressed_dup_arg = 1;
1127           }
1128         so++;
1129       }
1130 
1131   /* Now, long options.  */
1132   if (odoc (real))
1133     /* A "documentation" option.  */
1134     {
1135       __argp_fmtstream_set_wmargin (stream, uparams.doc_opt_col);
1136       for (opt = real, num = entry->num; num > 0; opt++, num--)
1137         if (opt->name && ovisible (opt))
1138           {
1139             comma (uparams.doc_opt_col, &pest);
1140             /* Calling dgettext here isn't quite right, since sorting will
1141                have been done on the original; but documentation options
1142                should be pretty rare anyway...  */
1143             __argp_fmtstream_puts (stream,
1144                                    dgettext (state == NULL ? NULL
1145                                              : state->root_argp->argp_domain,
1146                                              opt->name));
1147           }
1148     }
1149   else
1150     /* A real long option.  */
1151     {
1152       __argp_fmtstream_set_wmargin (stream, uparams.long_opt_col);
1153       for (opt = real, num = entry->num; num > 0; opt++, num--)
1154         if (opt->name && ovisible (opt))
1155           {
1156             comma (uparams.long_opt_col, &pest);
1157             __argp_fmtstream_printf (stream, "--%s", opt->name);
1158             arg (real, "=%s", "[=%s]",
1159                  state == NULL ? NULL : state->root_argp->argp_domain, stream);
1160           }
1161     }
1162 
1163   /* Next, documentation strings.  */
1164   __argp_fmtstream_set_lmargin (stream, 0);
1165 
1166   if (pest.first)
1167     {
1168       /* Didn't print any switches, what's up?  */
1169       if (!oshort (real) && !real->name)
1170         /* This is a group header, print it nicely.  */
1171         print_header (real->doc, entry->argp, &pest);
1172       else
1173         /* Just a totally shadowed option or null header; print nothing.  */
1174         goto cleanup;           /* Just return, after cleaning up.  */
1175     }
1176   else
1177     {
1178       const char *tstr = real->doc ? dgettext (state == NULL ? NULL
1179                                                : state->root_argp->argp_domain,
1180                                                real->doc) : 0;
1181       const char *fstr = filter_doc (tstr, real->key, entry->argp, state);
1182       if (fstr && *fstr)
1183         {
1184           unsigned int col = __argp_fmtstream_point (stream);
1185 
1186           __argp_fmtstream_set_lmargin (stream, uparams.opt_doc_col);
1187           __argp_fmtstream_set_wmargin (stream, uparams.opt_doc_col);
1188 
1189           if (col > (unsigned int) (uparams.opt_doc_col + 3))
1190             __argp_fmtstream_putc (stream, '\n');
1191           else if (col >= (unsigned int) uparams.opt_doc_col)
1192             __argp_fmtstream_puts (stream, "   ");
1193           else
1194             indent_to (stream, uparams.opt_doc_col);
1195 
1196           __argp_fmtstream_puts (stream, fstr);
1197         }
1198       if (fstr && fstr != tstr)
1199         free ((char *) fstr);
1200 
1201       /* Reset the left margin.  */
1202       __argp_fmtstream_set_lmargin (stream, 0);
1203       __argp_fmtstream_putc (stream, '\n');
1204     }
1205 
1206   hhstate->prev_entry = entry;
1207 
1208 cleanup:
1209   __argp_fmtstream_set_lmargin (stream, old_lm);
1210   __argp_fmtstream_set_wmargin (stream, old_wm);
1211 }
1212 
1213 /* Output a long help message about the options in HOL to STREAM.  */
1214 static void
hol_help(struct hol * hol,const struct argp_state * state,argp_fmtstream_t stream)1215 hol_help (struct hol *hol, const struct argp_state *state,
1216           argp_fmtstream_t stream)
1217 {
1218   unsigned num;
1219   struct hol_entry *entry;
1220   struct hol_help_state hhstate = { 0, 0, 0 };
1221 
1222   for (entry = hol->entries, num = hol->num_entries; num > 0; entry++, num--)
1223     hol_entry_help (entry, state, stream, &hhstate);
1224 
1225   if (hhstate.suppressed_dup_arg && uparams.dup_args_note)
1226     {
1227       const char *tstr = dgettext (state == NULL ? NULL
1228                                    : state->root_argp->argp_domain, "\
1229 Mandatory or optional arguments to long options are also mandatory or \
1230 optional for any corresponding short options.");
1231       const char *fstr = filter_doc (tstr, ARGP_KEY_HELP_DUP_ARGS_NOTE,
1232                                      state ? state->root_argp : 0, state);
1233       if (fstr && *fstr)
1234         {
1235           __argp_fmtstream_putc (stream, '\n');
1236           __argp_fmtstream_puts (stream, fstr);
1237           __argp_fmtstream_putc (stream, '\n');
1238         }
1239       if (fstr && fstr != tstr)
1240         free ((char *) fstr);
1241     }
1242 }
1243 
1244 /* Helper functions for hol_usage.  */
1245 
1246 /* If OPT is a short option without an arg, append its key to the string
1247    pointer pointer to by COOKIE, and advance the pointer.  */
1248 static int
add_argless_short_opt(const struct argp_option * opt,const struct argp_option * real,const char * domain,void * cookie)1249 add_argless_short_opt (const struct argp_option *opt,
1250                        const struct argp_option *real,
1251                        const char *domain, void *cookie)
1252 {
1253   char **snao_end = cookie;
1254   if (!(opt->arg || real->arg)
1255       && !((opt->flags | real->flags) & OPTION_NO_USAGE))
1256     *(*snao_end)++ = opt->key;
1257   return 0;
1258 }
1259 
1260 /* If OPT is a short option with an arg, output a usage entry for it to the
1261    stream pointed at by COOKIE.  */
1262 static int
usage_argful_short_opt(const struct argp_option * opt,const struct argp_option * real,const char * domain,void * cookie)1263 usage_argful_short_opt (const struct argp_option *opt,
1264                         const struct argp_option *real,
1265                         const char *domain, void *cookie)
1266 {
1267   argp_fmtstream_t stream = cookie;
1268   const char *arg = opt->arg;
1269   int flags = opt->flags | real->flags;
1270 
1271   if (! arg)
1272     arg = real->arg;
1273 
1274   if (arg && !(flags & OPTION_NO_USAGE))
1275     {
1276       arg = dgettext (domain, arg);
1277 
1278       if (flags & OPTION_ARG_OPTIONAL)
1279         __argp_fmtstream_printf (stream, " [-%c[%s]]", opt->key, arg);
1280       else
1281         {
1282           /* Manually do line wrapping so that it (probably) won't
1283              get wrapped at the embedded space.  */
1284           space (stream, 6 + strlen (arg));
1285           __argp_fmtstream_printf (stream, "[-%c %s]", opt->key, arg);
1286         }
1287     }
1288 
1289   return 0;
1290 }
1291 
1292 /* Output a usage entry for the long option opt to the stream pointed at by
1293    COOKIE.  */
1294 static int
usage_long_opt(const struct argp_option * opt,const struct argp_option * real,const char * domain,void * cookie)1295 usage_long_opt (const struct argp_option *opt,
1296                 const struct argp_option *real,
1297                 const char *domain, void *cookie)
1298 {
1299   argp_fmtstream_t stream = cookie;
1300   const char *arg = opt->arg;
1301   int flags = opt->flags | real->flags;
1302 
1303   if (! arg)
1304     arg = real->arg;
1305 
1306   if (! (flags & OPTION_NO_USAGE))
1307     {
1308       if (arg)
1309         {
1310           arg = dgettext (domain, arg);
1311           if (flags & OPTION_ARG_OPTIONAL)
1312             __argp_fmtstream_printf (stream, " [--%s[=%s]]", opt->name, arg);
1313           else
1314             __argp_fmtstream_printf (stream, " [--%s=%s]", opt->name, arg);
1315         }
1316       else
1317         __argp_fmtstream_printf (stream, " [--%s]", opt->name);
1318     }
1319 
1320   return 0;
1321 }
1322 
1323 /* Print a short usage description for the arguments in HOL to STREAM.  */
1324 static void
hol_usage(struct hol * hol,argp_fmtstream_t stream)1325 hol_usage (struct hol *hol, argp_fmtstream_t stream)
1326 {
1327   if (hol->num_entries > 0)
1328     {
1329       unsigned nentries;
1330       struct hol_entry *entry;
1331       char *short_no_arg_opts = alloca (strlen (hol->short_options) + 1);
1332       char *snao_end = short_no_arg_opts;
1333 
1334       /* First we put a list of short options without arguments.  */
1335       for (entry = hol->entries, nentries = hol->num_entries
1336            ; nentries > 0
1337            ; entry++, nentries--)
1338         hol_entry_short_iterate (entry, add_argless_short_opt,
1339                                  entry->argp->argp_domain, &snao_end);
1340       if (snao_end > short_no_arg_opts)
1341         {
1342           *snao_end++ = 0;
1343           __argp_fmtstream_printf (stream, " [-%s]", short_no_arg_opts);
1344         }
1345 
1346       /* Now a list of short options *with* arguments.  */
1347       for (entry = hol->entries, nentries = hol->num_entries
1348            ; nentries > 0
1349            ; entry++, nentries--)
1350         hol_entry_short_iterate (entry, usage_argful_short_opt,
1351                                  entry->argp->argp_domain, stream);
1352 
1353       /* Finally, a list of long options (whew!).  */
1354       for (entry = hol->entries, nentries = hol->num_entries
1355            ; nentries > 0
1356            ; entry++, nentries--)
1357         hol_entry_long_iterate (entry, usage_long_opt,
1358                                 entry->argp->argp_domain, stream);
1359     }
1360 }
1361 
1362 /* Make a HOL containing all levels of options in ARGP.  CLUSTER is the
1363    cluster in which ARGP's entries should be clustered, or 0.  */
1364 static struct hol *
argp_hol(const struct argp * argp,struct hol_cluster * cluster)1365 argp_hol (const struct argp *argp, struct hol_cluster *cluster)
1366 {
1367   const struct argp_child *child = argp->children;
1368   struct hol *hol = make_hol (argp, cluster);
1369   if (child)
1370     while (child->argp)
1371       {
1372         struct hol_cluster *child_cluster =
1373           ((child->group || child->header)
1374            /* Put CHILD->argp within its own cluster.  */
1375            ? hol_add_cluster (hol, child->group, child->header,
1376                               child - argp->children, cluster, argp)
1377            /* Just merge it into the parent's cluster.  */
1378            : cluster);
1379         hol_append (hol, argp_hol (child->argp, child_cluster)) ;
1380         child++;
1381       }
1382   return hol;
1383 }
1384 
1385 /* Calculate how many different levels with alternative args strings exist in
1386    ARGP.  */
1387 static size_t
argp_args_levels(const struct argp * argp)1388 argp_args_levels (const struct argp *argp)
1389 {
1390   size_t levels = 0;
1391   const struct argp_child *child = argp->children;
1392 
1393   if (argp->args_doc && strchr (argp->args_doc, '\n'))
1394     levels++;
1395 
1396   if (child)
1397     while (child->argp)
1398       levels += argp_args_levels ((child++)->argp);
1399 
1400   return levels;
1401 }
1402 
1403 /* Print all the non-option args documented in ARGP to STREAM.  Any output is
1404    preceded by a space.  LEVELS is a pointer to a byte vector the length
1405    returned by argp_args_levels; it should be initialized to zero, and
1406    updated by this routine for the next call if ADVANCE is true.  True is
1407    returned as long as there are more patterns to output.  */
1408 static int
argp_args_usage(const struct argp * argp,const struct argp_state * state,char ** levels,int advance,argp_fmtstream_t stream)1409 argp_args_usage (const struct argp *argp, const struct argp_state *state,
1410                  char **levels, int advance, argp_fmtstream_t stream)
1411 {
1412   char *our_level = *levels;
1413   int multiple = 0;
1414   const struct argp_child *child = argp->children;
1415   const char *tdoc =
1416     argp->args_doc ? dgettext (argp->argp_domain, argp->args_doc) : NULL;
1417   const char *fdoc = filter_doc (tdoc, ARGP_KEY_HELP_ARGS_DOC, argp, state);
1418   const char *nl = NULL;
1419 
1420   if (fdoc)
1421     {
1422       const char *cp = fdoc;
1423       nl = __strchrnul (cp, '\n');
1424       if (*nl != '\0')
1425         /* This is a 'multi-level' args doc; advance to the correct position
1426            as determined by our state in LEVELS, and update LEVELS.  */
1427         {
1428           int i;
1429           multiple = 1;
1430           for (i = 0; i < *our_level; i++)
1431             cp = nl + 1, nl = __strchrnul (cp, '\n');
1432           (*levels)++;
1433         }
1434 
1435       /* Manually do line wrapping so that it (probably) won't get wrapped at
1436          any embedded spaces.  */
1437       space (stream, 1 + nl - cp);
1438 
1439       __argp_fmtstream_write (stream, cp, nl - cp);
1440     }
1441   if (fdoc && fdoc != tdoc)
1442     free ((char *)fdoc);        /* Free user's modified doc string.  */
1443 
1444   if (child)
1445     while (child->argp)
1446       advance = !argp_args_usage ((child++)->argp, state, levels, advance, stream);
1447 
1448   if (advance && multiple)
1449     {
1450       /* Need to increment our level.  */
1451       if (*nl)
1452         /* There's more we can do here.  */
1453         {
1454           (*our_level)++;
1455           advance = 0;          /* Our parent shouldn't advance also. */
1456         }
1457       else if (*our_level > 0)
1458         /* We had multiple levels, but used them up; reset to zero.  */
1459         *our_level = 0;
1460     }
1461 
1462   return !advance;
1463 }
1464 
1465 /* Print the documentation for ARGP to STREAM; if POST is false, then
1466    everything preceding a '\v' character in the documentation strings (or
1467    the whole string, for those with none) is printed, otherwise, everything
1468    following the '\v' character (nothing for strings without).  Each separate
1469    bit of documentation is separated a blank line, and if PRE_BLANK is true,
1470    then the first is as well.  If FIRST_ONLY is true, only the first
1471    occurrence is output.  Returns true if anything was output.  */
1472 static int
argp_doc(const struct argp * argp,const struct argp_state * state,int post,int pre_blank,int first_only,argp_fmtstream_t stream)1473 argp_doc (const struct argp *argp, const struct argp_state *state,
1474           int post, int pre_blank, int first_only,
1475           argp_fmtstream_t stream)
1476 {
1477   const char *text;
1478   const char *inp_text;
1479   void *input = 0;
1480   int anything = 0;
1481   size_t inp_text_limit = 0;
1482   const char *doc = argp->doc ? dgettext (argp->argp_domain, argp->doc) : NULL;
1483   const struct argp_child *child = argp->children;
1484 
1485   if (doc)
1486     {
1487       char *vt = strchr (doc, '\v');
1488       inp_text = post ? (vt ? vt + 1 : 0) : doc;
1489       inp_text_limit = (!post && vt) ? (vt - doc) : 0;
1490     }
1491   else
1492     inp_text = 0;
1493 
1494   if (argp->help_filter)
1495     /* We have to filter the doc strings.  */
1496     {
1497       if (inp_text_limit)
1498         /* Copy INP_TEXT so that it's nul-terminated.  */
1499         inp_text = __strndup (inp_text, inp_text_limit);
1500       input = __argp_input (argp, state);
1501       text =
1502         (*argp->help_filter) (post
1503                               ? ARGP_KEY_HELP_POST_DOC
1504                               : ARGP_KEY_HELP_PRE_DOC,
1505                               inp_text, input);
1506     }
1507   else
1508     text = (const char *) inp_text;
1509 
1510   if (text)
1511     {
1512       if (pre_blank)
1513         __argp_fmtstream_putc (stream, '\n');
1514 
1515       if (text == inp_text && inp_text_limit)
1516         __argp_fmtstream_write (stream, inp_text, inp_text_limit);
1517       else
1518         __argp_fmtstream_puts (stream, text);
1519 
1520       if (__argp_fmtstream_point (stream) > __argp_fmtstream_lmargin (stream))
1521         __argp_fmtstream_putc (stream, '\n');
1522 
1523       anything = 1;
1524     }
1525 
1526   if (text && text != inp_text)
1527     free ((char *) text);       /* Free TEXT returned from the help filter.  */
1528   if (inp_text && inp_text_limit && argp->help_filter)
1529     free ((char *) inp_text);   /* We copied INP_TEXT, so free it now.  */
1530 
1531   if (post && argp->help_filter)
1532     /* Now see if we have to output a ARGP_KEY_HELP_EXTRA text.  */
1533     {
1534       text = (*argp->help_filter) (ARGP_KEY_HELP_EXTRA, 0, input);
1535       if (text)
1536         {
1537           if (anything || pre_blank)
1538             __argp_fmtstream_putc (stream, '\n');
1539           __argp_fmtstream_puts (stream, text);
1540           free ((char *) text);
1541           if (__argp_fmtstream_point (stream)
1542               > __argp_fmtstream_lmargin (stream))
1543             __argp_fmtstream_putc (stream, '\n');
1544           anything = 1;
1545         }
1546     }
1547 
1548   if (child)
1549     while (child->argp && !(first_only && anything))
1550       anything |=
1551         argp_doc ((child++)->argp, state,
1552                   post, anything || pre_blank, first_only,
1553                   stream);
1554 
1555   return anything;
1556 }
1557 
1558 /* Output a usage message for ARGP to STREAM.  If called from
1559    argp_state_help, STATE is the relevant parsing state.  FLAGS are from the
1560    set ARGP_HELP_*.  NAME is what to use wherever a 'program name' is
1561    needed. */
1562 static void
_help(const struct argp * argp,const struct argp_state * state,FILE * stream,unsigned flags,char * name)1563 _help (const struct argp *argp, const struct argp_state *state, FILE *stream,
1564        unsigned flags, char *name)
1565 {
1566   int anything = 0;             /* Whether we've output anything.  */
1567   struct hol *hol = 0;
1568   argp_fmtstream_t fs;
1569 
1570   if (! stream)
1571     return;
1572 
1573 #if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE)
1574   __flockfile (stream);
1575 #endif
1576 
1577   if (! uparams.valid)
1578     fill_in_uparams (state);
1579 
1580   fs = __argp_make_fmtstream (stream, 0, uparams.rmargin, 0);
1581   if (! fs)
1582     {
1583 #if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE)
1584       __funlockfile (stream);
1585 #endif
1586       return;
1587     }
1588 
1589   if (flags & (ARGP_HELP_USAGE | ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG))
1590     {
1591       hol = argp_hol (argp, 0);
1592 
1593       /* If present, these options always come last.  */
1594       hol_set_group (hol, "help", -1);
1595       hol_set_group (hol, "version", -1);
1596 
1597       hol_sort (hol);
1598     }
1599 
1600   if (flags & (ARGP_HELP_USAGE | ARGP_HELP_SHORT_USAGE))
1601     /* Print a short "Usage:" message.  */
1602     {
1603       int first_pattern = 1, more_patterns;
1604       size_t num_pattern_levels = argp_args_levels (argp);
1605       char *pattern_levels = alloca (num_pattern_levels);
1606 
1607       memset (pattern_levels, 0, num_pattern_levels);
1608 
1609       do
1610         {
1611           int old_lm;
1612           int old_wm = __argp_fmtstream_set_wmargin (fs, uparams.usage_indent);
1613           char *levels = pattern_levels;
1614 
1615           if (first_pattern)
1616             __argp_fmtstream_printf (fs, "%s %s",
1617                                      dgettext (argp->argp_domain, "Usage:"),
1618                                      name);
1619           else
1620             __argp_fmtstream_printf (fs, "%s %s",
1621                                      dgettext (argp->argp_domain, "  or: "),
1622                                      name);
1623 
1624           /* We set the lmargin as well as the wmargin, because hol_usage
1625              manually wraps options with newline to avoid annoying breaks.  */
1626           old_lm = __argp_fmtstream_set_lmargin (fs, uparams.usage_indent);
1627 
1628           if (flags & ARGP_HELP_SHORT_USAGE)
1629             /* Just show where the options go.  */
1630             {
1631               if (hol->num_entries > 0)
1632                 __argp_fmtstream_puts (fs, dgettext (argp->argp_domain,
1633                                                      " [OPTION...]"));
1634             }
1635           else
1636             /* Actually print the options.  */
1637             {
1638               hol_usage (hol, fs);
1639               flags |= ARGP_HELP_SHORT_USAGE; /* But only do so once.  */
1640             }
1641 
1642           more_patterns = argp_args_usage (argp, state, &levels, 1, fs);
1643 
1644           __argp_fmtstream_set_wmargin (fs, old_wm);
1645           __argp_fmtstream_set_lmargin (fs, old_lm);
1646 
1647           __argp_fmtstream_putc (fs, '\n');
1648           anything = 1;
1649 
1650           first_pattern = 0;
1651         }
1652       while (more_patterns);
1653     }
1654 
1655   if (flags & ARGP_HELP_PRE_DOC)
1656     anything |= argp_doc (argp, state, 0, 0, 1, fs);
1657 
1658   if (flags & ARGP_HELP_SEE)
1659     {
1660       __argp_fmtstream_printf (fs, dgettext (argp->argp_domain, "\
1661 Try '%s --help' or '%s --usage' for more information.\n"),
1662                                name, name);
1663       anything = 1;
1664     }
1665 
1666   if (flags & ARGP_HELP_LONG)
1667     /* Print a long, detailed help message.  */
1668     {
1669       /* Print info about all the options.  */
1670       if (hol->num_entries > 0)
1671         {
1672           if (anything)
1673             __argp_fmtstream_putc (fs, '\n');
1674           hol_help (hol, state, fs);
1675           anything = 1;
1676         }
1677     }
1678 
1679   if (flags & ARGP_HELP_POST_DOC)
1680     /* Print any documentation strings at the end.  */
1681     anything |= argp_doc (argp, state, 1, anything, 0, fs);
1682 
1683   if ((flags & ARGP_HELP_BUG_ADDR) && argp_program_bug_address)
1684     {
1685       if (anything)
1686         __argp_fmtstream_putc (fs, '\n');
1687       __argp_fmtstream_printf (fs, dgettext (argp->argp_domain,
1688                                              "Report bugs to %s.\n"),
1689                                argp_program_bug_address);
1690       anything = 1;
1691     }
1692 
1693 #if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE)
1694   __funlockfile (stream);
1695 #endif
1696 
1697   if (hol)
1698     hol_free (hol);
1699 
1700   __argp_fmtstream_free (fs);
1701 }
1702 
1703 /* Output a usage message for ARGP to STREAM.  FLAGS are from the set
1704    ARGP_HELP_*.  NAME is what to use wherever a 'program name' is needed. */
__argp_help(const struct argp * argp,FILE * stream,unsigned flags,char * name)1705 void __argp_help (const struct argp *argp, FILE *stream,
1706                   unsigned flags, char *name)
1707 {
1708   _help (argp, 0, stream, flags, name);
1709 }
1710 #ifdef weak_alias
weak_alias(__argp_help,argp_help)1711 weak_alias (__argp_help, argp_help)
1712 #endif
1713 
1714 #if ! (defined _LIBC || HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME)
1715 char *
1716 __argp_short_program_name (void)
1717 {
1718 # if HAVE_DECL_PROGRAM_INVOCATION_NAME
1719   char *name = strrchr (program_invocation_name, '/');
1720   return name ? name + 1 : program_invocation_name;
1721 # else
1722   /* FIXME: What now? Miles suggests that it is better to use NULL,
1723      but currently the value is passed on directly to fputs_unlocked,
1724      so that requires more changes. */
1725 # if __GNUC__
1726 #  warning No reasonable value to return
1727 # endif /* __GNUC__ */
1728   return "";
1729 # endif
1730 }
1731 #endif
1732 
1733 /* Output, if appropriate, a usage message for STATE to STREAM.  FLAGS are
1734    from the set ARGP_HELP_*.  */
1735 void
__argp_state_help(const struct argp_state * state,FILE * stream,unsigned flags)1736 __argp_state_help (const struct argp_state *state, FILE *stream, unsigned flags)
1737 {
1738   if ((!state || ! (state->flags & ARGP_NO_ERRS)) && stream)
1739     {
1740       if (state && (state->flags & ARGP_LONG_ONLY))
1741         flags |= ARGP_HELP_LONG_ONLY;
1742 
1743       _help (state ? state->root_argp : 0, state, stream, flags,
1744              state ? state->name : __argp_short_program_name ());
1745 
1746       if (!state || ! (state->flags & ARGP_NO_EXIT))
1747         {
1748           if (flags & ARGP_HELP_EXIT_ERR)
1749             exit (argp_err_exit_status);
1750           if (flags & ARGP_HELP_EXIT_OK)
1751             exit (0);
1752         }
1753   }
1754 }
1755 #ifdef weak_alias
weak_alias(__argp_state_help,argp_state_help)1756 weak_alias (__argp_state_help, argp_state_help)
1757 #endif
1758 
1759 /* If appropriate, print the printf string FMT and following args, preceded
1760    by the program name and ':', to stderr, and followed by a "Try ... --help"
1761    message, then exit (1).  */
1762 void
1763 __argp_error (const struct argp_state *state, const char *fmt, ...)
1764 {
1765   if (!state || !(state->flags & ARGP_NO_ERRS))
1766     {
1767       FILE *stream = state ? state->err_stream : stderr;
1768 
1769       if (stream)
1770         {
1771           va_list ap;
1772 
1773 #if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE)
1774           __flockfile (stream);
1775 #endif
1776 
1777           va_start (ap, fmt);
1778 
1779 #ifdef _LIBC
1780           char *buf;
1781 
1782           if (_IO_vasprintf (&buf, fmt, ap) < 0)
1783             buf = NULL;
1784 
1785           __fxprintf (stream, "%s: %s\n",
1786                       state ? state->name : __argp_short_program_name (), buf);
1787 
1788           free (buf);
1789 #else
1790           fputs_unlocked (state ? state->name : __argp_short_program_name (),
1791                           stream);
1792           putc_unlocked (':', stream);
1793           putc_unlocked (' ', stream);
1794 
1795           vfprintf (stream, fmt, ap);
1796 
1797           putc_unlocked ('\n', stream);
1798 #endif
1799 
1800           __argp_state_help (state, stream, ARGP_HELP_STD_ERR);
1801 
1802           va_end (ap);
1803 
1804 #if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE)
1805           __funlockfile (stream);
1806 #endif
1807         }
1808     }
1809 }
1810 #ifdef weak_alias
weak_alias(__argp_error,argp_error)1811 weak_alias (__argp_error, argp_error)
1812 #endif
1813 
1814 /* Similar to the standard gnu error-reporting function error(), but will
1815    respect the ARGP_NO_EXIT and ARGP_NO_ERRS flags in STATE, and will print
1816    to STATE->err_stream.  This is useful for argument parsing code that is
1817    shared between program startup (when exiting is desired) and runtime
1818    option parsing (when typically an error code is returned instead).  The
1819    difference between this function and argp_error is that the latter is for
1820    *parsing errors*, and the former is for other problems that occur during
1821    parsing but don't reflect a (syntactic) problem with the input.  */
1822 void
1823 __argp_failure (const struct argp_state *state, int status, int errnum,
1824                 const char *fmt, ...)
1825 {
1826   if (!state || !(state->flags & ARGP_NO_ERRS))
1827     {
1828       FILE *stream = state ? state->err_stream : stderr;
1829 
1830       if (stream)
1831         {
1832 #if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE)
1833           __flockfile (stream);
1834 #endif
1835 
1836 #ifdef _LIBC
1837           __fxprintf (stream, "%s",
1838                       state ? state->name : __argp_short_program_name ());
1839 #else
1840           fputs_unlocked (state ? state->name : __argp_short_program_name (),
1841                           stream);
1842 #endif
1843 
1844           if (fmt)
1845             {
1846               va_list ap;
1847 
1848               va_start (ap, fmt);
1849 #ifdef _LIBC
1850               char *buf;
1851 
1852               if (_IO_vasprintf (&buf, fmt, ap) < 0)
1853                 buf = NULL;
1854 
1855               __fxprintf (stream, ": %s", buf);
1856 
1857               free (buf);
1858 #else
1859               putc_unlocked (':', stream);
1860               putc_unlocked (' ', stream);
1861 
1862               vfprintf (stream, fmt, ap);
1863 #endif
1864 
1865               va_end (ap);
1866             }
1867 
1868           if (errnum)
1869             {
1870               char buf[200];
1871 
1872 #ifdef _LIBC
1873               __fxprintf (stream, ": %s",
1874                           __strerror_r (errnum, buf, sizeof (buf)));
1875 #else
1876               char const *s = NULL;
1877               putc_unlocked (':', stream);
1878               putc_unlocked (' ', stream);
1879 # if GNULIB_STRERROR_R_POSIX || HAVE_DECL_STRERROR_R
1880 #  if !GNULIB_STRERROR_R_POSIX && STRERROR_R_CHAR_P
1881               s = __strerror_r (errnum, buf, sizeof buf);
1882 #  else
1883               if (__strerror_r (errnum, buf, sizeof buf) == 0)
1884                 s = buf;
1885 #  endif
1886 # endif
1887               if (! s && ! (s = strerror (errnum)))
1888                 s = dgettext (state->root_argp->argp_domain,
1889                               "Unknown system error");
1890               fputs_unlocked (s, stream);
1891 #endif
1892             }
1893 
1894 #if _LIBC
1895           if (_IO_fwide (stream, 0) > 0)
1896             putwc_unlocked (L'\n', stream);
1897           else
1898 #endif
1899             putc_unlocked ('\n', stream);
1900 
1901 #if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE)
1902           __funlockfile (stream);
1903 #endif
1904 
1905           if (status && (!state || !(state->flags & ARGP_NO_EXIT)))
1906             exit (status);
1907         }
1908     }
1909 }
1910 #ifdef weak_alias
1911 weak_alias (__argp_failure, argp_failure)
1912 #endif
1913