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