Bug Summary

File:argp-standalone/argp-help.c
Location:line 1328, column 7
Description:Access to field 'num_entries' results in a dereference of a null pointer (loaded from variable 'hol')

Annotated Source Code

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