00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef _GNU_SOURCE
00021 # define _GNU_SOURCE 1
00022 #endif
00023
00024 #ifdef HAVE_CONFIG_H
00025 # include <config.h>
00026 #endif
00027
00028 #include <alloca.h>
00029 #include <errno.h>
00030 #include <stddef.h>
00031 #include <stdlib.h>
00032 #include <string.h>
00033 #include <assert.h>
00034 #include <stdarg.h>
00035 #include <ctype.h>
00036 #include <limits.h>
00037 #ifdef USE_IN_LIBIO
00038 # include <wchar.h>
00039 #endif
00040
00041 #ifdef _LIBC
00042 # include <libintl.h>
00043 # undef dgettext
00044 # define dgettext(domain, msgid) \
00045 INTUSE(__dcgettext) (domain, msgid, LC_MESSAGES)
00046 #else
00047 # include "gettext.h"
00048 #endif
00049
00050 #include "argp.h"
00051 #include "argp-fmtstream.h"
00052 #include "argp-namefrob.h"
00053
00054 #ifndef SIZE_MAX
00055 # define SIZE_MAX ((size_t) -1)
00056 #endif
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066 #define DUP_ARGS 0
00067 #define DUP_ARGS_NOTE 1
00068 #define SHORT_OPT_COL 2
00069 #define LONG_OPT_COL 6
00070 #define DOC_OPT_COL 2
00071 #define OPT_DOC_COL 29
00072 #define HEADER_COL 1
00073 #define USAGE_INDENT 12
00074 #define RMARGIN 79
00075
00076
00077
00078 struct uparams
00079 {
00080
00081
00082
00083
00084
00085 int dup_args;
00086
00087
00088
00089 int dup_args_note;
00090
00091
00092 int short_opt_col;
00093 int long_opt_col;
00094 int doc_opt_col;
00095 int opt_doc_col;
00096 int header_col;
00097 int usage_indent;
00098 int rmargin;
00099
00100 int valid;
00101 };
00102
00103
00104 static struct uparams uparams = {
00105 DUP_ARGS, DUP_ARGS_NOTE,
00106 SHORT_OPT_COL, LONG_OPT_COL, DOC_OPT_COL, OPT_DOC_COL, HEADER_COL,
00107 USAGE_INDENT, RMARGIN,
00108 0
00109 };
00110
00111
00112 struct uparam_name
00113 {
00114 const char *name;
00115 int is_bool;
00116 size_t uparams_offs;
00117 };
00118
00119
00120 static const struct uparam_name uparam_names[] =
00121 {
00122 { "dup-args", 1, offsetof (struct uparams, dup_args) },
00123 { "dup-args-note", 1, offsetof (struct uparams, dup_args_note) },
00124 { "short-opt-col", 0, offsetof (struct uparams, short_opt_col) },
00125 { "long-opt-col", 0, offsetof (struct uparams, long_opt_col) },
00126 { "doc-opt-col", 0, offsetof (struct uparams, doc_opt_col) },
00127 { "opt-doc-col", 0, offsetof (struct uparams, opt_doc_col) },
00128 { "header-col", 0, offsetof (struct uparams, header_col) },
00129 { "usage-indent", 0, offsetof (struct uparams, usage_indent) },
00130 { "rmargin", 0, offsetof (struct uparams, rmargin) },
00131 { 0 }
00132 };
00133
00134
00135 static void
00136 fill_in_uparams (const struct argp_state *state)
00137 {
00138 const char *var = getenv ("ARGP_HELP_FMT");
00139
00140 #define SKIPWS(p) do { while (isspace (*p)) p++; } while (0);
00141
00142 if (var)
00143
00144 while (*var)
00145 {
00146 SKIPWS (var);
00147
00148 if (isalpha (*var))
00149 {
00150 size_t var_len;
00151 const struct uparam_name *un;
00152 int unspec = 0, val = 0;
00153 const char *arg = var;
00154
00155 while (isalnum (*arg) || *arg == '-' || *arg == '_')
00156 arg++;
00157 var_len = arg - var;
00158
00159 SKIPWS (arg);
00160
00161 if (*arg == '\0' || *arg == ',')
00162 unspec = 1;
00163 else if (*arg == '=')
00164 {
00165 arg++;
00166 SKIPWS (arg);
00167 }
00168
00169 if (unspec)
00170 {
00171 if (var[0] == 'n' && var[1] == 'o' && var[2] == '-')
00172 {
00173 val = 0;
00174 var += 3;
00175 var_len -= 3;
00176 }
00177 else
00178 val = 1;
00179 }
00180 else if (isdigit (*arg))
00181 {
00182 val = atoi (arg);
00183 while (isdigit (*arg))
00184 arg++;
00185 SKIPWS (arg);
00186 }
00187
00188 for (un = uparam_names; un->name; un++)
00189 if (strlen (un->name) == var_len
00190 && strncmp (var, un->name, var_len) == 0)
00191 {
00192 if (unspec && !un->is_bool)
00193 __argp_failure (state, 0, 0,
00194 dgettext (state->root_argp->argp_domain, "\
00195 %.*s: ARGP_HELP_FMT parameter requires a value"),
00196 (int) var_len, var);
00197 else
00198 *(int *)((char *)&uparams + un->uparams_offs) = val;
00199 break;
00200 }
00201 if (! un->name)
00202 __argp_failure (state, 0, 0,
00203 dgettext (state->root_argp->argp_domain, "\
00204 %.*s: Unknown ARGP_HELP_FMT parameter"),
00205 (int) var_len, var);
00206
00207 var = arg;
00208 if (*var == ',')
00209 var++;
00210 }
00211 else if (*var)
00212 {
00213 __argp_failure (state, 0, 0,
00214 dgettext (state->root_argp->argp_domain,
00215 "Garbage in ARGP_HELP_FMT: %s"), var);
00216 break;
00217 }
00218 }
00219 }
00220
00221
00222
00223 #define ovisible(opt) (! ((opt)->flags & OPTION_HIDDEN))
00224
00225
00226 #define oalias(opt) ((opt)->flags & OPTION_ALIAS)
00227
00228
00229 #define odoc(opt) ((opt)->flags & OPTION_DOC)
00230
00231
00232 #define onotrans(opt) ((opt)->flags & OPTION_NO_TRANS)
00233
00234
00235 #define oend(opt) __option_is_end (opt)
00236
00237
00238 #define oshort(opt) __option_is_short (opt)
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305 static int
00306 find_char (char ch, char *beg, char *end)
00307 {
00308 while (beg < end)
00309 if (*beg == ch)
00310 return 1;
00311 else
00312 beg++;
00313 return 0;
00314 }
00315
00316 struct hol_cluster;
00317
00318 struct hol_entry
00319 {
00320
00321 const struct argp_option *opt;
00322
00323 unsigned num;
00324
00325
00326
00327
00328
00329
00330
00331 char *short_options;
00332
00333
00334
00335
00336 int group;
00337
00338
00339 struct hol_cluster *cluster;
00340
00341
00342 const struct argp *argp;
00343 };
00344
00345
00346 struct hol_cluster
00347 {
00348
00349 const char *header;
00350
00351
00352
00353
00354 int index;
00355
00356
00357
00358 int group;
00359
00360
00361
00362 struct hol_cluster *parent;
00363
00364
00365 const struct argp *argp;
00366
00367
00368 int depth;
00369
00370
00371
00372 struct hol_cluster *next;
00373 };
00374
00375
00376 struct hol
00377 {
00378
00379 struct hol_entry *entries;
00380
00381
00382 unsigned num_entries;
00383
00384
00385
00386 char *short_options;
00387
00388
00389 struct hol_cluster *clusters;
00390 };
00391
00392
00393
00394 static struct hol *
00395 make_hol (const struct argp *argp, struct hol_cluster *cluster)
00396 {
00397 char *so;
00398 const struct argp_option *o;
00399 const struct argp_option *opts = argp->options;
00400 struct hol_entry *entry;
00401 unsigned num_short_options = 0;
00402 struct hol *hol = malloc (sizeof (struct hol));
00403
00404 assert (hol);
00405
00406 hol->num_entries = 0;
00407 hol->clusters = 0;
00408
00409 if (opts)
00410 {
00411 int cur_group = 0;
00412
00413
00414 assert (! oalias (opts));
00415
00416
00417 for (o = opts; ! oend (o); o++)
00418 {
00419 if (! oalias (o))
00420 hol->num_entries++;
00421 if (oshort (o))
00422 num_short_options++;
00423 }
00424
00425 hol->entries = malloc (sizeof (struct hol_entry) * hol->num_entries);
00426 hol->short_options = malloc (num_short_options + 1);
00427
00428 assert (hol->entries && hol->short_options);
00429 if (SIZE_MAX <= UINT_MAX)
00430 assert (hol->num_entries <= SIZE_MAX / sizeof (struct hol_entry));
00431
00432
00433 so = hol->short_options;
00434 for (o = opts, entry = hol->entries; ! oend (o); entry++)
00435 {
00436 entry->opt = o;
00437 entry->num = 0;
00438 entry->short_options = so;
00439 entry->group = cur_group =
00440 o->group
00441 ? o->group
00442 : ((!o->name && !o->key)
00443 ? cur_group + 1
00444 : cur_group);
00445 entry->cluster = cluster;
00446 entry->argp = argp;
00447
00448 do
00449 {
00450 entry->num++;
00451 if (oshort (o) && ! find_char (o->key, hol->short_options, so))
00452
00453 *so++ = o->key;
00454 o++;
00455 }
00456 while (! oend (o) && oalias (o));
00457 }
00458 *so = '\0';
00459 }
00460
00461 return hol;
00462 }
00463
00464
00465
00466
00467 static struct hol_cluster *
00468 hol_add_cluster (struct hol *hol, int group, const char *header, int index,
00469 struct hol_cluster *parent, const struct argp *argp)
00470 {
00471 struct hol_cluster *cl = malloc (sizeof (struct hol_cluster));
00472 if (cl)
00473 {
00474 cl->group = group;
00475 cl->header = header;
00476
00477 cl->index = index;
00478 cl->parent = parent;
00479 cl->argp = argp;
00480 cl->depth = parent ? parent->depth + 1 : 0;
00481
00482 cl->next = hol->clusters;
00483 hol->clusters = cl;
00484 }
00485 return cl;
00486 }
00487
00488
00489 static void
00490 hol_free (struct hol *hol)
00491 {
00492 struct hol_cluster *cl = hol->clusters;
00493
00494 while (cl)
00495 {
00496 struct hol_cluster *next = cl->next;
00497 free (cl);
00498 cl = next;
00499 }
00500
00501 if (hol->num_entries > 0)
00502 {
00503 free (hol->entries);
00504 free (hol->short_options);
00505 }
00506
00507 free (hol);
00508 }
00509
00510 static int
00511 hol_entry_short_iterate (const struct hol_entry *entry,
00512 int (*func)(const struct argp_option *opt,
00513 const struct argp_option *real,
00514 const char *domain, void *cookie),
00515 const char *domain, void *cookie)
00516 {
00517 unsigned nopts;
00518 int val = 0;
00519 const struct argp_option *opt, *real = entry->opt;
00520 char *so = entry->short_options;
00521
00522 for (opt = real, nopts = entry->num; nopts > 0 && !val; opt++, nopts--)
00523 if (oshort (opt) && *so == opt->key)
00524 {
00525 if (!oalias (opt))
00526 real = opt;
00527 if (ovisible (opt))
00528 val = (*func)(opt, real, domain, cookie);
00529 so++;
00530 }
00531
00532 return val;
00533 }
00534
00535 static inline int
00536 __attribute__ ((always_inline))
00537 hol_entry_long_iterate (const struct hol_entry *entry,
00538 int (*func)(const struct argp_option *opt,
00539 const struct argp_option *real,
00540 const char *domain, void *cookie),
00541 const char *domain, void *cookie)
00542 {
00543 unsigned nopts;
00544 int val = 0;
00545 const struct argp_option *opt, *real = entry->opt;
00546
00547 for (opt = real, nopts = entry->num; nopts > 0 && !val; opt++, nopts--)
00548 if (opt->name)
00549 {
00550 if (!oalias (opt))
00551 real = opt;
00552 if (ovisible (opt))
00553 val = (*func)(opt, real, domain, cookie);
00554 }
00555
00556 return val;
00557 }
00558
00559
00560 static inline int
00561 until_short (const struct argp_option *opt, const struct argp_option *real,
00562 const char *domain, void *cookie)
00563 {
00564 return oshort (opt) ? opt->key : 0;
00565 }
00566
00567
00568 static char
00569 hol_entry_first_short (const struct hol_entry *entry)
00570 {
00571 return hol_entry_short_iterate (entry, until_short,
00572 entry->argp->argp_domain, 0);
00573 }
00574
00575
00576 static const char *
00577 hol_entry_first_long (const struct hol_entry *entry)
00578 {
00579 const struct argp_option *opt;
00580 unsigned num;
00581 for (opt = entry->opt, num = entry->num; num > 0; opt++, num--)
00582 if (opt->name && ovisible (opt))
00583 return opt->name;
00584 return 0;
00585 }
00586
00587
00588
00589 static struct hol_entry *
00590 hol_find_entry (struct hol *hol, const char *name)
00591 {
00592 struct hol_entry *entry = hol->entries;
00593 unsigned num_entries = hol->num_entries;
00594
00595 while (num_entries-- > 0)
00596 {
00597 const struct argp_option *opt = entry->opt;
00598 unsigned num_opts = entry->num;
00599
00600 while (num_opts-- > 0)
00601 if (opt->name && ovisible (opt) && strcmp (opt->name, name) == 0)
00602 return entry;
00603 else
00604 opt++;
00605
00606 entry++;
00607 }
00608
00609 return 0;
00610 }
00611
00612
00613
00614 static void
00615 hol_set_group (struct hol *hol, const char *name, int group)
00616 {
00617 struct hol_entry *entry = hol_find_entry (hol, name);
00618 if (entry)
00619 entry->group = group;
00620 }
00621
00622
00623
00624 static int
00625 group_cmp (int group1, int group2, int eq)
00626 {
00627 if (group1 == group2)
00628 return eq;
00629 else if ((group1 < 0 && group2 < 0) || (group1 >= 0 && group2 >= 0))
00630 return group1 - group2;
00631 else
00632 return group2 - group1;
00633 }
00634
00635
00636
00637 static int
00638 hol_cluster_cmp (const struct hol_cluster *cl1, const struct hol_cluster *cl2)
00639 {
00640
00641
00642 while (cl1->depth < cl2->depth)
00643 cl1 = cl1->parent;
00644 while (cl2->depth < cl1->depth)
00645 cl2 = cl2->parent;
00646
00647
00648
00649 while (cl1->parent != cl2->parent)
00650 cl1 = cl1->parent, cl2 = cl2->parent;
00651
00652 return group_cmp (cl1->group, cl2->group, cl2->index - cl1->index);
00653 }
00654
00655
00656
00657 static struct hol_cluster *
00658 hol_cluster_base (struct hol_cluster *cl)
00659 {
00660 while (cl->parent)
00661 cl = cl->parent;
00662 return cl;
00663 }
00664
00665
00666 static int
00667 hol_cluster_is_child (const struct hol_cluster *cl1,
00668 const struct hol_cluster *cl2)
00669 {
00670 while (cl1 && cl1 != cl2)
00671 cl1 = cl1->parent;
00672 return cl1 == cl2;
00673 }
00674
00675
00676
00677
00678 static int
00679 canon_doc_option (const char **name)
00680 {
00681 int non_opt;
00682
00683 if (!*name)
00684 non_opt = 1;
00685 else
00686 {
00687
00688 while (isspace (**name))
00689 (*name)++;
00690
00691 non_opt = (**name != '-');
00692
00693 while (**name && !isalnum (**name))
00694 (*name)++;
00695 }
00696 return non_opt;
00697 }
00698
00699
00700
00701 static int
00702 hol_entry_cmp (const struct hol_entry *entry1,
00703 const struct hol_entry *entry2)
00704 {
00705
00706
00707 int group1 = entry1->group, group2 = entry2->group;
00708
00709 if (entry1->cluster != entry2->cluster)
00710 {
00711
00712
00713 if (! entry1->cluster)
00714
00715
00716
00717
00718 return group_cmp (group1, hol_cluster_base (entry2->cluster)->group, -1);
00719 else if (! entry2->cluster)
00720
00721 return group_cmp (hol_cluster_base (entry1->cluster)->group, group2, 1);
00722 else
00723
00724 return hol_cluster_cmp (entry1->cluster, entry2->cluster);
00725 }
00726 else if (group1 == group2)
00727
00728
00729 {
00730 int short1 = hol_entry_first_short (entry1);
00731 int short2 = hol_entry_first_short (entry2);
00732 int doc1 = odoc (entry1->opt);
00733 int doc2 = odoc (entry2->opt);
00734 const char *long1 = hol_entry_first_long (entry1);
00735 const char *long2 = hol_entry_first_long (entry2);
00736
00737 if (doc1)
00738 doc1 = canon_doc_option (&long1);
00739 if (doc2)
00740 doc2 = canon_doc_option (&long2);
00741
00742 if (doc1 != doc2)
00743
00744
00745 return doc1 - doc2;
00746 else if (!short1 && !short2 && long1 && long2)
00747
00748 return __strcasecmp (long1, long2);
00749 else
00750
00751
00752
00753
00754
00755 {
00756 char first1 = short1 ? short1 : long1 ? *long1 : 0;
00757 char first2 = short2 ? short2 : long2 ? *long2 : 0;
00758 #ifdef _tolower
00759 int lower_cmp = _tolower (first1) - _tolower (first2);
00760 #else
00761 int lower_cmp = tolower (first1) - tolower (first2);
00762 #endif
00763
00764
00765 return lower_cmp ? lower_cmp : first2 - first1;
00766 }
00767 }
00768 else
00769
00770
00771 return group_cmp (group1, group2, 0);
00772 }
00773
00774
00775 static int
00776 hol_entry_qcmp (const void *entry1_v, const void *entry2_v)
00777 {
00778 return hol_entry_cmp (entry1_v, entry2_v);
00779 }
00780
00781
00782
00783
00784 static void
00785 hol_sort (struct hol *hol)
00786 {
00787 if (hol->num_entries > 0)
00788 qsort (hol->entries, hol->num_entries, sizeof (struct hol_entry),
00789 hol_entry_qcmp);
00790 }
00791
00792
00793
00794 static void
00795 hol_append (struct hol *hol, struct hol *more)
00796 {
00797 struct hol_cluster **cl_end = &hol->clusters;
00798
00799
00800 while (*cl_end)
00801 cl_end = &(*cl_end)->next;
00802 *cl_end = more->clusters;
00803 more->clusters = 0;
00804
00805
00806 if (more->num_entries > 0)
00807 {
00808 if (hol->num_entries == 0)
00809 {
00810 hol->num_entries = more->num_entries;
00811 hol->entries = more->entries;
00812 hol->short_options = more->short_options;
00813 more->num_entries = 0;
00814 }
00815 else
00816
00817
00818 {
00819 unsigned left;
00820 char *so, *more_so;
00821 struct hol_entry *e;
00822 unsigned num_entries = hol->num_entries + more->num_entries;
00823 struct hol_entry *entries =
00824 malloc (num_entries * sizeof (struct hol_entry));
00825 unsigned hol_so_len = strlen (hol->short_options);
00826 char *short_options =
00827 malloc (hol_so_len + strlen (more->short_options) + 1);
00828
00829 assert (entries && short_options);
00830 if (SIZE_MAX <= UINT_MAX)
00831 assert (num_entries <= SIZE_MAX / sizeof (struct hol_entry));
00832
00833 __mempcpy (__mempcpy (entries, hol->entries,
00834 hol->num_entries * sizeof (struct hol_entry)),
00835 more->entries,
00836 more->num_entries * sizeof (struct hol_entry));
00837
00838 __mempcpy (short_options, hol->short_options, hol_so_len);
00839
00840
00841 for (e = entries, left = hol->num_entries; left > 0; e++, left--)
00842 e->short_options += (short_options - hol->short_options);
00843
00844
00845
00846 so = short_options + hol_so_len;
00847 more_so = more->short_options;
00848 for (left = more->num_entries; left > 0; e++, left--)
00849 {
00850 int opts_left;
00851 const struct argp_option *opt;
00852
00853 e->short_options = so;
00854
00855 for (opts_left = e->num, opt = e->opt; opts_left; opt++, opts_left--)
00856 {
00857 int ch = *more_so;
00858 if (oshort (opt) && ch == opt->key)
00859
00860 {
00861 if (! find_char (ch, short_options,
00862 short_options + hol_so_len))
00863
00864
00865 *so++ = ch;
00866 more_so++;
00867 }
00868 }
00869 }
00870
00871 *so = '\0';
00872
00873 free (hol->entries);
00874 free (hol->short_options);
00875
00876 hol->entries = entries;
00877 hol->num_entries = num_entries;
00878 hol->short_options = short_options;
00879 }
00880 }
00881
00882 hol_free (more);
00883 }
00884
00885
00886 static void
00887 indent_to (argp_fmtstream_t stream, unsigned col)
00888 {
00889 int needed = col - __argp_fmtstream_point (stream);
00890 while (needed-- > 0)
00891 __argp_fmtstream_putc (stream, ' ');
00892 }
00893
00894
00895
00896 static void
00897 space (argp_fmtstream_t stream, size_t ensure)
00898 {
00899 if (__argp_fmtstream_point (stream) + ensure
00900 >= __argp_fmtstream_rmargin (stream))
00901 __argp_fmtstream_putc (stream, '\n');
00902 else
00903 __argp_fmtstream_putc (stream, ' ');
00904 }
00905
00906
00907
00908
00909 static void
00910 arg (const struct argp_option *real, const char *req_fmt, const char *opt_fmt,
00911 const char *domain, argp_fmtstream_t stream)
00912 {
00913 if (real->arg)
00914 {
00915 if (real->flags & OPTION_ARG_OPTIONAL)
00916 __argp_fmtstream_printf (stream, opt_fmt,
00917 dgettext (domain, real->arg));
00918 else
00919 __argp_fmtstream_printf (stream, req_fmt,
00920 dgettext (domain, real->arg));
00921 }
00922 }
00923
00924
00925
00926
00927 struct hol_help_state
00928 {
00929
00930 struct hol_entry *prev_entry;
00931
00932
00933
00934 int sep_groups;
00935
00936
00937
00938 int suppressed_dup_arg;
00939 };
00940
00941
00942
00943
00944 struct pentry_state
00945 {
00946 const struct hol_entry *entry;
00947 argp_fmtstream_t stream;
00948 struct hol_help_state *hhstate;
00949
00950
00951 int first;
00952
00953
00954 const struct argp_state *state;
00955 };
00956
00957
00958 static const char *
00959 filter_doc (const char *doc, int key, const struct argp *argp,
00960 const struct argp_state *state)
00961 {
00962 if (argp->help_filter)
00963
00964 {
00965 void *input = __argp_input (argp, state);
00966 return (*argp->help_filter) (key, doc, input);
00967 }
00968 else
00969
00970 return doc;
00971 }
00972
00973
00974
00975
00976
00977
00978 static void
00979 print_header (const char *str, const struct argp *argp,
00980 struct pentry_state *pest)
00981 {
00982 const char *tstr = dgettext (argp->argp_domain, str);
00983 const char *fstr = filter_doc (tstr, ARGP_KEY_HELP_HEADER, argp, pest->state);
00984
00985 if (fstr)
00986 {
00987 if (*fstr)
00988 {
00989 if (pest->hhstate->prev_entry)
00990
00991 __argp_fmtstream_putc (pest->stream, '\n');
00992 indent_to (pest->stream, uparams.header_col);
00993 __argp_fmtstream_set_lmargin (pest->stream, uparams.header_col);
00994 __argp_fmtstream_set_wmargin (pest->stream, uparams.header_col);
00995 __argp_fmtstream_puts (pest->stream, fstr);
00996 __argp_fmtstream_set_lmargin (pest->stream, 0);
00997 __argp_fmtstream_putc (pest->stream, '\n');
00998 }
00999
01000 pest->hhstate->sep_groups = 1;
01001 }
01002
01003 if (fstr != tstr)
01004 free ((char *) fstr);
01005 }
01006
01007
01008
01009
01010
01011 static void
01012 comma (unsigned col, struct pentry_state *pest)
01013 {
01014 if (pest->first)
01015 {
01016 const struct hol_entry *pe = pest->hhstate->prev_entry;
01017 const struct hol_cluster *cl = pest->entry->cluster;
01018
01019 if (pest->hhstate->sep_groups && pe && pest->entry->group != pe->group)
01020 __argp_fmtstream_putc (pest->stream, '\n');
01021
01022 if (cl && cl->header && *cl->header
01023 && (!pe
01024 || (pe->cluster != cl
01025 && !hol_cluster_is_child (pe->cluster, cl))))
01026
01027
01028
01029
01030 {
01031 int old_wm = __argp_fmtstream_wmargin (pest->stream);
01032 print_header (cl->header, cl->argp, pest);
01033 __argp_fmtstream_set_wmargin (pest->stream, old_wm);
01034 }
01035
01036 pest->first = 0;
01037 }
01038 else
01039 __argp_fmtstream_puts (pest->stream, ", ");
01040
01041 indent_to (pest->stream, col);
01042 }
01043
01044
01045 static void
01046 hol_entry_help (struct hol_entry *entry, const struct argp_state *state,
01047 argp_fmtstream_t stream, struct hol_help_state *hhstate)
01048 {
01049 unsigned num;
01050 const struct argp_option *real = entry->opt, *opt;
01051 char *so = entry->short_options;
01052 int have_long_opt = 0;
01053
01054 int old_lm = __argp_fmtstream_set_lmargin (stream, 0);
01055 int old_wm = __argp_fmtstream_wmargin (stream);
01056
01057
01058 struct pentry_state pest;
01059
01060 pest.entry = entry;
01061 pest.stream = stream;
01062 pest.hhstate = hhstate;
01063 pest.first = 1;
01064 pest.state = state;
01065
01066 if (! odoc (real))
01067 for (opt = real, num = entry->num; num > 0; opt++, num--)
01068 if (opt->name && ovisible (opt))
01069 {
01070 have_long_opt = 1;
01071 break;
01072 }
01073
01074
01075 __argp_fmtstream_set_wmargin (stream, uparams.short_opt_col);
01076 for (opt = real, num = entry->num; num > 0; opt++, num--)
01077 if (oshort (opt) && opt->key == *so)
01078
01079 {
01080 if (ovisible (opt))
01081 {
01082 comma (uparams.short_opt_col, &pest);
01083 __argp_fmtstream_putc (stream, '-');
01084 __argp_fmtstream_putc (stream, *so);
01085 if (!have_long_opt || uparams.dup_args)
01086 arg (real, " %s", "[%s]", state->root_argp->argp_domain, stream);
01087 else if (real->arg)
01088 hhstate->suppressed_dup_arg = 1;
01089 }
01090 so++;
01091 }
01092
01093
01094 if (odoc (real))
01095
01096 {
01097 __argp_fmtstream_set_wmargin (stream, uparams.doc_opt_col);
01098 for (opt = real, num = entry->num; num > 0; opt++, num--)
01099 if (opt->name && *opt->name && ovisible (opt))
01100 {
01101 comma (uparams.doc_opt_col, &pest);
01102
01103
01104
01105 __argp_fmtstream_puts (stream,
01106 onotrans (opt) ?
01107 opt->name :
01108 dgettext (state->root_argp->argp_domain,
01109 opt->name));
01110 }
01111 }
01112 else
01113
01114 {
01115 int first_long_opt = 1;
01116
01117 __argp_fmtstream_set_wmargin (stream, uparams.long_opt_col);
01118 for (opt = real, num = entry->num; num > 0; opt++, num--)
01119 if (opt->name && ovisible (opt))
01120 {
01121 comma (uparams.long_opt_col, &pest);
01122 __argp_fmtstream_printf (stream, "--%s", opt->name);
01123 if (first_long_opt || uparams.dup_args)
01124 arg (real, "=%s", "[=%s]", state->root_argp->argp_domain,
01125 stream);
01126 else if (real->arg)
01127 hhstate->suppressed_dup_arg = 1;
01128 }
01129 }
01130
01131
01132 __argp_fmtstream_set_lmargin (stream, 0);
01133
01134 if (pest.first)
01135 {
01136
01137 if (!oshort (real) && !real->name)
01138
01139 print_header (real->doc, entry->argp, &pest);
01140 else
01141
01142 goto cleanup;
01143 }
01144 else
01145 {
01146 const char *tstr = real->doc ? dgettext (state->root_argp->argp_domain,
01147 real->doc) : 0;
01148 const char *fstr = filter_doc (tstr, real->key, entry->argp, state);
01149 if (fstr && *fstr)
01150 {
01151 unsigned int col = __argp_fmtstream_point (stream);
01152
01153 __argp_fmtstream_set_lmargin (stream, uparams.opt_doc_col);
01154 __argp_fmtstream_set_wmargin (stream, uparams.opt_doc_col);
01155
01156 if (col > (unsigned int) (uparams.opt_doc_col + 3))
01157 __argp_fmtstream_putc (stream, '\n');
01158 else if (col >= (unsigned int) uparams.opt_doc_col)
01159 __argp_fmtstream_puts (stream, " ");
01160 else
01161 indent_to (stream, uparams.opt_doc_col);
01162
01163 __argp_fmtstream_puts (stream, fstr);
01164 }
01165 if (fstr && fstr != tstr)
01166 free ((char *) fstr);
01167
01168
01169 __argp_fmtstream_set_lmargin (stream, 0);
01170 __argp_fmtstream_putc (stream, '\n');
01171 }
01172
01173 hhstate->prev_entry = entry;
01174
01175 cleanup:
01176 __argp_fmtstream_set_lmargin (stream, old_lm);
01177 __argp_fmtstream_set_wmargin (stream, old_wm);
01178 }
01179
01180
01181 static void
01182 hol_help (struct hol *hol, const struct argp_state *state,
01183 argp_fmtstream_t stream)
01184 {
01185 unsigned num;
01186 struct hol_entry *entry;
01187 struct hol_help_state hhstate = { 0, 0, 0 };
01188
01189 for (entry = hol->entries, num = hol->num_entries; num > 0; entry++, num--)
01190 hol_entry_help (entry, state, stream, &hhstate);
01191
01192 if (hhstate.suppressed_dup_arg && uparams.dup_args_note)
01193 {
01194 const char *tstr = dgettext (state->root_argp->argp_domain, "\
01195 Mandatory or optional arguments to long options are also mandatory or \
01196 optional for any corresponding short options.");
01197 const char *fstr = filter_doc (tstr, ARGP_KEY_HELP_DUP_ARGS_NOTE,
01198 state ? state->root_argp : 0, state);
01199 if (fstr && *fstr)
01200 {
01201 __argp_fmtstream_putc (stream, '\n');
01202 __argp_fmtstream_puts (stream, fstr);
01203 __argp_fmtstream_putc (stream, '\n');
01204 }
01205 if (fstr && fstr != tstr)
01206 free ((char *) fstr);
01207 }
01208 }
01209
01210
01211
01212
01213
01214 static int
01215 add_argless_short_opt (const struct argp_option *opt,
01216 const struct argp_option *real,
01217 const char *domain, void *cookie)
01218 {
01219 char **snao_end = cookie;
01220 if (!(opt->arg || real->arg)
01221 && !((opt->flags | real->flags) & OPTION_NO_USAGE))
01222 *(*snao_end)++ = opt->key;
01223 return 0;
01224 }
01225
01226
01227
01228 static int
01229 usage_argful_short_opt (const struct argp_option *opt,
01230 const struct argp_option *real,
01231 const char *domain, void *cookie)
01232 {
01233 argp_fmtstream_t stream = cookie;
01234 const char *arg = opt->arg;
01235 int flags = opt->flags | real->flags;
01236
01237 if (! arg)
01238 arg = real->arg;
01239
01240 if (arg && !(flags & OPTION_NO_USAGE))
01241 {
01242 arg = dgettext (domain, arg);
01243
01244 if (flags & OPTION_ARG_OPTIONAL)
01245 __argp_fmtstream_printf (stream, " [-%c[%s]]", opt->key, arg);
01246 else
01247 {
01248
01249
01250 space (stream, 6 + strlen (arg));
01251 __argp_fmtstream_printf (stream, "[-%c %s]", opt->key, arg);
01252 }
01253 }
01254
01255 return 0;
01256 }
01257
01258
01259
01260 static int
01261 usage_long_opt (const struct argp_option *opt,
01262 const struct argp_option *real,
01263 const char *domain, void *cookie)
01264 {
01265 argp_fmtstream_t stream = cookie;
01266 const char *arg = opt->arg;
01267 int flags = opt->flags | real->flags;
01268
01269 if (! arg)
01270 arg = real->arg;
01271
01272 if (! (flags & OPTION_NO_USAGE))
01273 {
01274 if (arg)
01275 {
01276 arg = dgettext (domain, arg);
01277 if (flags & OPTION_ARG_OPTIONAL)
01278 __argp_fmtstream_printf (stream, " [--%s[=%s]]", opt->name, arg);
01279 else
01280 __argp_fmtstream_printf (stream, " [--%s=%s]", opt->name, arg);
01281 }
01282 else
01283 __argp_fmtstream_printf (stream, " [--%s]", opt->name);
01284 }
01285
01286 return 0;
01287 }
01288
01289
01290 static void
01291 hol_usage (struct hol *hol, argp_fmtstream_t stream)
01292 {
01293 if (hol->num_entries > 0)
01294 {
01295 unsigned nentries;
01296 struct hol_entry *entry;
01297 char *short_no_arg_opts = alloca (strlen (hol->short_options) + 1);
01298 char *snao_end = short_no_arg_opts;
01299
01300
01301 for (entry = hol->entries, nentries = hol->num_entries
01302 ; nentries > 0
01303 ; entry++, nentries--)
01304 hol_entry_short_iterate (entry, add_argless_short_opt,
01305 entry->argp->argp_domain, &snao_end);
01306 if (snao_end > short_no_arg_opts)
01307 {
01308 *snao_end++ = 0;
01309 __argp_fmtstream_printf (stream, " [-%s]", short_no_arg_opts);
01310 }
01311
01312
01313 for (entry = hol->entries, nentries = hol->num_entries
01314 ; nentries > 0
01315 ; entry++, nentries--)
01316 hol_entry_short_iterate (entry, usage_argful_short_opt,
01317 entry->argp->argp_domain, stream);
01318
01319
01320 for (entry = hol->entries, nentries = hol->num_entries
01321 ; nentries > 0
01322 ; entry++, nentries--)
01323 hol_entry_long_iterate (entry, usage_long_opt,
01324 entry->argp->argp_domain, stream);
01325 }
01326 }
01327
01328
01329
01330 static struct hol *
01331 argp_hol (const struct argp *argp, struct hol_cluster *cluster)
01332 {
01333 const struct argp_child *child = argp->children;
01334 struct hol *hol = make_hol (argp, cluster);
01335 if (child)
01336 while (child->argp)
01337 {
01338 struct hol_cluster *child_cluster =
01339 ((child->group || child->header)
01340
01341 ? hol_add_cluster (hol, child->group, child->header,
01342 child - argp->children, cluster, argp)
01343
01344 : cluster);
01345 hol_append (hol, argp_hol (child->argp, child_cluster)) ;
01346 child++;
01347 }
01348 return hol;
01349 }
01350
01351
01352
01353 static size_t
01354 argp_args_levels (const struct argp *argp)
01355 {
01356 size_t levels = 0;
01357 const struct argp_child *child = argp->children;
01358
01359 if (argp->args_doc && strchr (argp->args_doc, '\n'))
01360 levels++;
01361
01362 if (child)
01363 while (child->argp)
01364 levels += argp_args_levels ((child++)->argp);
01365
01366 return levels;
01367 }
01368
01369
01370
01371
01372
01373
01374 static int
01375 argp_args_usage (const struct argp *argp, const struct argp_state *state,
01376 char **levels, int advance, argp_fmtstream_t stream)
01377 {
01378 char *our_level = *levels;
01379 int multiple = 0;
01380 const struct argp_child *child = argp->children;
01381 const char *tdoc = dgettext (argp->argp_domain, argp->args_doc), *nl = 0;
01382 const char *fdoc = filter_doc (tdoc, ARGP_KEY_HELP_ARGS_DOC, argp, state);
01383
01384 if (fdoc)
01385 {
01386 const char *cp = fdoc;
01387 nl = __strchrnul (cp, '\n');
01388 if (*nl != '\0')
01389
01390
01391 {
01392 int i;
01393 multiple = 1;
01394 for (i = 0; i < *our_level; i++)
01395 cp = nl + 1, nl = __strchrnul (cp, '\n');
01396 (*levels)++;
01397 }
01398
01399
01400
01401 space (stream, 1 + nl - cp);
01402
01403 __argp_fmtstream_write (stream, cp, nl - cp);
01404 }
01405 if (fdoc && fdoc != tdoc)
01406 free ((char *)fdoc);
01407
01408 if (child)
01409 while (child->argp)
01410 advance = !argp_args_usage ((child++)->argp, state, levels, advance, stream);
01411
01412 if (advance && multiple)
01413 {
01414
01415 if (*nl)
01416
01417 {
01418 (*our_level)++;
01419 advance = 0;
01420 }
01421 else if (*our_level > 0)
01422
01423 *our_level = 0;
01424 }
01425
01426 return !advance;
01427 }
01428
01429
01430
01431
01432
01433
01434
01435
01436 static int
01437 argp_doc (const struct argp *argp, const struct argp_state *state,
01438 int post, int pre_blank, int first_only,
01439 argp_fmtstream_t stream)
01440 {
01441 const char *text;
01442 const char *inp_text;
01443 void *input = 0;
01444 int anything = 0;
01445 size_t inp_text_limit = 0;
01446 const char *doc = dgettext (argp->argp_domain, argp->doc);
01447 const struct argp_child *child = argp->children;
01448
01449 if (doc)
01450 {
01451 char *vt = strchr (doc, '\v');
01452 inp_text = post ? (vt ? vt + 1 : 0) : doc;
01453 inp_text_limit = (!post && vt) ? (vt - doc) : 0;
01454 }
01455 else
01456 inp_text = 0;
01457
01458 if (argp->help_filter)
01459
01460 {
01461 if (inp_text_limit)
01462
01463 inp_text = __strndup (inp_text, inp_text_limit);
01464 input = __argp_input (argp, state);
01465 text =
01466 (*argp->help_filter) (post
01467 ? ARGP_KEY_HELP_POST_DOC
01468 : ARGP_KEY_HELP_PRE_DOC,
01469 inp_text, input);
01470 }
01471 else
01472 text = (const char *) inp_text;
01473
01474 if (text)
01475 {
01476 if (pre_blank)
01477 __argp_fmtstream_putc (stream, '\n');
01478
01479 if (text == inp_text && inp_text_limit)
01480 __argp_fmtstream_write (stream, inp_text, inp_text_limit);
01481 else
01482 __argp_fmtstream_puts (stream, text);
01483
01484 if (__argp_fmtstream_point (stream) > __argp_fmtstream_lmargin (stream))
01485 __argp_fmtstream_putc (stream, '\n');
01486
01487 anything = 1;
01488 }
01489
01490 if (text && text != inp_text)
01491 free ((char *) text);
01492 if (inp_text && inp_text_limit && argp->help_filter)
01493 free ((char *) inp_text);
01494
01495 if (post && argp->help_filter)
01496
01497 {
01498 text = (*argp->help_filter) (ARGP_KEY_HELP_EXTRA, 0, input);
01499 if (text)
01500 {
01501 if (anything || pre_blank)
01502 __argp_fmtstream_putc (stream, '\n');
01503 __argp_fmtstream_puts (stream, text);
01504 free ((char *) text);
01505 if (__argp_fmtstream_point (stream)
01506 > __argp_fmtstream_lmargin (stream))
01507 __argp_fmtstream_putc (stream, '\n');
01508 anything = 1;
01509 }
01510 }
01511
01512 if (child)
01513 while (child->argp && !(first_only && anything))
01514 anything |=
01515 argp_doc ((child++)->argp, state,
01516 post, anything || pre_blank, first_only,
01517 stream);
01518
01519 return anything;
01520 }
01521
01522
01523
01524
01525
01526 static void
01527 _help (const struct argp *argp, const struct argp_state *state, FILE *stream,
01528 unsigned flags, char *name)
01529 {
01530 int anything = 0;
01531 struct hol *hol = 0;
01532 argp_fmtstream_t fs;
01533
01534 if (! stream)
01535 return;
01536
01537 #if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE)
01538 __flockfile (stream);
01539 #endif
01540
01541 if (! uparams.valid)
01542 fill_in_uparams (state);
01543
01544 fs = __argp_make_fmtstream (stream, 0, uparams.rmargin, 0);
01545 if (! fs)
01546 {
01547 #if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE)
01548 __funlockfile (stream);
01549 #endif
01550 return;
01551 }
01552
01553 if (flags & (ARGP_HELP_USAGE | ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG))
01554 {
01555 hol = argp_hol (argp, 0);
01556
01557
01558 hol_set_group (hol, "help", -1);
01559 hol_set_group (hol, "version", -1);
01560
01561 hol_sort (hol);
01562 }
01563
01564 if (flags & (ARGP_HELP_USAGE | ARGP_HELP_SHORT_USAGE))
01565
01566 {
01567 int first_pattern = 1, more_patterns;
01568 size_t num_pattern_levels = argp_args_levels (argp);
01569 char *pattern_levels = alloca (num_pattern_levels);
01570
01571 memset (pattern_levels, 0, num_pattern_levels);
01572
01573 do
01574 {
01575 int old_lm;
01576 int old_wm = __argp_fmtstream_set_wmargin (fs, uparams.usage_indent);
01577 char *levels = pattern_levels;
01578
01579 if (first_pattern)
01580 __argp_fmtstream_printf (fs, "%s %s",
01581 dgettext (argp->argp_domain, "Usage:"),
01582 name);
01583 else
01584 __argp_fmtstream_printf (fs, "%s %s",
01585 dgettext (argp->argp_domain, " or: "),
01586 name);
01587
01588
01589
01590 old_lm = __argp_fmtstream_set_lmargin (fs, uparams.usage_indent);
01591
01592 if (flags & ARGP_HELP_SHORT_USAGE)
01593
01594 {
01595 if (hol->num_entries > 0)
01596 __argp_fmtstream_puts (fs, dgettext (argp->argp_domain,
01597 " [OPTION...]"));
01598 }
01599 else
01600
01601 {
01602 hol_usage (hol, fs);
01603 flags |= ARGP_HELP_SHORT_USAGE;
01604 }
01605
01606 more_patterns = argp_args_usage (argp, state, &levels, 1, fs);
01607
01608 __argp_fmtstream_set_wmargin (fs, old_wm);
01609 __argp_fmtstream_set_lmargin (fs, old_lm);
01610
01611 __argp_fmtstream_putc (fs, '\n');
01612 anything = 1;
01613
01614 first_pattern = 0;
01615 }
01616 while (more_patterns);
01617 }
01618
01619 if (flags & ARGP_HELP_PRE_DOC)
01620 anything |= argp_doc (argp, state, 0, 0, 1, fs);
01621
01622 if (flags & ARGP_HELP_SEE)
01623 {
01624 __argp_fmtstream_printf (fs, dgettext (argp->argp_domain, "\
01625 Try `%s --help' or `%s --usage' for more information.\n"),
01626 name, name);
01627 anything = 1;
01628 }
01629
01630 if (flags & ARGP_HELP_LONG)
01631
01632 {
01633
01634 if (hol->num_entries > 0)
01635 {
01636 if (anything)
01637 __argp_fmtstream_putc (fs, '\n');
01638 hol_help (hol, state, fs);
01639 anything = 1;
01640 }
01641 }
01642
01643 if (flags & ARGP_HELP_POST_DOC)
01644
01645 anything |= argp_doc (argp, state, 1, anything, 0, fs);
01646
01647 if ((flags & ARGP_HELP_BUG_ADDR) && argp_program_bug_address)
01648 {
01649 if (anything)
01650 __argp_fmtstream_putc (fs, '\n');
01651 __argp_fmtstream_printf (fs, dgettext (argp->argp_domain,
01652 "Report bugs to %s.\n"),
01653 argp_program_bug_address);
01654 anything = 1;
01655 }
01656
01657 #if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE)
01658 __funlockfile (stream);
01659 #endif
01660
01661 if (hol)
01662 hol_free (hol);
01663
01664 __argp_fmtstream_free (fs);
01665 }
01666
01667
01668
01669 void __argp_help (const struct argp *argp, FILE *stream,
01670 unsigned flags, char *name)
01671 {
01672 struct argp_state state;
01673 memset (&state, 0, sizeof state);
01674 state.root_argp = argp;
01675 _help (argp, &state, stream, flags, name);
01676 }
01677 #ifdef weak_alias
01678 weak_alias (__argp_help, argp_help)
01679 #endif
01680
01681 #if ! (defined _LIBC || HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME)
01682 char *
01683 __argp_short_program_name (void)
01684 {
01685 # if HAVE_DECL_PROGRAM_INVOCATION_NAME
01686 char *name = strrchr (program_invocation_name, '/');
01687 return name ? name + 1 : program_invocation_name;
01688 # else
01689
01690
01691
01692 # if __GNUC__
01693 # warning No reasonable value to return
01694 # endif
01695 return "";
01696 # endif
01697 }
01698 #endif
01699
01700
01701
01702 void
01703 __argp_state_help (const struct argp_state *state, FILE *stream, unsigned flags)
01704 {
01705 if ((!state || ! (state->flags & ARGP_NO_ERRS)) && stream)
01706 {
01707 if (state && (state->flags & ARGP_LONG_ONLY))
01708 flags |= ARGP_HELP_LONG_ONLY;
01709
01710 _help (state ? state->root_argp : 0, state, stream, flags,
01711 state ? state->name : __argp_short_program_name ());
01712
01713 if (!state || ! (state->flags & ARGP_NO_EXIT))
01714 {
01715 if (flags & ARGP_HELP_EXIT_ERR)
01716 exit (argp_err_exit_status);
01717 if (flags & ARGP_HELP_EXIT_OK)
01718 exit (0);
01719 }
01720 }
01721 }
01722 #ifdef weak_alias
01723 weak_alias (__argp_state_help, argp_state_help)
01724 #endif
01725
01726
01727
01728
01729 void
01730 __argp_error (const struct argp_state *state, const char *fmt, ...)
01731 {
01732 if (!state || !(state->flags & ARGP_NO_ERRS))
01733 {
01734 FILE *stream = state ? state->err_stream : stderr;
01735
01736 if (stream)
01737 {
01738 va_list ap;
01739
01740 #if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE)
01741 __flockfile (stream);
01742 #endif
01743
01744 va_start (ap, fmt);
01745
01746 #ifdef USE_IN_LIBIO
01747 if (_IO_fwide (stream, 0) > 0)
01748 {
01749 char *buf;
01750
01751 if (__asprintf (&buf, fmt, ap) < 0)
01752 buf = NULL;
01753
01754 __fwprintf (stream, L"%s: %s\n",
01755 state ? state->name : __argp_short_program_name (),
01756 buf);
01757
01758 free (buf);
01759 }
01760 else
01761 #endif
01762 {
01763 fputs_unlocked (state
01764 ? state->name : __argp_short_program_name (),
01765 stream);
01766 putc_unlocked (':', stream);
01767 putc_unlocked (' ', stream);
01768
01769 vfprintf (stream, fmt, ap);
01770
01771 putc_unlocked ('\n', stream);
01772 }
01773
01774 __argp_state_help (state, stream, ARGP_HELP_STD_ERR);
01775
01776 va_end (ap);
01777
01778 #if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE)
01779 __funlockfile (stream);
01780 #endif
01781 }
01782 }
01783 }
01784 #ifdef weak_alias
01785 weak_alias (__argp_error, argp_error)
01786 #endif
01787
01788
01789
01790
01791
01792
01793
01794
01795
01796 void
01797 __argp_failure (const struct argp_state *state, int status, int errnum,
01798 const char *fmt, ...)
01799 {
01800 if (!state || !(state->flags & ARGP_NO_ERRS))
01801 {
01802 FILE *stream = state ? state->err_stream : stderr;
01803
01804 if (stream)
01805 {
01806 #if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE)
01807 __flockfile (stream);
01808 #endif
01809
01810 #ifdef USE_IN_LIBIO
01811 if (_IO_fwide (stream, 0) > 0)
01812 __fwprintf (stream, L"%s",
01813 state ? state->name : __argp_short_program_name ());
01814 else
01815 #endif
01816 fputs_unlocked (state
01817 ? state->name : __argp_short_program_name (),
01818 stream);
01819
01820 if (fmt)
01821 {
01822 va_list ap;
01823
01824 va_start (ap, fmt);
01825 #ifdef USE_IN_LIBIO
01826 if (_IO_fwide (stream, 0) > 0)
01827 {
01828 char *buf;
01829
01830 if (__asprintf (&buf, fmt, ap) < 0)
01831 buf = NULL;
01832
01833 __fwprintf (stream, L": %s", buf);
01834
01835 free (buf);
01836 }
01837 else
01838 #endif
01839 {
01840 putc_unlocked (':', stream);
01841 putc_unlocked (' ', stream);
01842
01843 vfprintf (stream, fmt, ap);
01844 }
01845
01846 va_end (ap);
01847 }
01848
01849 if (errnum)
01850 {
01851 char buf[200];
01852
01853 #ifdef USE_IN_LIBIO
01854 if (_IO_fwide (stream, 0) > 0)
01855 __fwprintf (stream, L": %s",
01856 __strerror_r (errnum, buf, sizeof (buf)));
01857 else
01858 #endif
01859 {
01860 char const *s = NULL;
01861 putc_unlocked (':', stream);
01862 putc_unlocked (' ', stream);
01863 #if _LIBC || (HAVE_DECL_STRERROR_R && STRERROR_R_CHAR_P)
01864 s = __strerror_r (errnum, buf, sizeof buf);
01865 #elif HAVE_DECL_STRERROR_R
01866 if (__strerror_r (errnum, buf, sizeof buf) == 0)
01867 s = buf;
01868 #endif
01869 #if !_LIBC
01870 if (! s && ! (s = strerror (errnum)))
01871 s = dgettext (state->root_argp->argp_domain,
01872 "Unknown system error");
01873 #endif
01874 fputs (s, stream);
01875 }
01876 }
01877
01878 #ifdef USE_IN_LIBIO
01879 if (_IO_fwide (stream, 0) > 0)
01880 putwc_unlocked (L'\n', stream);
01881 else
01882 #endif
01883 putc_unlocked ('\n', stream);
01884
01885 #if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE)
01886 __funlockfile (stream);
01887 #endif
01888
01889 if (status && (!state || !(state->flags & ARGP_NO_EXIT)))
01890 exit (status);
01891 }
01892 }
01893 }
01894 #ifdef weak_alias
01895 weak_alias (__argp_failure, argp_failure)
01896 #endif