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