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