WvStreams
|
00001 /* Hierarchial argument parsing help output 00002 Copyright (C) 1995,96,97,98,99,2000, 2003 Free Software Foundation, Inc. 00003 This file is part of the GNU C Library. 00004 Written by Miles Bader <miles@gnu.ai.mit.edu>. 00005 00006 The GNU C Library is free software; you can redistribute it and/or 00007 modify it under the terms of the GNU Library General Public License as 00008 published by the Free Software Foundation; either version 2 of the 00009 License, or (at your option) any later version. 00010 00011 The GNU C Library is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 Library General Public License for more details. 00015 00016 You should have received a copy of the GNU Library General Public 00017 License along with the GNU C Library; see the file COPYING.LIB. If not, 00018 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00019 Boston, MA 02111-1307, USA. */ 00020 00021 #ifndef _GNU_SOURCE 00022 # define _GNU_SOURCE 1 00023 #endif 00024 00025 #ifdef HAVE_CONFIG_H 00026 #include <config.h> 00027 #endif 00028 00029 /* AIX requires this to be the first thing in the file. */ 00030 #ifndef __GNUC__ 00031 # if HAVE_ALLOCA_H 00032 # include <alloca.h> 00033 # else 00034 # ifdef _AIX 00035 #pragma alloca 00036 # else 00037 # ifndef alloca /* predefined by HP cc +Olibcalls */ 00038 char *alloca (); 00039 # endif 00040 # endif 00041 # endif 00042 #endif 00043 00044 #include <stddef.h> 00045 #include <stdlib.h> 00046 #include <string.h> 00047 #include <assert.h> 00048 #include <stdarg.h> 00049 #include <ctype.h> 00050 /* Does any system still need malloc.h? If so, we'd need a configure 00051 test. */ 00052 #ifdef _WIN32 00053 #include <malloc.h> 00054 #endif 00055 00056 #ifndef _ 00057 /* This is for other GNU distributions with internationalized messages. */ 00058 # if defined HAVE_LIBINTL_H || defined _LIBC 00059 # include <libintl.h> 00060 # ifdef _LIBC 00061 # undef dgettext 00062 # define dgettext(domain, msgid) __dcgettext (domain, msgid, LC_MESSAGES) 00063 # endif 00064 # else 00065 # define dgettext(domain, msgid) (msgid) 00066 # endif 00067 #endif 00068 00069 #include "argp.h" 00070 #include "argp-fmtstream.h" 00071 #include "argp-namefrob.h" 00072 00073 00074 #ifndef _LIBC 00075 # ifndef __strchrnul 00076 # define __strchrnul strchrnul 00077 # endif 00078 # ifndef __mempcpy 00079 # define __mempcpy mempcpy 00080 # endif 00081 /* We need to use a different name, as __strndup is likely a macro. */ 00082 # define STRNDUP strndup 00083 # if HAVE_STRERROR 00084 # define STRERROR strerror 00085 # else 00086 # define STRERROR(x) (sys_errlist[x]) 00087 # endif 00088 #else /* _LIBC */ 00089 # define FLOCKFILE __flockfile 00090 # define FUNLOCKFILE __funlockfile 00091 # define STRNDUP __strndup 00092 # define STRERROR strerror 00093 #endif 00094 00095 #if !_LIBC 00096 # if !HAVE_STRNDUP 00097 char *strndup (const char *s, size_t size); 00098 # endif /* !HAVE_STRNDUP */ 00099 00100 # if !HAVE_MEMPCPY 00101 void *mempcpy (void *to, const void *from, size_t size); 00102 # endif /* !HAVE_MEMPCPY */ 00103 00104 # if !HAVE_STRCHRNUL 00105 char *strchrnul(const char *s, int c); 00106 # endif /* !HAVE_STRCHRNUL */ 00107 00108 #endif /* !_LIBC */ 00109 00110 00111 /* User-selectable (using an environment variable) formatting parameters. 00112 00113 These may be specified in an environment variable called `ARGP_HELP_FMT', 00114 with a contents like: VAR1=VAL1,VAR2=VAL2,BOOLVAR2,no-BOOLVAR2 00115 Where VALn must be a positive integer. The list of variables is in the 00116 UPARAM_NAMES vector, below. */ 00117 00118 /* Default parameters. */ 00119 #define DUP_ARGS 0 /* True if option argument can be duplicated. */ 00120 #define DUP_ARGS_NOTE 1 /* True to print a note about duplicate args. */ 00121 #define SHORT_OPT_COL 2 /* column in which short options start */ 00122 #define LONG_OPT_COL 6 /* column in which long options start */ 00123 #define DOC_OPT_COL 2 /* column in which doc options start */ 00124 #define OPT_DOC_COL 29 /* column in which option text starts */ 00125 #define HEADER_COL 1 /* column in which group headers are printed */ 00126 #define USAGE_INDENT 12 /* indentation of wrapped usage lines */ 00127 #define RMARGIN 79 /* right margin used for wrapping */ 00128 00129 /* User-selectable (using an environment variable) formatting parameters. 00130 They must all be of type `int' for the parsing code to work. */ 00131 struct uparams 00132 { 00133 /* If true, arguments for an option are shown with both short and long 00134 options, even when a given option has both, e.g. `-x ARG, --longx=ARG'. 00135 If false, then if an option has both, the argument is only shown with 00136 the long one, e.g., `-x, --longx=ARG', and a message indicating that 00137 this really means both is printed below the options. */ 00138 int dup_args; 00139 00140 /* This is true if when DUP_ARGS is false, and some duplicate arguments have 00141 been suppressed, an explanatory message should be printed. */ 00142 int dup_args_note; 00143 00144 /* Various output columns. */ 00145 int short_opt_col; 00146 int long_opt_col; 00147 int doc_opt_col; 00148 int opt_doc_col; 00149 int header_col; 00150 int usage_indent; 00151 int rmargin; 00152 00153 int valid; /* True when the values in here are valid. */ 00154 }; 00155 00156 /* This is a global variable, as user options are only ever read once. */ 00157 static struct uparams uparams = { 00158 DUP_ARGS, DUP_ARGS_NOTE, 00159 SHORT_OPT_COL, LONG_OPT_COL, DOC_OPT_COL, OPT_DOC_COL, HEADER_COL, 00160 USAGE_INDENT, RMARGIN, 00161 0 00162 }; 00163 00164 /* A particular uparam, and what the user name is. */ 00165 struct uparam_name 00166 { 00167 const char *name; /* User name. */ 00168 int is_bool; /* Whether it's `boolean'. */ 00169 size_t uparams_offs; /* Location of the (int) field in UPARAMS. */ 00170 }; 00171 00172 /* The name-field mappings we know about. */ 00173 static const struct uparam_name uparam_names[] = 00174 { 00175 { "dup-args", 1, offsetof (struct uparams, dup_args) }, 00176 { "dup-args-note", 1, offsetof (struct uparams, dup_args_note) }, 00177 { "short-opt-col", 0, offsetof (struct uparams, short_opt_col) }, 00178 { "long-opt-col", 0, offsetof (struct uparams, long_opt_col) }, 00179 { "doc-opt-col", 0, offsetof (struct uparams, doc_opt_col) }, 00180 { "opt-doc-col", 0, offsetof (struct uparams, opt_doc_col) }, 00181 { "header-col", 0, offsetof (struct uparams, header_col) }, 00182 { "usage-indent", 0, offsetof (struct uparams, usage_indent) }, 00183 { "rmargin", 0, offsetof (struct uparams, rmargin) }, 00184 { 0, 0, 0 } 00185 }; 00186 00187 /* Read user options from the environment, and fill in UPARAMS appropiately. */ 00188 static void 00189 fill_in_uparams (const struct argp_state *state) 00190 { 00191 /* FIXME: Can we get away without an explicit cast? */ 00192 const unsigned char *var = (unsigned char *) getenv ("ARGP_HELP_FMT"); 00193 00194 #define SKIPWS(p) do { while (isspace (*p)) p++; } while (0); 00195 00196 if (var) 00197 /* Parse var. */ 00198 while (*var) 00199 { 00200 SKIPWS (var); 00201 00202 if (isalpha (*var)) 00203 { 00204 size_t var_len; 00205 const struct uparam_name *un; 00206 int unspec = 0, val = 0; 00207 const unsigned char *arg = var; 00208 00209 while (isalnum (*arg) || *arg == '-' || *arg == '_') 00210 arg++; 00211 var_len = arg - var; 00212 00213 SKIPWS (arg); 00214 00215 if (*arg == '\0' || *arg == ',') 00216 unspec = 1; 00217 else if (*arg == '=') 00218 { 00219 arg++; 00220 SKIPWS (arg); 00221 } 00222 00223 if (unspec) 00224 { 00225 if (var[0] == 'n' && var[1] == 'o' && var[2] == '-') 00226 { 00227 val = 0; 00228 var += 3; 00229 var_len -= 3; 00230 } 00231 else 00232 val = 1; 00233 } 00234 else if (isdigit (*arg)) 00235 { 00236 val = atoi (arg); 00237 while (isdigit (*arg)) 00238 arg++; 00239 SKIPWS (arg); 00240 } 00241 00242 for (un = uparam_names; un->name; un++) 00243 if (strlen (un->name) == var_len 00244 && strncmp (var, un->name, var_len) == 0) 00245 { 00246 if (unspec && !un->is_bool) 00247 __argp_failure (state, 0, 0, 00248 dgettext (state->root_argp->argp_domain, "\ 00249 %.*s: ARGP_HELP_FMT parameter requires a value"), 00250 (int) var_len, var); 00251 else 00252 *(int *)((char *)&uparams + un->uparams_offs) = val; 00253 break; 00254 } 00255 if (! un->name) 00256 __argp_failure (state, 0, 0, 00257 dgettext (state->root_argp->argp_domain, "\ 00258 %.*s: Unknown ARGP_HELP_FMT parameter"), 00259 (int) var_len, var); 00260 00261 var = arg; 00262 if (*var == ',') 00263 var++; 00264 } 00265 else if (*var) 00266 { 00267 __argp_failure (state, 0, 0, 00268 dgettext (state->root_argp->argp_domain, 00269 "Garbage in ARGP_HELP_FMT: %s"), var); 00270 break; 00271 } 00272 } 00273 } 00274 00275 /* Returns true if OPT hasn't been marked invisible. Visibility only affects 00276 whether OPT is displayed or used in sorting, not option shadowing. */ 00277 #define ovisible(opt) (! ((opt)->flags & OPTION_HIDDEN)) 00278 00279 /* Returns true if OPT is an alias for an earlier option. */ 00280 #define oalias(opt) ((opt)->flags & OPTION_ALIAS) 00281 00282 /* Returns true if OPT is an documentation-only entry. */ 00283 #define odoc(opt) ((opt)->flags & OPTION_DOC) 00284 00285 /* Returns true if OPT is the end-of-list marker for a list of options. */ 00286 #define oend(opt) __option_is_end (opt) 00287 00288 /* Returns true if OPT has a short option. */ 00289 #define oshort(opt) __option_is_short (opt) 00290 00291 /* 00292 The help format for a particular option is like: 00293 00294 -xARG, -yARG, --long1=ARG, --long2=ARG Documentation... 00295 00296 Where ARG will be omitted if there's no argument, for this option, or 00297 will be surrounded by "[" and "]" appropiately if the argument is 00298 optional. The documentation string is word-wrapped appropiately, and if 00299 the list of options is long enough, it will be started on a separate line. 00300 If there are no short options for a given option, the first long option is 00301 indented slighly in a way that's supposed to make most long options appear 00302 to be in a separate column. 00303 00304 For example, the following output (from ps): 00305 00306 -p PID, --pid=PID List the process PID 00307 --pgrp=PGRP List processes in the process group PGRP 00308 -P, -x, --no-parent Include processes without parents 00309 -Q, --all-fields Don't elide unusable fields (normally if there's 00310 some reason ps can't print a field for any 00311 process, it's removed from the output entirely) 00312 -r, --reverse, --gratuitously-long-reverse-option 00313 Reverse the order of any sort 00314 --session[=SID] Add the processes from the session SID (which 00315 defaults to the sid of the current process) 00316 00317 Here are some more options: 00318 -f ZOT, --foonly=ZOT Glork a foonly 00319 -z, --zaza Snit a zar 00320 00321 -?, --help Give this help list 00322 --usage Give a short usage message 00323 -V, --version Print program version 00324 00325 The struct argp_option array for the above could look like: 00326 00327 { 00328 {"pid", 'p', "PID", 0, "List the process PID"}, 00329 {"pgrp", OPT_PGRP, "PGRP", 0, "List processes in the process group PGRP"}, 00330 {"no-parent", 'P', 0, 0, "Include processes without parents"}, 00331 {0, 'x', 0, OPTION_ALIAS}, 00332 {"all-fields",'Q', 0, 0, "Don't elide unusable fields (normally" 00333 " if there's some reason ps can't" 00334 " print a field for any process, it's" 00335 " removed from the output entirely)" }, 00336 {"reverse", 'r', 0, 0, "Reverse the order of any sort"}, 00337 {"gratuitously-long-reverse-option", 0, 0, OPTION_ALIAS}, 00338 {"session", OPT_SESS, "SID", OPTION_ARG_OPTIONAL, 00339 "Add the processes from the session" 00340 " SID (which defaults to the sid of" 00341 " the current process)" }, 00342 00343 {0,0,0,0, "Here are some more options:"}, 00344 {"foonly", 'f', "ZOT", 0, "Glork a foonly"}, 00345 {"zaza", 'z', 0, 0, "Snit a zar"}, 00346 00347 {0} 00348 } 00349 00350 Note that the last three options are automatically supplied by argp_parse, 00351 unless you tell it not to with ARGP_NO_HELP. 00352 00353 */ 00354 00355 /* Returns true if CH occurs between BEG and END. */ 00356 static int 00357 find_char (char ch, char *beg, char *end) 00358 { 00359 while (beg < end) 00360 if (*beg == ch) 00361 return 1; 00362 else 00363 beg++; 00364 return 0; 00365 } 00366 00367 struct hol_cluster; /* fwd decl */ 00368 00369 struct hol_entry 00370 { 00371 /* First option. */ 00372 const struct argp_option *opt; 00373 /* Number of options (including aliases). */ 00374 unsigned num; 00375 00376 /* A pointers into the HOL's short_options field, to the first short option 00377 letter for this entry. The order of the characters following this point 00378 corresponds to the order of options pointed to by OPT, and there are at 00379 most NUM. A short option recorded in a option following OPT is only 00380 valid if it occurs in the right place in SHORT_OPTIONS (otherwise it's 00381 probably been shadowed by some other entry). */ 00382 char *short_options; 00383 00384 /* Entries are sorted by their group first, in the order: 00385 1, 2, ..., n, 0, -m, ..., -2, -1 00386 and then alphabetically within each group. The default is 0. */ 00387 int group; 00388 00389 /* The cluster of options this entry belongs to, or 0 if none. */ 00390 struct hol_cluster *cluster; 00391 00392 /* The argp from which this option came. */ 00393 const struct argp *argp; 00394 }; 00395 00396 /* A cluster of entries to reflect the argp tree structure. */ 00397 struct hol_cluster 00398 { 00399 /* A descriptive header printed before options in this cluster. */ 00400 const char *header; 00401 00402 /* Used to order clusters within the same group with the same parent, 00403 according to the order in which they occurred in the parent argp's child 00404 list. */ 00405 int index; 00406 00407 /* How to sort this cluster with respect to options and other clusters at the 00408 same depth (clusters always follow options in the same group). */ 00409 int group; 00410 00411 /* The cluster to which this cluster belongs, or 0 if it's at the base 00412 level. */ 00413 struct hol_cluster *parent; 00414 00415 /* The argp from which this cluster is (eventually) derived. */ 00416 const struct argp *argp; 00417 00418 /* The distance this cluster is from the root. */ 00419 int depth; 00420 00421 /* Clusters in a given hol are kept in a linked list, to make freeing them 00422 possible. */ 00423 struct hol_cluster *next; 00424 }; 00425 00426 /* A list of options for help. */ 00427 struct hol 00428 { 00429 /* An array of hol_entry's. */ 00430 struct hol_entry *entries; 00431 /* The number of entries in this hol. If this field is zero, the others 00432 are undefined. */ 00433 unsigned num_entries; 00434 00435 /* A string containing all short options in this HOL. Each entry contains 00436 pointers into this string, so the order can't be messed with blindly. */ 00437 char *short_options; 00438 00439 /* Clusters of entries in this hol. */ 00440 struct hol_cluster *clusters; 00441 }; 00442 00443 /* Create a struct hol from the options in ARGP. CLUSTER is the 00444 hol_cluster in which these entries occur, or 0, if at the root. */ 00445 static struct hol * 00446 make_hol (const struct argp *argp, struct hol_cluster *cluster) 00447 { 00448 char *so; 00449 const struct argp_option *o; 00450 const struct argp_option *opts = argp->options; 00451 struct hol_entry *entry; 00452 unsigned num_short_options = 0; 00453 struct hol *hol = malloc (sizeof (struct hol)); 00454 00455 assert (hol); 00456 00457 hol->num_entries = 0; 00458 hol->clusters = 0; 00459 00460 if (opts) 00461 { 00462 int cur_group = 0; 00463 00464 /* The first option must not be an alias. */ 00465 assert (! oalias (opts)); 00466 00467 /* Calculate the space needed. */ 00468 for (o = opts; ! oend (o); o++) 00469 { 00470 if (! oalias (o)) 00471 hol->num_entries++; 00472 if (oshort (o)) 00473 num_short_options++; /* This is an upper bound. */ 00474 } 00475 00476 hol->entries = malloc (sizeof (struct hol_entry) * hol->num_entries); 00477 hol->short_options = malloc (num_short_options + 1); 00478 00479 assert (hol->entries && hol->short_options); 00480 00481 /* Fill in the entries. */ 00482 so = hol->short_options; 00483 for (o = opts, entry = hol->entries; ! oend (o); entry++) 00484 { 00485 entry->opt = o; 00486 entry->num = 0; 00487 entry->short_options = so; 00488 entry->group = cur_group = 00489 o->group 00490 ? o->group 00491 : ((!o->name && !o->key) 00492 ? cur_group + 1 00493 : cur_group); 00494 entry->cluster = cluster; 00495 entry->argp = argp; 00496 00497 do 00498 { 00499 entry->num++; 00500 if (oshort (o) && ! find_char (o->key, hol->short_options, so)) 00501 /* O has a valid short option which hasn't already been used.*/ 00502 *so++ = o->key; 00503 o++; 00504 } 00505 while (! oend (o) && oalias (o)); 00506 } 00507 *so = '\0'; /* null terminated so we can find the length */ 00508 } 00509 00510 return hol; 00511 } 00512 00513 /* Add a new cluster to HOL, with the given GROUP and HEADER (taken from the 00514 associated argp child list entry), INDEX, and PARENT, and return a pointer 00515 to it. ARGP is the argp that this cluster results from. */ 00516 static struct hol_cluster * 00517 hol_add_cluster (struct hol *hol, int group, const char *header, int index, 00518 struct hol_cluster *parent, const struct argp *argp) 00519 { 00520 struct hol_cluster *cl = malloc (sizeof (struct hol_cluster)); 00521 if (cl) 00522 { 00523 cl->group = group; 00524 cl->header = header; 00525 00526 cl->index = index; 00527 cl->parent = parent; 00528 cl->argp = argp; 00529 cl->depth = parent ? parent->depth + 1 : 0; 00530 00531 cl->next = hol->clusters; 00532 hol->clusters = cl; 00533 } 00534 return cl; 00535 } 00536 00537 /* Free HOL and any resources it uses. */ 00538 static void 00539 hol_free (struct hol *hol) 00540 { 00541 struct hol_cluster *cl = hol->clusters; 00542 00543 while (cl) 00544 { 00545 struct hol_cluster *next = cl->next; 00546 free (cl); 00547 cl = next; 00548 } 00549 00550 if (hol->num_entries > 0) 00551 { 00552 free (hol->entries); 00553 free (hol->short_options); 00554 } 00555 00556 free (hol); 00557 } 00558 00559 static inline int 00560 hol_entry_short_iterate (const struct hol_entry *entry, 00561 int (*func)(const struct argp_option *opt, 00562 const struct argp_option *real, 00563 const char *domain, void *cookie), 00564 const char *domain, void *cookie) 00565 { 00566 unsigned nopts; 00567 int val = 0; 00568 const struct argp_option *opt, *real = entry->opt; 00569 char *so = entry->short_options; 00570 00571 for (opt = real, nopts = entry->num; nopts > 0 && !val; opt++, nopts--) 00572 if (oshort (opt) && *so == opt->key) 00573 { 00574 if (!oalias (opt)) 00575 real = opt; 00576 if (ovisible (opt)) 00577 val = (*func)(opt, real, domain, cookie); 00578 so++; 00579 } 00580 00581 return val; 00582 } 00583 00584 static inline int 00585 hol_entry_long_iterate (const struct hol_entry *entry, 00586 int (*func)(const struct argp_option *opt, 00587 const struct argp_option *real, 00588 const char *domain, void *cookie), 00589 const char *domain, void *cookie) 00590 { 00591 unsigned nopts; 00592 int val = 0; 00593 const struct argp_option *opt, *real = entry->opt; 00594 00595 for (opt = real, nopts = entry->num; nopts > 0 && !val; opt++, nopts--) 00596 if (opt->name) 00597 { 00598 if (!oalias (opt)) 00599 real = opt; 00600 if (ovisible (opt)) 00601 val = (*func)(opt, real, domain, cookie); 00602 } 00603 00604 return val; 00605 } 00606 00607 /* Iterator that returns true for the first short option. */ 00608 static inline int 00609 until_short (const struct argp_option *opt, const struct argp_option *real UNUSED, 00610 const char *domain UNUSED, void *cookie UNUSED) 00611 { 00612 return oshort (opt) ? opt->key : 0; 00613 } 00614 00615 /* Returns the first valid short option in ENTRY, or 0 if there is none. */ 00616 static char 00617 hol_entry_first_short (const struct hol_entry *entry) 00618 { 00619 return hol_entry_short_iterate (entry, until_short, 00620 entry->argp->argp_domain, 0); 00621 } 00622 00623 /* Returns the first valid long option in ENTRY, or 0 if there is none. */ 00624 static const char * 00625 hol_entry_first_long (const struct hol_entry *entry) 00626 { 00627 const struct argp_option *opt; 00628 unsigned num; 00629 for (opt = entry->opt, num = entry->num; num > 0; opt++, num--) 00630 if (opt->name && ovisible (opt)) 00631 return opt->name; 00632 return 0; 00633 } 00634 00635 /* Returns the entry in HOL with the long option name NAME, or 0 if there is 00636 none. */ 00637 static struct hol_entry * 00638 hol_find_entry (struct hol *hol, const char *name) 00639 { 00640 struct hol_entry *entry = hol->entries; 00641 unsigned num_entries = hol->num_entries; 00642 00643 while (num_entries-- > 0) 00644 { 00645 const struct argp_option *opt = entry->opt; 00646 unsigned num_opts = entry->num; 00647 00648 while (num_opts-- > 0) 00649 if (opt->name && ovisible (opt) && strcmp (opt->name, name) == 0) 00650 return entry; 00651 else 00652 opt++; 00653 00654 entry++; 00655 } 00656 00657 return 0; 00658 } 00659 00660 /* If an entry with the long option NAME occurs in HOL, set it's special 00661 sort position to GROUP. */ 00662 static void 00663 hol_set_group (struct hol *hol, const char *name, int group) 00664 { 00665 struct hol_entry *entry = hol_find_entry (hol, name); 00666 if (entry) 00667 entry->group = group; 00668 } 00669 00670 /* Order by group: 0, 1, 2, ..., n, -m, ..., -2, -1. 00671 EQ is what to return if GROUP1 and GROUP2 are the same. */ 00672 static int 00673 group_cmp (int group1, int group2, int eq) 00674 { 00675 if (group1 == group2) 00676 return eq; 00677 else if ((group1 < 0 && group2 < 0) || (group1 >= 0 && group2 >= 0)) 00678 return group1 - group2; 00679 else 00680 return group2 - group1; 00681 } 00682 00683 /* Compare clusters CL1 & CL2 by the order that they should appear in 00684 output. */ 00685 static int 00686 hol_cluster_cmp (const struct hol_cluster *cl1, const struct hol_cluster *cl2) 00687 { 00688 /* If one cluster is deeper than the other, use its ancestor at the same 00689 level, so that finding the common ancestor is straightforward. */ 00690 while (cl1->depth < cl2->depth) 00691 cl1 = cl1->parent; 00692 while (cl2->depth < cl1->depth) 00693 cl2 = cl2->parent; 00694 00695 /* Now reduce both clusters to their ancestors at the point where both have 00696 a common parent; these can be directly compared. */ 00697 while (cl1->parent != cl2->parent) 00698 cl1 = cl1->parent, cl2 = cl2->parent; 00699 00700 return group_cmp (cl1->group, cl2->group, cl2->index - cl1->index); 00701 } 00702 00703 /* Return the ancestor of CL that's just below the root (i.e., has a parent 00704 of 0). */ 00705 static struct hol_cluster * 00706 hol_cluster_base (struct hol_cluster *cl) 00707 { 00708 while (cl->parent) 00709 cl = cl->parent; 00710 return cl; 00711 } 00712 00713 /* Return true if CL1 is a child of CL2. */ 00714 static int 00715 hol_cluster_is_child (const struct hol_cluster *cl1, 00716 const struct hol_cluster *cl2) 00717 { 00718 while (cl1 && cl1 != cl2) 00719 cl1 = cl1->parent; 00720 return cl1 == cl2; 00721 } 00722 00723 /* Given the name of a OPTION_DOC option, modifies NAME to start at the tail 00724 that should be used for comparisons, and returns true iff it should be 00725 treated as a non-option. */ 00726 00727 /* FIXME: Can we use unsigned char * for the argument? */ 00728 static int 00729 canon_doc_option (const char **name) 00730 { 00731 int non_opt; 00732 /* Skip initial whitespace. */ 00733 while (isspace ( (unsigned char) **name)) 00734 (*name)++; 00735 /* Decide whether this looks like an option (leading `-') or not. */ 00736 non_opt = (**name != '-'); 00737 /* Skip until part of name used for sorting. */ 00738 while (**name && !isalnum ( (unsigned char) **name)) 00739 (*name)++; 00740 return non_opt; 00741 } 00742 00743 /* Order ENTRY1 & ENTRY2 by the order which they should appear in a help 00744 listing. */ 00745 static int 00746 hol_entry_cmp (const struct hol_entry *entry1, 00747 const struct hol_entry *entry2) 00748 { 00749 /* The group numbers by which the entries should be ordered; if either is 00750 in a cluster, then this is just the group within the cluster. */ 00751 int group1 = entry1->group, group2 = entry2->group; 00752 00753 if (entry1->cluster != entry2->cluster) 00754 { 00755 /* The entries are not within the same cluster, so we can't compare them 00756 directly, we have to use the appropiate clustering level too. */ 00757 if (! entry1->cluster) 00758 /* ENTRY1 is at the `base level', not in a cluster, so we have to 00759 compare it's group number with that of the base cluster in which 00760 ENTRY2 resides. Note that if they're in the same group, the 00761 clustered option always comes laster. */ 00762 return group_cmp (group1, hol_cluster_base (entry2->cluster)->group, -1); 00763 else if (! entry2->cluster) 00764 /* Likewise, but ENTRY2's not in a cluster. */ 00765 return group_cmp (hol_cluster_base (entry1->cluster)->group, group2, 1); 00766 else 00767 /* Both entries are in clusters, we can just compare the clusters. */ 00768 return hol_cluster_cmp (entry1->cluster, entry2->cluster); 00769 } 00770 else if (group1 == group2) 00771 /* The entries are both in the same cluster and group, so compare them 00772 alphabetically. */ 00773 { 00774 int short1 = hol_entry_first_short (entry1); 00775 int short2 = hol_entry_first_short (entry2); 00776 int doc1 = odoc (entry1->opt); 00777 int doc2 = odoc (entry2->opt); 00778 /* FIXME: Can we use unsigned char * instead? */ 00779 const char *long1 = hol_entry_first_long (entry1); 00780 const char *long2 = hol_entry_first_long (entry2); 00781 00782 if (doc1) 00783 doc1 = canon_doc_option (&long1); 00784 if (doc2) 00785 doc2 = canon_doc_option (&long2); 00786 00787 if (doc1 != doc2) 00788 /* `documentation' options always follow normal options (or 00789 documentation options that *look* like normal options). */ 00790 return doc1 - doc2; 00791 else if (!short1 && !short2 && long1 && long2) 00792 /* Only long options. */ 00793 return __strcasecmp (long1, long2); 00794 else 00795 /* Compare short/short, long/short, short/long, using the first 00796 character of long options. Entries without *any* valid 00797 options (such as options with OPTION_HIDDEN set) will be put 00798 first, but as they're not displayed, it doesn't matter where 00799 they are. */ 00800 { 00801 unsigned char first1 = short1 ? short1 : long1 ? *long1 : 0; 00802 unsigned char first2 = short2 ? short2 : long2 ? *long2 : 0; 00803 #ifdef _tolower 00804 int lower_cmp = _tolower (first1) - _tolower (first2); 00805 #else 00806 int lower_cmp = tolower (first1) - tolower (first2); 00807 #endif 00808 /* Compare ignoring case, except when the options are both the 00809 same letter, in which case lower-case always comes first. */ 00810 /* NOTE: The subtraction below does the right thing 00811 even with eight-bit chars: first1 and first2 are 00812 converted to int *before* the subtraction. */ 00813 return lower_cmp ? lower_cmp : first2 - first1; 00814 } 00815 } 00816 else 00817 /* Within the same cluster, but not the same group, so just compare 00818 groups. */ 00819 return group_cmp (group1, group2, 0); 00820 } 00821 00822 /* Version of hol_entry_cmp with correct signature for qsort. */ 00823 static int 00824 hol_entry_qcmp (const void *entry1_v, const void *entry2_v) 00825 { 00826 return hol_entry_cmp (entry1_v, entry2_v); 00827 } 00828 00829 /* Sort HOL by group and alphabetically by option name (with short options 00830 taking precedence over long). Since the sorting is for display purposes 00831 only, the shadowing of options isn't effected. */ 00832 static void 00833 hol_sort (struct hol *hol) 00834 { 00835 if (hol->num_entries > 0) 00836 qsort (hol->entries, hol->num_entries, sizeof (struct hol_entry), 00837 hol_entry_qcmp); 00838 } 00839 00840 /* Append MORE to HOL, destroying MORE in the process. Options in HOL shadow 00841 any in MORE with the same name. */ 00842 static void 00843 hol_append (struct hol *hol, struct hol *more) 00844 { 00845 struct hol_cluster **cl_end = &hol->clusters; 00846 00847 /* Steal MORE's cluster list, and add it to the end of HOL's. */ 00848 while (*cl_end) 00849 cl_end = &(*cl_end)->next; 00850 *cl_end = more->clusters; 00851 more->clusters = 0; 00852 00853 /* Merge entries. */ 00854 if (more->num_entries > 0) 00855 { 00856 if (hol->num_entries == 0) 00857 { 00858 hol->num_entries = more->num_entries; 00859 hol->entries = more->entries; 00860 hol->short_options = more->short_options; 00861 more->num_entries = 0; /* Mark MORE's fields as invalid. */ 00862 } 00863 else 00864 /* Append the entries in MORE to those in HOL, taking care to only add 00865 non-shadowed SHORT_OPTIONS values. */ 00866 { 00867 unsigned left; 00868 char *so, *more_so; 00869 struct hol_entry *e; 00870 unsigned num_entries = hol->num_entries + more->num_entries; 00871 struct hol_entry *entries = 00872 malloc (num_entries * sizeof (struct hol_entry)); 00873 unsigned hol_so_len = strlen (hol->short_options); 00874 char *short_options = 00875 malloc (hol_so_len + strlen (more->short_options) + 1); 00876 00877 __mempcpy (__mempcpy (entries, hol->entries, 00878 hol->num_entries * sizeof (struct hol_entry)), 00879 more->entries, 00880 more->num_entries * sizeof (struct hol_entry)); 00881 00882 __mempcpy (short_options, hol->short_options, hol_so_len); 00883 00884 /* Fix up the short options pointers from HOL. */ 00885 for (e = entries, left = hol->num_entries; left > 0; e++, left--) 00886 e->short_options += (short_options - hol->short_options); 00887 00888 /* Now add the short options from MORE, fixing up its entries 00889 too. */ 00890 so = short_options + hol_so_len; 00891 more_so = more->short_options; 00892 for (left = more->num_entries; left > 0; e++, left--) 00893 { 00894 int opts_left; 00895 const struct argp_option *opt; 00896 00897 e->short_options = so; 00898 00899 for (opts_left = e->num, opt = e->opt; opts_left; opt++, opts_left--) 00900 { 00901 int ch = *more_so; 00902 if (oshort (opt) && ch == opt->key) 00903 /* The next short option in MORE_SO, CH, is from OPT. */ 00904 { 00905 if (! find_char (ch, short_options, 00906 short_options + hol_so_len)) 00907 /* The short option CH isn't shadowed by HOL's options, 00908 so add it to the sum. */ 00909 *so++ = ch; 00910 more_so++; 00911 } 00912 } 00913 } 00914 00915 *so = '\0'; 00916 00917 free (hol->entries); 00918 free (hol->short_options); 00919 00920 hol->entries = entries; 00921 hol->num_entries = num_entries; 00922 hol->short_options = short_options; 00923 } 00924 } 00925 00926 hol_free (more); 00927 } 00928 00929 /* Inserts enough spaces to make sure STREAM is at column COL. */ 00930 static void 00931 indent_to (argp_fmtstream_t stream, unsigned col) 00932 { 00933 int needed = col - __argp_fmtstream_point (stream); 00934 while (needed-- > 0) 00935 __argp_fmtstream_putc (stream, ' '); 00936 } 00937 00938 /* Output to STREAM either a space, or a newline if there isn't room for at 00939 least ENSURE characters before the right margin. */ 00940 static void 00941 space (argp_fmtstream_t stream, size_t ensure) 00942 { 00943 if (__argp_fmtstream_point (stream) + ensure 00944 >= __argp_fmtstream_rmargin (stream)) 00945 __argp_fmtstream_putc (stream, '\n'); 00946 else 00947 __argp_fmtstream_putc (stream, ' '); 00948 } 00949 00950 /* If the option REAL has an argument, we print it in using the printf 00951 format REQ_FMT or OPT_FMT depending on whether it's a required or 00952 optional argument. */ 00953 static void 00954 arg (const struct argp_option *real, const char *req_fmt, const char *opt_fmt, 00955 const char *domain UNUSED, argp_fmtstream_t stream) 00956 { 00957 if (real->arg) 00958 { 00959 if (real->flags & OPTION_ARG_OPTIONAL) 00960 __argp_fmtstream_printf (stream, opt_fmt, 00961 dgettext (domain, real->arg)); 00962 else 00963 __argp_fmtstream_printf (stream, req_fmt, 00964 dgettext (domain, real->arg)); 00965 } 00966 } 00967 00968 /* Helper functions for hol_entry_help. */ 00969 00970 /* State used during the execution of hol_help. */ 00971 struct hol_help_state 00972 { 00973 /* PREV_ENTRY should contain the previous entry printed, or 0. */ 00974 struct hol_entry *prev_entry; 00975 00976 /* If an entry is in a different group from the previous one, and SEP_GROUPS 00977 is true, then a blank line will be printed before any output. */ 00978 int sep_groups; 00979 00980 /* True if a duplicate option argument was suppressed (only ever set if 00981 UPARAMS.dup_args is false). */ 00982 int suppressed_dup_arg; 00983 }; 00984 00985 /* Some state used while printing a help entry (used to communicate with 00986 helper functions). See the doc for hol_entry_help for more info, as most 00987 of the fields are copied from its arguments. */ 00988 struct pentry_state 00989 { 00990 const struct hol_entry *entry; 00991 argp_fmtstream_t stream; 00992 struct hol_help_state *hhstate; 00993 00994 /* True if nothing's been printed so far. */ 00995 int first; 00996 00997 /* If non-zero, the state that was used to print this help. */ 00998 const struct argp_state *state; 00999 }; 01000 01001 /* If a user doc filter should be applied to DOC, do so. */ 01002 static const char * 01003 filter_doc (const char *doc, int key, const struct argp *argp, 01004 const struct argp_state *state) 01005 { 01006 if (argp->help_filter) 01007 /* We must apply a user filter to this output. */ 01008 { 01009 void *input = __argp_input (argp, state); 01010 return (*argp->help_filter) (key, doc, input); 01011 } 01012 else 01013 /* No filter. */ 01014 return doc; 01015 } 01016 01017 /* Prints STR as a header line, with the margin lines set appropiately, and 01018 notes the fact that groups should be separated with a blank line. ARGP is 01019 the argp that should dictate any user doc filtering to take place. Note 01020 that the previous wrap margin isn't restored, but the left margin is reset 01021 to 0. */ 01022 static void 01023 print_header (const char *str, const struct argp *argp, 01024 struct pentry_state *pest) 01025 { 01026 const char *tstr = dgettext (argp->argp_domain, str); 01027 const char *fstr = filter_doc (tstr, ARGP_KEY_HELP_HEADER, argp, pest->state); 01028 01029 if (fstr) 01030 { 01031 if (*fstr) 01032 { 01033 if (pest->hhstate->prev_entry) 01034 /* Precede with a blank line. */ 01035 __argp_fmtstream_putc (pest->stream, '\n'); 01036 indent_to (pest->stream, uparams.header_col); 01037 __argp_fmtstream_set_lmargin (pest->stream, uparams.header_col); 01038 __argp_fmtstream_set_wmargin (pest->stream, uparams.header_col); 01039 __argp_fmtstream_puts (pest->stream, fstr); 01040 __argp_fmtstream_set_lmargin (pest->stream, 0); 01041 __argp_fmtstream_putc (pest->stream, '\n'); 01042 } 01043 01044 pest->hhstate->sep_groups = 1; /* Separate subsequent groups. */ 01045 } 01046 01047 if (fstr != tstr) 01048 free ((char *) fstr); 01049 } 01050 01051 /* Inserts a comma if this isn't the first item on the line, and then makes 01052 sure we're at least to column COL. If this *is* the first item on a line, 01053 prints any pending whitespace/headers that should precede this line. Also 01054 clears FIRST. */ 01055 static void 01056 comma (unsigned col, struct pentry_state *pest) 01057 { 01058 if (pest->first) 01059 { 01060 const struct hol_entry *pe = pest->hhstate->prev_entry; 01061 const struct hol_cluster *cl = pest->entry->cluster; 01062 01063 if (pest->hhstate->sep_groups && pe && pest->entry->group != pe->group) 01064 __argp_fmtstream_putc (pest->stream, '\n'); 01065 01066 if (cl && cl->header && *cl->header 01067 && (!pe 01068 || (pe->cluster != cl 01069 && !hol_cluster_is_child (pe->cluster, cl)))) 01070 /* If we're changing clusters, then this must be the start of the 01071 ENTRY's cluster unless that is an ancestor of the previous one 01072 (in which case we had just popped into a sub-cluster for a bit). 01073 If so, then print the cluster's header line. */ 01074 { 01075 int old_wm = __argp_fmtstream_wmargin (pest->stream); 01076 print_header (cl->header, cl->argp, pest); 01077 __argp_fmtstream_set_wmargin (pest->stream, old_wm); 01078 } 01079 01080 pest->first = 0; 01081 } 01082 else 01083 __argp_fmtstream_puts (pest->stream, ", "); 01084 01085 indent_to (pest->stream, col); 01086 } 01087 01088 /* Print help for ENTRY to STREAM. */ 01089 static void 01090 hol_entry_help (struct hol_entry *entry, const struct argp_state *state, 01091 argp_fmtstream_t stream, struct hol_help_state *hhstate) 01092 { 01093 unsigned num; 01094 const struct argp_option *real = entry->opt, *opt; 01095 char *so = entry->short_options; 01096 int have_long_opt = 0; /* We have any long options. */ 01097 /* Saved margins. */ 01098 int old_lm = __argp_fmtstream_set_lmargin (stream, 0); 01099 int old_wm = __argp_fmtstream_wmargin (stream); 01100 /* PEST is a state block holding some of our variables that we'd like to 01101 share with helper functions. */ 01102 01103 /* Decent initializers are a GNU extension, so don't use it here. */ 01104 struct pentry_state pest; 01105 pest.entry = entry; 01106 pest.stream = stream; 01107 pest.hhstate = hhstate; 01108 pest.first = 1; 01109 pest.state = state; 01110 01111 if (! odoc (real)) 01112 for (opt = real, num = entry->num; num > 0; opt++, num--) 01113 if (opt->name && ovisible (opt)) 01114 { 01115 have_long_opt = 1; 01116 break; 01117 } 01118 01119 /* First emit short options. */ 01120 __argp_fmtstream_set_wmargin (stream, uparams.short_opt_col); /* For truly bizarre cases. */ 01121 for (opt = real, num = entry->num; num > 0; opt++, num--) 01122 if (oshort (opt) && opt->key == *so) 01123 /* OPT has a valid (non shadowed) short option. */ 01124 { 01125 if (ovisible (opt)) 01126 { 01127 comma (uparams.short_opt_col, &pest); 01128 __argp_fmtstream_putc (stream, '-'); 01129 __argp_fmtstream_putc (stream, *so); 01130 if (!have_long_opt || uparams.dup_args) 01131 arg (real, " %s", "[%s]", state->root_argp->argp_domain, stream); 01132 else if (real->arg) 01133 hhstate->suppressed_dup_arg = 1; 01134 } 01135 so++; 01136 } 01137 01138 /* Now, long options. */ 01139 if (odoc (real)) 01140 /* A `documentation' option. */ 01141 { 01142 __argp_fmtstream_set_wmargin (stream, uparams.doc_opt_col); 01143 for (opt = real, num = entry->num; num > 0; opt++, num--) 01144 if (opt->name && ovisible (opt)) 01145 { 01146 comma (uparams.doc_opt_col, &pest); 01147 /* Calling gettext here isn't quite right, since sorting will 01148 have been done on the original; but documentation options 01149 should be pretty rare anyway... */ 01150 __argp_fmtstream_puts (stream, 01151 dgettext (state->root_argp->argp_domain, 01152 opt->name)); 01153 } 01154 } 01155 else 01156 /* A real long option. */ 01157 { 01158 int first_long_opt = 1; 01159 01160 __argp_fmtstream_set_wmargin (stream, uparams.long_opt_col); 01161 for (opt = real, num = entry->num; num > 0; opt++, num--) 01162 if (opt->name && ovisible (opt)) 01163 { 01164 comma (uparams.long_opt_col, &pest); 01165 __argp_fmtstream_printf (stream, "--%s", opt->name); 01166 if (first_long_opt || uparams.dup_args) 01167 arg (real, "=%s", "[=%s]", state->root_argp->argp_domain, 01168 stream); 01169 else if (real->arg) 01170 hhstate->suppressed_dup_arg = 1; 01171 } 01172 } 01173 01174 /* Next, documentation strings. */ 01175 __argp_fmtstream_set_lmargin (stream, 0); 01176 01177 if (pest.first) 01178 { 01179 /* Didn't print any switches, what's up? */ 01180 if (!oshort (real) && !real->name) 01181 /* This is a group header, print it nicely. */ 01182 print_header (real->doc, entry->argp, &pest); 01183 else 01184 /* Just a totally shadowed option or null header; print nothing. */ 01185 goto cleanup; /* Just return, after cleaning up. */ 01186 } 01187 else 01188 { 01189 const char *tstr = real->doc ? dgettext (state->root_argp->argp_domain, 01190 real->doc) : 0; 01191 const char *fstr = filter_doc (tstr, real->key, entry->argp, state); 01192 if (fstr && *fstr) 01193 { 01194 unsigned int col = __argp_fmtstream_point (stream); 01195 01196 __argp_fmtstream_set_lmargin (stream, uparams.opt_doc_col); 01197 __argp_fmtstream_set_wmargin (stream, uparams.opt_doc_col); 01198 01199 if (col > (unsigned int) (uparams.opt_doc_col + 3)) 01200 __argp_fmtstream_putc (stream, '\n'); 01201 else if (col >= (unsigned int) uparams.opt_doc_col) 01202 __argp_fmtstream_puts (stream, " "); 01203 else 01204 indent_to (stream, uparams.opt_doc_col); 01205 01206 __argp_fmtstream_puts (stream, fstr); 01207 } 01208 if (fstr && fstr != tstr) 01209 free ((char *) fstr); 01210 01211 /* Reset the left margin. */ 01212 __argp_fmtstream_set_lmargin (stream, 0); 01213 __argp_fmtstream_putc (stream, '\n'); 01214 } 01215 01216 hhstate->prev_entry = entry; 01217 01218 cleanup: 01219 __argp_fmtstream_set_lmargin (stream, old_lm); 01220 __argp_fmtstream_set_wmargin (stream, old_wm); 01221 } 01222 01223 /* Output a long help message about the options in HOL to STREAM. */ 01224 static void 01225 hol_help (struct hol *hol, const struct argp_state *state, 01226 argp_fmtstream_t stream) 01227 { 01228 unsigned num; 01229 struct hol_entry *entry; 01230 struct hol_help_state hhstate = { 0, 0, 0 }; 01231 01232 for (entry = hol->entries, num = hol->num_entries; num > 0; entry++, num--) 01233 hol_entry_help (entry, state, stream, &hhstate); 01234 01235 if (hhstate.suppressed_dup_arg && uparams.dup_args_note) 01236 { 01237 const char *tstr = dgettext (state->root_argp->argp_domain, "\ 01238 Mandatory or optional arguments to long options are also mandatory or \ 01239 optional for any corresponding short options."); 01240 const char *fstr = filter_doc (tstr, ARGP_KEY_HELP_DUP_ARGS_NOTE, 01241 state ? state->root_argp : 0, state); 01242 if (fstr && *fstr) 01243 { 01244 __argp_fmtstream_putc (stream, '\n'); 01245 __argp_fmtstream_puts (stream, fstr); 01246 __argp_fmtstream_putc (stream, '\n'); 01247 } 01248 if (fstr && fstr != tstr) 01249 free ((char *) fstr); 01250 } 01251 } 01252 01253 /* Helper functions for hol_usage. */ 01254 01255 /* If OPT is a short option without an arg, append its key to the string 01256 pointer pointer to by COOKIE, and advance the pointer. */ 01257 static int 01258 add_argless_short_opt (const struct argp_option *opt, 01259 const struct argp_option *real, 01260 const char *domain UNUSED, void *cookie) 01261 { 01262 char **snao_end = cookie; 01263 if (!(opt->arg || real->arg) 01264 && !((opt->flags | real->flags) & OPTION_NO_USAGE)) 01265 *(*snao_end)++ = opt->key; 01266 return 0; 01267 } 01268 01269 /* If OPT is a short option with an arg, output a usage entry for it to the 01270 stream pointed at by COOKIE. */ 01271 static int 01272 usage_argful_short_opt (const struct argp_option *opt, 01273 const struct argp_option *real, 01274 const char *domain UNUSED, void *cookie) 01275 { 01276 argp_fmtstream_t stream = cookie; 01277 const char *arg = opt->arg; 01278 int flags = opt->flags | real->flags; 01279 01280 if (! arg) 01281 arg = real->arg; 01282 01283 if (arg && !(flags & OPTION_NO_USAGE)) 01284 { 01285 arg = dgettext (domain, arg); 01286 01287 if (flags & OPTION_ARG_OPTIONAL) 01288 __argp_fmtstream_printf (stream, " [-%c[%s]]", opt->key, arg); 01289 else 01290 { 01291 /* Manually do line wrapping so that it (probably) won't 01292 get wrapped at the embedded space. */ 01293 space (stream, 6 + strlen (arg)); 01294 __argp_fmtstream_printf (stream, "[-%c %s]", opt->key, arg); 01295 } 01296 } 01297 01298 return 0; 01299 } 01300 01301 /* Output a usage entry for the long option opt to the stream pointed at by 01302 COOKIE. */ 01303 static int 01304 usage_long_opt (const struct argp_option *opt, 01305 const struct argp_option *real, 01306 const char *domain UNUSED, void *cookie) 01307 { 01308 argp_fmtstream_t stream = cookie; 01309 const char *arg = opt->arg; 01310 int flags = opt->flags | real->flags; 01311 01312 if (! arg) 01313 arg = real->arg; 01314 01315 if (! (flags & OPTION_NO_USAGE)) 01316 { 01317 if (arg) 01318 { 01319 arg = dgettext (domain, arg); 01320 if (flags & OPTION_ARG_OPTIONAL) 01321 __argp_fmtstream_printf (stream, " [--%s[=%s]]", opt->name, arg); 01322 else 01323 __argp_fmtstream_printf (stream, " [--%s=%s]", opt->name, arg); 01324 } 01325 else 01326 __argp_fmtstream_printf (stream, " [--%s]", opt->name); 01327 } 01328 01329 return 0; 01330 } 01331 01332 /* Print a short usage description for the arguments in HOL to STREAM. */ 01333 static void 01334 hol_usage (struct hol *hol, argp_fmtstream_t stream) 01335 { 01336 if (hol->num_entries > 0) 01337 { 01338 unsigned nentries; 01339 struct hol_entry *entry; 01340 char *short_no_arg_opts = alloca (strlen (hol->short_options) + 1); 01341 char *snao_end = short_no_arg_opts; 01342 01343 /* First we put a list of short options without arguments. */ 01344 for (entry = hol->entries, nentries = hol->num_entries 01345 ; nentries > 0 01346 ; entry++, nentries--) 01347 hol_entry_short_iterate (entry, add_argless_short_opt, 01348 entry->argp->argp_domain, &snao_end); 01349 if (snao_end > short_no_arg_opts) 01350 { 01351 *snao_end++ = 0; 01352 __argp_fmtstream_printf (stream, " [-%s]", short_no_arg_opts); 01353 } 01354 01355 /* Now a list of short options *with* arguments. */ 01356 for (entry = hol->entries, nentries = hol->num_entries 01357 ; nentries > 0 01358 ; entry++, nentries--) 01359 hol_entry_short_iterate (entry, usage_argful_short_opt, 01360 entry->argp->argp_domain, stream); 01361 01362 /* Finally, a list of long options (whew!). */ 01363 for (entry = hol->entries, nentries = hol->num_entries 01364 ; nentries > 0 01365 ; entry++, nentries--) 01366 hol_entry_long_iterate (entry, usage_long_opt, 01367 entry->argp->argp_domain, stream); 01368 } 01369 } 01370 01371 /* Make a HOL containing all levels of options in ARGP. CLUSTER is the 01372 cluster in which ARGP's entries should be clustered, or 0. */ 01373 static struct hol * 01374 argp_hol (const struct argp *argp, struct hol_cluster *cluster) 01375 { 01376 const struct argp_child *child = argp->children; 01377 struct hol *hol = make_hol (argp, cluster); 01378 if (child) 01379 while (child->argp) 01380 { 01381 struct hol_cluster *child_cluster = 01382 ((child->group || child->header) 01383 /* Put CHILD->argp within its own cluster. */ 01384 ? hol_add_cluster (hol, child->group, child->header, 01385 child - argp->children, cluster, argp) 01386 /* Just merge it into the parent's cluster. */ 01387 : cluster); 01388 hol_append (hol, argp_hol (child->argp, child_cluster)) ; 01389 child++; 01390 } 01391 return hol; 01392 } 01393 01394 /* Calculate how many different levels with alternative args strings exist in 01395 ARGP. */ 01396 static size_t 01397 argp_args_levels (const struct argp *argp) 01398 { 01399 size_t levels = 0; 01400 const struct argp_child *child = argp->children; 01401 01402 if (argp->args_doc && strchr (argp->args_doc, '\n')) 01403 levels++; 01404 01405 if (child) 01406 while (child->argp) 01407 levels += argp_args_levels ((child++)->argp); 01408 01409 return levels; 01410 } 01411 01412 /* Print all the non-option args documented in ARGP to STREAM. Any output is 01413 preceded by a space. LEVELS is a pointer to a byte vector the length 01414 returned by argp_args_levels; it should be initialized to zero, and 01415 updated by this routine for the next call if ADVANCE is true. True is 01416 returned as long as there are more patterns to output. */ 01417 static int 01418 argp_args_usage (const struct argp *argp, const struct argp_state *state, 01419 char **levels, int advance, argp_fmtstream_t stream) 01420 { 01421 char *our_level = *levels; 01422 int multiple = 0; 01423 const struct argp_child *child = argp->children; 01424 const char *tdoc = dgettext (argp->argp_domain, argp->args_doc), *nl = 0; 01425 const char *fdoc = filter_doc (tdoc, ARGP_KEY_HELP_ARGS_DOC, argp, state); 01426 01427 if (fdoc) 01428 { 01429 const char *cp = fdoc; 01430 nl = __strchrnul (cp, '\n'); 01431 if (*nl != '\0') 01432 /* This is a `multi-level' args doc; advance to the correct position 01433 as determined by our state in LEVELS, and update LEVELS. */ 01434 { 01435 int i; 01436 multiple = 1; 01437 for (i = 0; i < *our_level; i++) 01438 cp = nl + 1, nl = __strchrnul (cp, '\n'); 01439 (*levels)++; 01440 } 01441 01442 /* Manually do line wrapping so that it (probably) won't get wrapped at 01443 any embedded spaces. */ 01444 space (stream, 1 + nl - cp); 01445 01446 __argp_fmtstream_write (stream, cp, nl - cp); 01447 } 01448 if (fdoc && fdoc != tdoc) 01449 free ((char *)fdoc); /* Free user's modified doc string. */ 01450 01451 if (child) 01452 while (child->argp) 01453 advance = !argp_args_usage ((child++)->argp, state, levels, advance, stream); 01454 01455 if (advance && multiple) 01456 { 01457 /* Need to increment our level. */ 01458 if (*nl) 01459 /* There's more we can do here. */ 01460 { 01461 (*our_level)++; 01462 advance = 0; /* Our parent shouldn't advance also. */ 01463 } 01464 else if (*our_level > 0) 01465 /* We had multiple levels, but used them up; reset to zero. */ 01466 *our_level = 0; 01467 } 01468 01469 return !advance; 01470 } 01471 01472 /* Print the documentation for ARGP to STREAM; if POST is false, then 01473 everything preceeding a `\v' character in the documentation strings (or 01474 the whole string, for those with none) is printed, otherwise, everything 01475 following the `\v' character (nothing for strings without). Each separate 01476 bit of documentation is separated a blank line, and if PRE_BLANK is true, 01477 then the first is as well. If FIRST_ONLY is true, only the first 01478 occurrence is output. Returns true if anything was output. */ 01479 static int 01480 argp_doc (const struct argp *argp, const struct argp_state *state, 01481 int post, int pre_blank, int first_only, 01482 argp_fmtstream_t stream) 01483 { 01484 const char *text; 01485 const char *inp_text; 01486 void *input = 0; 01487 int anything = 0; 01488 size_t inp_text_limit = 0; 01489 const char *doc = dgettext (argp->argp_domain, argp->doc); 01490 const struct argp_child *child = argp->children; 01491 01492 if (doc) 01493 { 01494 char *vt = strchr (doc, '\v'); 01495 inp_text = post ? (vt ? vt + 1 : 0) : doc; 01496 inp_text_limit = (!post && vt) ? (vt - doc) : 0; 01497 } 01498 else 01499 inp_text = 0; 01500 01501 if (argp->help_filter) 01502 /* We have to filter the doc strings. */ 01503 { 01504 if (inp_text_limit) 01505 /* Copy INP_TEXT so that it's nul-terminated. */ 01506 inp_text = STRNDUP (inp_text, inp_text_limit); 01507 input = __argp_input (argp, state); 01508 text = 01509 (*argp->help_filter) (post 01510 ? ARGP_KEY_HELP_POST_DOC 01511 : ARGP_KEY_HELP_PRE_DOC, 01512 inp_text, input); 01513 } 01514 else 01515 text = (const char *) inp_text; 01516 01517 if (text) 01518 { 01519 if (pre_blank) 01520 __argp_fmtstream_putc (stream, '\n'); 01521 01522 if (text == inp_text && inp_text_limit) 01523 __argp_fmtstream_write (stream, inp_text, inp_text_limit); 01524 else 01525 __argp_fmtstream_puts (stream, text); 01526 01527 if (__argp_fmtstream_point (stream) > __argp_fmtstream_lmargin (stream)) 01528 __argp_fmtstream_putc (stream, '\n'); 01529 01530 anything = 1; 01531 } 01532 01533 if (text && text != inp_text) 01534 free ((char *) text); /* Free TEXT returned from the help filter. */ 01535 if (inp_text && inp_text_limit && argp->help_filter) 01536 free ((char *) inp_text); /* We copied INP_TEXT, so free it now. */ 01537 01538 if (post && argp->help_filter) 01539 /* Now see if we have to output a ARGP_KEY_HELP_EXTRA text. */ 01540 { 01541 text = (*argp->help_filter) (ARGP_KEY_HELP_EXTRA, 0, input); 01542 if (text) 01543 { 01544 if (anything || pre_blank) 01545 __argp_fmtstream_putc (stream, '\n'); 01546 __argp_fmtstream_puts (stream, text); 01547 free ((char *) text); 01548 if (__argp_fmtstream_point (stream) 01549 > __argp_fmtstream_lmargin (stream)) 01550 __argp_fmtstream_putc (stream, '\n'); 01551 anything = 1; 01552 } 01553 } 01554 01555 if (child) 01556 while (child->argp && !(first_only && anything)) 01557 anything |= 01558 argp_doc ((child++)->argp, state, 01559 post, anything || pre_blank, first_only, 01560 stream); 01561 01562 return anything; 01563 } 01564 01565 /* Output a usage message for ARGP to STREAM. If called from 01566 argp_state_help, STATE is the relevent parsing state. FLAGS are from the 01567 set ARGP_HELP_*. NAME is what to use wherever a `program name' is 01568 needed. */ 01569 01570 static void 01571 _help (const struct argp *argp, const struct argp_state *state, FILE *stream, 01572 unsigned flags, const char *name) 01573 { 01574 int anything = 0; /* Whether we've output anything. */ 01575 struct hol *hol = 0; 01576 argp_fmtstream_t fs; 01577 01578 if (! stream) 01579 return; 01580 01581 FLOCKFILE (stream); 01582 01583 if (! uparams.valid) 01584 fill_in_uparams (state); 01585 01586 fs = __argp_make_fmtstream (stream, 0, uparams.rmargin, 0); 01587 if (! fs) 01588 { 01589 FUNLOCKFILE (stream); 01590 return; 01591 } 01592 01593 if (flags & (ARGP_HELP_USAGE | ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG)) 01594 { 01595 hol = argp_hol (argp, 0); 01596 01597 /* If present, these options always come last. */ 01598 hol_set_group (hol, "help", -1); 01599 hol_set_group (hol, "version", -1); 01600 01601 hol_sort (hol); 01602 } 01603 01604 if (flags & (ARGP_HELP_USAGE | ARGP_HELP_SHORT_USAGE)) 01605 /* Print a short `Usage:' message. */ 01606 { 01607 int first_pattern = 1, more_patterns; 01608 size_t num_pattern_levels = argp_args_levels (argp); 01609 char *pattern_levels = alloca (num_pattern_levels); 01610 01611 memset (pattern_levels, 0, num_pattern_levels); 01612 01613 do 01614 { 01615 int old_lm; 01616 int old_wm = __argp_fmtstream_set_wmargin (fs, uparams.usage_indent); 01617 char *levels = pattern_levels; 01618 01619 if (first_pattern) 01620 __argp_fmtstream_printf (fs, "%s %s", 01621 dgettext (argp->argp_domain, "Usage:"), 01622 name); 01623 else 01624 __argp_fmtstream_printf (fs, "%s %s", 01625 dgettext (argp->argp_domain, " or: "), 01626 name); 01627 01628 /* We set the lmargin as well as the wmargin, because hol_usage 01629 manually wraps options with newline to avoid annoying breaks. */ 01630 old_lm = __argp_fmtstream_set_lmargin (fs, uparams.usage_indent); 01631 01632 if (flags & ARGP_HELP_SHORT_USAGE) 01633 /* Just show where the options go. */ 01634 { 01635 if (hol->num_entries > 0) 01636 __argp_fmtstream_puts (fs, dgettext (argp->argp_domain, 01637 " [OPTION...]")); 01638 } 01639 else 01640 /* Actually print the options. */ 01641 { 01642 hol_usage (hol, fs); 01643 flags |= ARGP_HELP_SHORT_USAGE; /* But only do so once. */ 01644 } 01645 01646 more_patterns = argp_args_usage (argp, state, &levels, 1, fs); 01647 01648 __argp_fmtstream_set_wmargin (fs, old_wm); 01649 __argp_fmtstream_set_lmargin (fs, old_lm); 01650 01651 __argp_fmtstream_putc (fs, '\n'); 01652 anything = 1; 01653 01654 first_pattern = 0; 01655 } 01656 while (more_patterns); 01657 } 01658 01659 if (flags & ARGP_HELP_PRE_DOC) 01660 anything |= argp_doc (argp, state, 0, 0, 1, fs); 01661 01662 if (flags & ARGP_HELP_SEE) 01663 { 01664 __argp_fmtstream_printf (fs, dgettext (argp->argp_domain, "\ 01665 Try `%s --help' or `%s --usage' for more information.\n"), 01666 name, name); 01667 anything = 1; 01668 } 01669 01670 if (flags & ARGP_HELP_LONG) 01671 /* Print a long, detailed help message. */ 01672 { 01673 /* Print info about all the options. */ 01674 if (hol->num_entries > 0) 01675 { 01676 if (anything) 01677 __argp_fmtstream_putc (fs, '\n'); 01678 hol_help (hol, state, fs); 01679 anything = 1; 01680 } 01681 } 01682 01683 if (flags & ARGP_HELP_POST_DOC) 01684 /* Print any documentation strings at the end. */ 01685 anything |= argp_doc (argp, state, 1, anything, 0, fs); 01686 01687 if ((flags & ARGP_HELP_BUG_ADDR) && argp_program_bug_address) 01688 { 01689 if (anything) 01690 __argp_fmtstream_putc (fs, '\n'); 01691 __argp_fmtstream_printf (fs, dgettext (argp->argp_domain, 01692 "Report bugs to %s.\n"), 01693 argp_program_bug_address); 01694 anything = 1; 01695 } 01696 01697 FUNLOCKFILE (stream); 01698 01699 if (hol) 01700 hol_free (hol); 01701 01702 __argp_fmtstream_free (fs); 01703 } 01704 01705 /* Output a usage message for ARGP to STREAM. FLAGS are from the set 01706 ARGP_HELP_*. NAME is what to use wherever a `program name' is needed. */ 01707 void __argp_help (const struct argp *argp, FILE *stream, 01708 unsigned flags, char *name) 01709 { 01710 _help (argp, 0, stream, flags, name); 01711 } 01712 #ifdef weak_alias 01713 weak_alias (__argp_help, argp_help) 01714 #endif 01715 01716 char *__argp_basename(char *name) 01717 { 01718 char *short_name = strrchr(name, '/'); 01719 return short_name ? short_name + 1 : name; 01720 } 01721 01722 char * 01723 __argp_short_program_name(const struct argp_state *state) 01724 { 01725 if (state) 01726 return state->name; 01727 #if HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME 01728 return program_invocation_short_name; 01729 #elif HAVE_DECL_PROGRAM_INVOCATION_NAME 01730 return __argp_basename(program_invocation_name); 01731 #else /* !HAVE_DECL_PROGRAM_INVOCATION_NAME */ 01732 /* FIXME: What now? Miles suggests that it is better to use NULL, 01733 but currently the value is passed on directly to fputs_unlocked, 01734 so that requires more changes. */ 01735 # if __GNUC__ 01736 # warning No reasonable value to return 01737 return ""; 01738 # endif /* __GNUC__ */ 01739 #endif /* !HAVE_DECL_PROGRAM_INVOCATION_NAME */ 01740 } 01741 01742 /* Output, if appropriate, a usage message for STATE to STREAM. FLAGS are 01743 from the set ARGP_HELP_*. */ 01744 void 01745 __argp_state_help (const struct argp_state *state, FILE *stream, unsigned flags) 01746 { 01747 if ((!state || ! (state->flags & ARGP_NO_ERRS)) && stream) 01748 { 01749 if (state && (state->flags & ARGP_LONG_ONLY)) 01750 flags |= ARGP_HELP_LONG_ONLY; 01751 01752 _help (state ? state->root_argp : 0, state, stream, flags, 01753 __argp_short_program_name(state)); 01754 01755 if (!state || ! (state->flags & ARGP_NO_EXIT)) 01756 { 01757 if (flags & ARGP_HELP_EXIT_ERR) 01758 exit (argp_err_exit_status); 01759 if (flags & ARGP_HELP_EXIT_OK) 01760 exit (0); 01761 } 01762 } 01763 } 01764 #ifdef weak_alias 01765 weak_alias (__argp_state_help, argp_state_help) 01766 #endif 01767 01768 /* If appropriate, print the printf string FMT and following args, preceded 01769 by the program name and `:', to stderr, and followed by a `Try ... --help' 01770 message, then exit (1). */ 01771 void 01772 __argp_error (const struct argp_state *state, const char *fmt, ...) 01773 { 01774 if (!state || !(state->flags & ARGP_NO_ERRS)) 01775 { 01776 FILE *stream = state ? state->err_stream : stderr; 01777 01778 if (stream) 01779 { 01780 va_list ap; 01781 01782 FLOCKFILE (stream); 01783 01784 FPUTS_UNLOCKED (__argp_short_program_name(state), 01785 stream); 01786 PUTC_UNLOCKED (':', stream); 01787 PUTC_UNLOCKED (' ', stream); 01788 01789 va_start (ap, fmt); 01790 vfprintf (stream, fmt, ap); 01791 va_end (ap); 01792 01793 PUTC_UNLOCKED ('\n', stream); 01794 01795 __argp_state_help (state, stream, ARGP_HELP_STD_ERR); 01796 01797 FUNLOCKFILE (stream); 01798 } 01799 } 01800 } 01801 #ifdef weak_alias 01802 weak_alias (__argp_error, argp_error) 01803 #endif 01804 01805 /* Similar to the standard gnu error-reporting function error(), but will 01806 respect the ARGP_NO_EXIT and ARGP_NO_ERRS flags in STATE, and will print 01807 to STATE->err_stream. This is useful for argument parsing code that is 01808 shared between program startup (when exiting is desired) and runtime 01809 option parsing (when typically an error code is returned instead). The 01810 difference between this function and argp_error is that the latter is for 01811 *parsing errors*, and the former is for other problems that occur during 01812 parsing but don't reflect a (syntactic) problem with the input. */ 01813 void 01814 __argp_failure (const struct argp_state *state, int status, int errnum, 01815 const char *fmt, ...) 01816 { 01817 if (!state || !(state->flags & ARGP_NO_ERRS)) 01818 { 01819 FILE *stream = state ? state->err_stream : stderr; 01820 01821 if (stream) 01822 { 01823 FLOCKFILE (stream); 01824 01825 FPUTS_UNLOCKED (__argp_short_program_name(state), 01826 stream); 01827 01828 if (fmt) 01829 { 01830 va_list ap; 01831 01832 PUTC_UNLOCKED (':', stream); 01833 PUTC_UNLOCKED (' ', stream); 01834 01835 va_start (ap, fmt); 01836 vfprintf (stream, fmt, ap); 01837 va_end (ap); 01838 } 01839 01840 if (errnum) 01841 { 01842 PUTC_UNLOCKED (':', stream); 01843 PUTC_UNLOCKED (' ', stream); 01844 fputs (STRERROR (errnum), stream); 01845 } 01846 01847 PUTC_UNLOCKED ('\n', stream); 01848 01849 FUNLOCKFILE (stream); 01850 01851 if (status && (!state || !(state->flags & ARGP_NO_EXIT))) 01852 exit (status); 01853 } 01854 } 01855 } 01856 #ifdef weak_alias 01857 weak_alias (__argp_failure, argp_failure) 01858 #endif