aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2002-06-17 16:27:40 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2002-06-17 16:27:40 +0000
commitd764db9c57ad3fd67c278010e275221158d53ed6 (patch)
tree530ca6a45aac492477faace53e728cc5a6882a0c
parentdf9b438dd6af695e0a1de6942f3cb28900e43a55 (diff)
downloadipacct-d764db9c57ad3fd67c278010e275221158d53ed6.tar.gz
ipacct-d764db9c57ad3fd67c278010e275221158d53ed6.tar.bz2
Added to repository
-rw-r--r--lib/argp-fmtstream.h292
-rw-r--r--lib/argp-fs-xinl.c41
-rw-r--r--lib/argp-help.c1778
-rw-r--r--lib/argp-namefrob.h88
-rw-r--r--lib/argp-parse.c979
-rw-r--r--lib/argp-pv.c25
-rw-r--r--lib/argp-pvh.c32
-rw-r--r--lib/argp-xinl.c40
-rw-r--r--lib/argp.h562
-rw-r--r--lib/pin.c8
-rw-r--r--lib/strchrnul.c163
-rw-r--r--lib/strerror.c62
-rw-r--r--lib/strndup.c46
-rw-r--r--lib/strnlen.c30
14 files changed, 4146 insertions, 0 deletions
diff --git a/lib/argp-fmtstream.h b/lib/argp-fmtstream.h
new file mode 100644
index 0000000..ba1dc8d
--- /dev/null
+++ b/lib/argp-fmtstream.h
@@ -0,0 +1,292 @@
+/* Word-wrapping and line-truncating streams.
+ Copyright (C) 1997, 2001 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Written by Miles Bader <miles@gnu.ai.mit.edu>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* This package emulates glibc `line_wrap_stream' semantics for systems that
+ don't have that. If the system does have it, it is just a wrapper for
+ that. This header file is only used internally while compiling argp, and
+ shouldn't be installed. */
+
+#ifndef _ARGP_FMTSTREAM_H
+#define _ARGP_FMTSTREAM_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#if (_LIBC - 0 && !defined (USE_IN_LIBIO)) \
+ || (defined (__GNU_LIBRARY__) && defined (HAVE_LINEWRAP_H))
+/* line_wrap_stream is available, so use that. */
+#define ARGP_FMTSTREAM_USE_LINEWRAP
+#endif
+
+#ifdef ARGP_FMTSTREAM_USE_LINEWRAP
+/* Just be a simple wrapper for line_wrap_stream; the semantics are
+ *slightly* different, as line_wrap_stream doesn't actually make a new
+ object, it just modifies the given stream (reversibly) to do
+ line-wrapping. Since we control who uses this code, it doesn't matter. */
+
+#include <linewrap.h>
+
+typedef FILE *argp_fmtstream_t;
+
+#define argp_make_fmtstream line_wrap_stream
+#define __argp_make_fmtstream line_wrap_stream
+#define argp_fmtstream_free line_unwrap_stream
+#define __argp_fmtstream_free line_unwrap_stream
+
+#define __argp_fmtstream_putc(fs,ch) putc(ch,fs)
+#define argp_fmtstream_putc(fs,ch) putc(ch,fs)
+#define __argp_fmtstream_puts(fs,str) fputs(str,fs)
+#define argp_fmtstream_puts(fs,str) fputs(str,fs)
+#define __argp_fmtstream_write(fs,str,len) fwrite(str,1,len,fs)
+#define argp_fmtstream_write(fs,str,len) fwrite(str,1,len,fs)
+#define __argp_fmtstream_printf fprintf
+#define argp_fmtstream_printf fprintf
+
+#define __argp_fmtstream_lmargin line_wrap_lmargin
+#define argp_fmtstream_lmargin line_wrap_lmargin
+#define __argp_fmtstream_set_lmargin line_wrap_set_lmargin
+#define argp_fmtstream_set_lmargin line_wrap_set_lmargin
+#define __argp_fmtstream_rmargin line_wrap_rmargin
+#define argp_fmtstream_rmargin line_wrap_rmargin
+#define __argp_fmtstream_set_rmargin line_wrap_set_rmargin
+#define argp_fmtstream_set_rmargin line_wrap_set_rmargin
+#define __argp_fmtstream_wmargin line_wrap_wmargin
+#define argp_fmtstream_wmargin line_wrap_wmargin
+#define __argp_fmtstream_set_wmargin line_wrap_set_wmargin
+#define argp_fmtstream_set_wmargin line_wrap_set_wmargin
+#define __argp_fmtstream_point line_wrap_point
+#define argp_fmtstream_point line_wrap_point
+
+#else /* !ARGP_FMTSTREAM_USE_LINEWRAP */
+/* Guess we have to define our own version. */
+
+
+struct argp_fmtstream
+{
+ FILE *stream; /* The stream we're outputting to. */
+
+ size_t lmargin, rmargin; /* Left and right margins. */
+ ssize_t wmargin; /* Margin to wrap to, or -1 to truncate. */
+
+ /* Point in buffer to which we've processed for wrapping, but not output. */
+ size_t point_offs;
+ /* Output column at POINT_OFFS, or -1 meaning 0 but don't add lmargin. */
+ ssize_t point_col;
+
+ char *buf; /* Output buffer. */
+ char *p; /* Current end of text in BUF. */
+ char *end; /* Absolute end of BUF. */
+};
+
+typedef struct argp_fmtstream *argp_fmtstream_t;
+
+/* Return an argp_fmtstream that outputs to STREAM, and which prefixes lines
+ written on it with LMARGIN spaces and limits them to RMARGIN columns
+ total. If WMARGIN >= 0, words that extend past RMARGIN are wrapped by
+ replacing the whitespace before them with a newline and WMARGIN spaces.
+ Otherwise, chars beyond RMARGIN are simply dropped until a newline.
+ Returns NULL if there was an error. */
+extern argp_fmtstream_t __argp_make_fmtstream (FILE *__stream,
+ size_t __lmargin,
+ size_t __rmargin,
+ ssize_t __wmargin);
+extern argp_fmtstream_t argp_make_fmtstream (FILE *__stream,
+ size_t __lmargin,
+ size_t __rmargin,
+ ssize_t __wmargin);
+
+/* Flush __FS to its stream, and free it (but don't close the stream). */
+extern void __argp_fmtstream_free (argp_fmtstream_t __fs);
+extern void argp_fmtstream_free (argp_fmtstream_t __fs);
+
+extern ssize_t __argp_fmtstream_printf (argp_fmtstream_t __fs,
+ const char *__fmt, ...);
+extern ssize_t argp_fmtstream_printf (argp_fmtstream_t __fs,
+ const char *__fmt, ...);
+
+extern int __argp_fmtstream_putc (argp_fmtstream_t __fs, int __ch);
+extern int argp_fmtstream_putc (argp_fmtstream_t __fs, int __ch);
+
+extern int __argp_fmtstream_puts (argp_fmtstream_t __fs, const char *__str);
+extern int argp_fmtstream_puts (argp_fmtstream_t __fs, const char *__str);
+
+extern size_t __argp_fmtstream_write (argp_fmtstream_t __fs,
+ const char *__str, size_t __len);
+extern size_t argp_fmtstream_write (argp_fmtstream_t __fs,
+ const char *__str, size_t __len);
+
+/* Access macros for various bits of state. */
+#define argp_fmtstream_lmargin(__fs) ((__fs)->lmargin)
+#define argp_fmtstream_rmargin(__fs) ((__fs)->rmargin)
+#define argp_fmtstream_wmargin(__fs) ((__fs)->wmargin)
+#define __argp_fmtstream_lmargin argp_fmtstream_lmargin
+#define __argp_fmtstream_rmargin argp_fmtstream_rmargin
+#define __argp_fmtstream_wmargin argp_fmtstream_wmargin
+
+/* Set __FS's left margin to LMARGIN and return the old value. */
+extern size_t argp_fmtstream_set_lmargin (argp_fmtstream_t __fs,
+ size_t __lmargin);
+extern size_t __argp_fmtstream_set_lmargin (argp_fmtstream_t __fs,
+ size_t __lmargin);
+
+/* Set __FS's right margin to __RMARGIN and return the old value. */
+extern size_t argp_fmtstream_set_rmargin (argp_fmtstream_t __fs,
+ size_t __rmargin);
+extern size_t __argp_fmtstream_set_rmargin (argp_fmtstream_t __fs,
+ size_t __rmargin);
+
+/* Set __FS's wrap margin to __WMARGIN and return the old value. */
+extern size_t argp_fmtstream_set_wmargin (argp_fmtstream_t __fs,
+ size_t __wmargin);
+extern size_t __argp_fmtstream_set_wmargin (argp_fmtstream_t __fs,
+ size_t __wmargin);
+
+/* Return the column number of the current output point in __FS. */
+extern size_t argp_fmtstream_point (argp_fmtstream_t __fs);
+extern size_t __argp_fmtstream_point (argp_fmtstream_t __fs);
+
+/* Internal routines. */
+extern void _argp_fmtstream_update (argp_fmtstream_t __fs);
+extern void __argp_fmtstream_update (argp_fmtstream_t __fs);
+extern int _argp_fmtstream_ensure (argp_fmtstream_t __fs, size_t __amount);
+extern int __argp_fmtstream_ensure (argp_fmtstream_t __fs, size_t __amount);
+
+#ifdef __OPTIMIZE__
+/* Inline versions of above routines. */
+
+#if !_LIBC
+#define __argp_fmtstream_putc argp_fmtstream_putc
+#define __argp_fmtstream_puts argp_fmtstream_puts
+#define __argp_fmtstream_write argp_fmtstream_write
+#define __argp_fmtstream_set_lmargin argp_fmtstream_set_lmargin
+#define __argp_fmtstream_set_rmargin argp_fmtstream_set_rmargin
+#define __argp_fmtstream_set_wmargin argp_fmtstream_set_wmargin
+#define __argp_fmtstream_point argp_fmtstream_point
+#define __argp_fmtstream_update _argp_fmtstream_update
+#define __argp_fmtstream_ensure _argp_fmtstream_ensure
+#endif
+
+#ifndef ARGP_FS_EI
+#define ARGP_FS_EI extern inline
+#endif
+
+ARGP_FS_EI size_t
+__argp_fmtstream_write (argp_fmtstream_t __fs,
+ const char *__str, size_t __len)
+{
+ if (__fs->p + __len <= __fs->end || __argp_fmtstream_ensure (__fs, __len))
+ {
+ memcpy (__fs->p, __str, __len);
+ __fs->p += __len;
+ return __len;
+ }
+ else
+ return 0;
+}
+
+ARGP_FS_EI int
+__argp_fmtstream_puts (argp_fmtstream_t __fs, const char *__str)
+{
+ size_t __len = strlen (__str);
+ if (__len)
+ {
+ size_t __wrote = __argp_fmtstream_write (__fs, __str, __len);
+ return __wrote == __len ? 0 : -1;
+ }
+ else
+ return 0;
+}
+
+ARGP_FS_EI int
+__argp_fmtstream_putc (argp_fmtstream_t __fs, int __ch)
+{
+ if (__fs->p < __fs->end || __argp_fmtstream_ensure (__fs, 1))
+ return *__fs->p++ = __ch;
+ else
+ return EOF;
+}
+
+/* Set __FS's left margin to __LMARGIN and return the old value. */
+ARGP_FS_EI size_t
+__argp_fmtstream_set_lmargin (argp_fmtstream_t __fs, size_t __lmargin)
+{
+ size_t __old;
+ if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs)
+ __argp_fmtstream_update (__fs);
+ __old = __fs->lmargin;
+ __fs->lmargin = __lmargin;
+ return __old;
+}
+
+/* Set __FS's right margin to __RMARGIN and return the old value. */
+ARGP_FS_EI size_t
+__argp_fmtstream_set_rmargin (argp_fmtstream_t __fs, size_t __rmargin)
+{
+ size_t __old;
+ if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs)
+ __argp_fmtstream_update (__fs);
+ __old = __fs->rmargin;
+ __fs->rmargin = __rmargin;
+ return __old;
+}
+
+/* Set FS's wrap margin to __WMARGIN and return the old value. */
+ARGP_FS_EI size_t
+__argp_fmtstream_set_wmargin (argp_fmtstream_t __fs, size_t __wmargin)
+{
+ size_t __old;
+ if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs)
+ __argp_fmtstream_update (__fs);
+ __old = __fs->wmargin;
+ __fs->wmargin = __wmargin;
+ return __old;
+}
+
+/* Return the column number of the current output point in __FS. */
+ARGP_FS_EI size_t
+__argp_fmtstream_point (argp_fmtstream_t __fs)
+{
+ if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs)
+ __argp_fmtstream_update (__fs);
+ return __fs->point_col >= 0 ? __fs->point_col : 0;
+}
+
+#if !_LIBC
+#undef __argp_fmtstream_putc
+#undef __argp_fmtstream_puts
+#undef __argp_fmtstream_write
+#undef __argp_fmtstream_set_lmargin
+#undef __argp_fmtstream_set_rmargin
+#undef __argp_fmtstream_set_wmargin
+#undef __argp_fmtstream_point
+#undef __argp_fmtstream_update
+#undef __argp_fmtstream_ensure
+#endif
+
+#endif /* __OPTIMIZE__ */
+
+#endif /* ARGP_FMTSTREAM_USE_LINEWRAP */
+
+#endif /* argp-fmtstream.h */
diff --git a/lib/argp-fs-xinl.c b/lib/argp-fs-xinl.c
new file mode 100644
index 0000000..94d5f58
--- /dev/null
+++ b/lib/argp-fs-xinl.c
@@ -0,0 +1,41 @@
+/* Real definitions for extern inline functions in argp-fmtstream.h
+ Copyright (C) 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Written by Miles Bader <miles@gnu.ai.mit.edu>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define ARGP_FS_EI
+#undef __OPTIMIZE__
+#define __OPTIMIZE__
+#include "argp-fmtstream.h"
+
+/* Add weak aliases. */
+#if _LIBC - 0 && !defined (ARGP_FMTSTREAM_USE_LINEWRAP) && defined (weak_alias)
+
+weak_alias (__argp_fmtstream_putc, argp_fmtstream_putc)
+weak_alias (__argp_fmtstream_puts, argp_fmtstream_puts)
+weak_alias (__argp_fmtstream_write, argp_fmtstream_write)
+weak_alias (__argp_fmtstream_set_lmargin, argp_fmtstream_set_lmargin)
+weak_alias (__argp_fmtstream_set_rmargin, argp_fmtstream_set_rmargin)
+weak_alias (__argp_fmtstream_set_wmargin, argp_fmtstream_set_wmargin)
+weak_alias (__argp_fmtstream_point, argp_fmtstream_point)
+
+#endif
diff --git a/lib/argp-help.c b/lib/argp-help.c
new file mode 100644
index 0000000..584541e
--- /dev/null
+++ b/lib/argp-help.c
@@ -0,0 +1,1778 @@
+/* Hierarchial argument parsing help output
+ Copyright (C) 1995,1996,1997,1998,1999,2000, 2001 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Written by Miles Bader <miles@gnu.ai.mit.edu>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef alloca
+# ifdef __GNUC__
+# define alloca __builtin_alloca
+# define HAVE_ALLOCA 1
+# else
+# if defined HAVE_ALLOCA_H || defined _LIBC
+# include <alloca.h>
+# else
+# ifdef _AIX
+ #pragma alloca
+# else
+# ifndef alloca
+char *alloca ();
+# endif
+# endif
+# endif
+# endif
+#endif
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <malloc.h>
+#include <ctype.h>
+
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+
+#ifndef _
+/* This is for other GNU distributions with internationalized messages. */
+# if defined HAVE_LIBINTL_H || defined _LIBC
+# include <libintl.h>
+# ifdef _LIBC
+# undef dgettext
+# define dgettext(domain, msgid) __dcgettext (domain, msgid, LC_MESSAGES)
+# endif
+# else
+# define dgettext(domain, msgid) (msgid)
+# endif
+#endif
+
+#include "argp.h"
+#include "argp-fmtstream.h"
+#include "argp-namefrob.h"
+
+/* User-selectable (using an environment variable) formatting parameters.
+
+ These may be specified in an environment variable called `ARGP_HELP_FMT',
+ with a contents like: VAR1=VAL1,VAR2=VAL2,BOOLVAR2,no-BOOLVAR2
+ Where VALn must be a positive integer. The list of variables is in the
+ UPARAM_NAMES vector, below. */
+
+/* Default parameters. */
+#define DUP_ARGS 0 /* True if option argument can be duplicated. */
+#define DUP_ARGS_NOTE 1 /* True to print a note about duplicate args. */
+#define SHORT_OPT_COL 2 /* column in which short options start */
+#define LONG_OPT_COL 6 /* column in which long options start */
+#define DOC_OPT_COL 2 /* column in which doc options start */
+#define OPT_DOC_COL 29 /* column in which option text starts */
+#define HEADER_COL 1 /* column in which group headers are printed */
+#define USAGE_INDENT 12 /* indentation of wrapped usage lines */
+#define RMARGIN 79 /* right margin used for wrapping */
+
+/* User-selectable (using an environment variable) formatting parameters.
+ They must all be of type `int' for the parsing code to work. */
+struct uparams
+{
+ /* If true, arguments for an option are shown with both short and long
+ options, even when a given option has both, e.g. `-x ARG, --longx=ARG'.
+ If false, then if an option has both, the argument is only shown with
+ the long one, e.g., `-x, --longx=ARG', and a message indicating that
+ this really means both is printed below the options. */
+ int dup_args;
+
+ /* This is true if when DUP_ARGS is false, and some duplicate arguments have
+ been suppressed, an explanatory message should be printed. */
+ int dup_args_note;
+
+ /* Various output columns. */
+ int short_opt_col;
+ int long_opt_col;
+ int doc_opt_col;
+ int opt_doc_col;
+ int header_col;
+ int usage_indent;
+ int rmargin;
+
+ int valid; /* True when the values in here are valid. */
+};
+
+/* This is a global variable, as user options are only ever read once. */
+static struct uparams uparams = {
+ DUP_ARGS, DUP_ARGS_NOTE,
+ SHORT_OPT_COL, LONG_OPT_COL, DOC_OPT_COL, OPT_DOC_COL, HEADER_COL,
+ USAGE_INDENT, RMARGIN,
+ 0
+};
+
+/* A particular uparam, and what the user name is. */
+struct uparam_name
+{
+ const char *name; /* User name. */
+ int is_bool; /* Whether it's `boolean'. */
+ size_t uparams_offs; /* Location of the (int) field in UPARAMS. */
+};
+
+/* The name-field mappings we know about. */
+static const struct uparam_name uparam_names[] =
+{
+ { "dup-args", 1, offsetof (struct uparams, dup_args) },
+ { "dup-args-note", 1, offsetof (struct uparams, dup_args_note) },
+ { "short-opt-col", 0, offsetof (struct uparams, short_opt_col) },
+ { "long-opt-col", 0, offsetof (struct uparams, long_opt_col) },
+ { "doc-opt-col", 0, offsetof (struct uparams, doc_opt_col) },
+ { "opt-doc-col", 0, offsetof (struct uparams, opt_doc_col) },
+ { "header-col", 0, offsetof (struct uparams, header_col) },
+ { "usage-indent", 0, offsetof (struct uparams, usage_indent) },
+ { "rmargin", 0, offsetof (struct uparams, rmargin) },
+ { 0 }
+};
+
+/* Read user options from the environment, and fill in UPARAMS appropiately. */
+static void
+fill_in_uparams (const struct argp_state *state)
+{
+ const char *var = getenv ("ARGP_HELP_FMT");
+
+#define SKIPWS(p) do { while (isspace (*p)) p++; } while (0);
+
+ if (var)
+ /* Parse var. */
+ while (*var)
+ {
+ SKIPWS (var);
+
+ if (isalpha (*var))
+ {
+ size_t var_len;
+ const struct uparam_name *un;
+ int unspec = 0, val = 0;
+ const char *arg = var;
+
+ while (isalnum (*arg) || *arg == '-' || *arg == '_')
+ arg++;
+ var_len = arg - var;
+
+ SKIPWS (arg);
+
+ if (*arg == '\0' || *arg == ',')
+ unspec = 1;
+ else if (*arg == '=')
+ {
+ arg++;
+ SKIPWS (arg);
+ }
+
+ if (unspec)
+ {
+ if (var[0] == 'n' && var[1] == 'o' && var[2] == '-')
+ {
+ val = 0;
+ var += 3;
+ var_len -= 3;
+ }
+ else
+ val = 1;
+ }
+ else if (isdigit (*arg))
+ {
+ val = atoi (arg);
+ while (isdigit (*arg))
+ arg++;
+ SKIPWS (arg);
+ }
+
+ for (un = uparam_names; un->name; un++)
+ if (strlen (un->name) == var_len
+ && strncmp (var, un->name, var_len) == 0)
+ {
+ if (unspec && !un->is_bool)
+ __argp_failure (state, 0, 0,
+ dgettext (state->root_argp->argp_domain, "\
+%.*s: ARGP_HELP_FMT parameter requires a value"),
+ (int) var_len, var);
+ else
+ *(int *)((char *)&uparams + un->uparams_offs) = val;
+ break;
+ }
+ if (! un->name)
+ __argp_failure (state, 0, 0,
+ dgettext (state->root_argp->argp_domain, "\
+%.*s: Unknown ARGP_HELP_FMT parameter"),
+ (int) var_len, var);
+
+ var = arg;
+ if (*var == ',')
+ var++;
+ }
+ else if (*var)
+ {
+ __argp_failure (state, 0, 0,
+ dgettext (state->root_argp->argp_domain,
+ "Garbage in ARGP_HELP_FMT: %s"), var);
+ break;
+ }
+ }
+}
+
+/* Returns true if OPT hasn't been marked invisible. Visibility only affects
+ whether OPT is displayed or used in sorting, not option shadowing. */
+#define ovisible(opt) (! ((opt)->flags & OPTION_HIDDEN))
+
+/* Returns true if OPT is an alias for an earlier option. */
+#define oalias(opt) ((opt)->flags & OPTION_ALIAS)
+
+/* Returns true if OPT is an documentation-only entry. */
+#define odoc(opt) ((opt)->flags & OPTION_DOC)
+
+/* Returns true if OPT is the end-of-list marker for a list of options. */
+#define oend(opt) __option_is_end (opt)
+
+/* Returns true if OPT has a short option. */
+#define oshort(opt) __option_is_short (opt)
+
+/*
+ The help format for a particular option is like:
+
+ -xARG, -yARG, --long1=ARG, --long2=ARG Documentation...
+
+ Where ARG will be omitted if there's no argument, for this option, or
+ will be surrounded by "[" and "]" appropiately if the argument is
+ optional. The documentation string is word-wrapped appropiately, and if
+ the list of options is long enough, it will be started on a separate line.
+ If there are no short options for a given option, the first long option is
+ indented slighly in a way that's supposed to make most long options appear
+ to be in a separate column.
+
+ For example, the following output (from ps):
+
+ -p PID, --pid=PID List the process PID
+ --pgrp=PGRP List processes in the process group PGRP
+ -P, -x, --no-parent Include processes without parents
+ -Q, --all-fields Don't elide unusable fields (normally if there's
+ some reason ps can't print a field for any
+ process, it's removed from the output entirely)
+ -r, --reverse, --gratuitously-long-reverse-option
+ Reverse the order of any sort
+ --session[=SID] Add the processes from the session SID (which
+ defaults to the sid of the current process)
+
+ Here are some more options:
+ -f ZOT, --foonly=ZOT Glork a foonly
+ -z, --zaza Snit a zar
+
+ -?, --help Give this help list
+ --usage Give a short usage message
+ -V, --version Print program version
+
+ The struct argp_option array for the above could look like:
+
+ {
+ {"pid", 'p', "PID", 0, "List the process PID"},
+ {"pgrp", OPT_PGRP, "PGRP", 0, "List processes in the process group PGRP"},
+ {"no-parent", 'P', 0, 0, "Include processes without parents"},
+ {0, 'x', 0, OPTION_ALIAS},
+ {"all-fields",'Q', 0, 0, "Don't elide unusable fields (normally"
+ " if there's some reason ps can't"
+ " print a field for any process, it's"
+ " removed from the output entirely)" },
+ {"reverse", 'r', 0, 0, "Reverse the order of any sort"},
+ {"gratuitously-long-reverse-option", 0, 0, OPTION_ALIAS},
+ {"session", OPT_SESS, "SID", OPTION_ARG_OPTIONAL,
+ "Add the processes from the session"
+ " SID (which defaults to the sid of"
+ " the current process)" },
+
+ {0,0,0,0, "Here are some more options:"},
+ {"foonly", 'f', "ZOT", 0, "Glork a foonly"},
+ {"zaza", 'z', 0, 0, "Snit a zar"},
+
+ {0}
+ }
+
+ Note that the last three options are automatically supplied by argp_parse,
+ unless you tell it not to with ARGP_NO_HELP.
+
+*/
+
+/* Returns true if CH occurs between BEG and END. */
+static int
+find_char (char ch, char *beg, char *end)
+{
+ while (beg < end)
+ if (*beg == ch)
+ return 1;
+ else
+ beg++;
+ return 0;
+}
+
+struct hol_cluster; /* fwd decl */
+
+struct hol_entry
+{
+ /* First option. */
+ const struct argp_option *opt;
+ /* Number of options (including aliases). */
+ unsigned num;
+
+ /* A pointers into the HOL's short_options field, to the first short option
+ letter for this entry. The order of the characters following this point
+ corresponds to the order of options pointed to by OPT, and there are at
+ most NUM. A short option recorded in a option following OPT is only
+ valid if it occurs in the right place in SHORT_OPTIONS (otherwise it's
+ probably been shadowed by some other entry). */
+ char *short_options;
+
+ /* Entries are sorted by their group first, in the order:
+ 1, 2, ..., n, 0, -m, ..., -2, -1
+ and then alphabetically within each group. The default is 0. */
+ int group;
+
+ /* The cluster of options this entry belongs to, or 0 if none. */
+ struct hol_cluster *cluster;
+
+ /* The argp from which this option came. */
+ const struct argp *argp;
+};
+
+/* A cluster of entries to reflect the argp tree structure. */
+struct hol_cluster
+{
+ /* A descriptive header printed before options in this cluster. */
+ const char *header;
+
+ /* Used to order clusters within the same group with the same parent,
+ according to the order in which they occurred in the parent argp's child
+ list. */
+ int index;
+
+ /* How to sort this cluster with respect to options and other clusters at the
+ same depth (clusters always follow options in the same group). */
+ int group;
+
+ /* The cluster to which this cluster belongs, or 0 if it's at the base
+ level. */
+ struct hol_cluster *parent;
+
+ /* The argp from which this cluster is (eventually) derived. */
+ const struct argp *argp;
+
+ /* The distance this cluster is from the root. */
+ int depth;
+
+ /* Clusters in a given hol are kept in a linked list, to make freeing them
+ possible. */
+ struct hol_cluster *next;
+};
+
+/* A list of options for help. */
+struct hol
+{
+ /* An array of hol_entry's. */
+ struct hol_entry *entries;
+ /* The number of entries in this hol. If this field is zero, the others
+ are undefined. */
+ unsigned num_entries;
+
+ /* A string containing all short options in this HOL. Each entry contains
+ pointers into this string, so the order can't be messed with blindly. */
+ char *short_options;
+
+ /* Clusters of entries in this hol. */
+ struct hol_cluster *clusters;
+};
+
+/* Create a struct hol from the options in ARGP. CLUSTER is the
+ hol_cluster in which these entries occur, or 0, if at the root. */
+static struct hol *
+make_hol (const struct argp *argp, struct hol_cluster *cluster)
+{
+ char *so;
+ const struct argp_option *o;
+ const struct argp_option *opts = argp->options;
+ struct hol_entry *entry;
+ unsigned num_short_options = 0;
+ struct hol *hol = malloc (sizeof (struct hol));
+
+ assert (hol);
+
+ hol->num_entries = 0;
+ hol->clusters = 0;
+
+ if (opts)
+ {
+ int cur_group = 0;
+
+ /* The first option must not be an alias. */
+ assert (! oalias (opts));
+
+ /* Calculate the space needed. */
+ for (o = opts; ! oend (o); o++)
+ {
+ if (! oalias (o))
+ hol->num_entries++;
+ if (oshort (o))
+ num_short_options++; /* This is an upper bound. */
+ }
+
+ hol->entries = malloc (sizeof (struct hol_entry) * hol->num_entries);
+ hol->short_options = malloc (num_short_options + 1);
+
+ assert (hol->entries && hol->short_options);
+
+ /* Fill in the entries. */
+ so = hol->short_options;
+ for (o = opts, entry = hol->entries; ! oend (o); entry++)
+ {
+ entry->opt = o;
+ entry->num = 0;
+ entry->short_options = so;
+ entry->group = cur_group =
+ o->group
+ ? o->group
+ : ((!o->name && !o->key)
+ ? cur_group + 1
+ : cur_group);
+ entry->cluster = cluster;
+ entry->argp = argp;
+
+ do
+ {
+ entry->num++;
+ if (oshort (o) && ! find_char (o->key, hol->short_options, so))
+ /* O has a valid short option which hasn't already been used.*/
+ *so++ = o->key;
+ o++;
+ }
+ while (! oend (o) && oalias (o));
+ }
+ *so = '\0'; /* null terminated so we can find the length */
+ }
+
+ return hol;
+}
+
+/* Add a new cluster to HOL, with the given GROUP and HEADER (taken from the
+ associated argp child list entry), INDEX, and PARENT, and return a pointer
+ to it. ARGP is the argp that this cluster results from. */
+static struct hol_cluster *
+hol_add_cluster (struct hol *hol, int group, const char *header, int index,
+ struct hol_cluster *parent, const struct argp *argp)
+{
+ struct hol_cluster *cl = malloc (sizeof (struct hol_cluster));
+ if (cl)
+ {
+ cl->group = group;
+ cl->header = header;
+
+ cl->index = index;
+ cl->parent = parent;
+ cl->argp = argp;
+ cl->depth = parent ? parent->depth + 1 : 0;
+
+ cl->next = hol->clusters;
+ hol->clusters = cl;
+ }
+ return cl;
+}
+
+/* Free HOL and any resources it uses. */
+static void
+hol_free (struct hol *hol)
+{
+ struct hol_cluster *cl = hol->clusters;
+
+ while (cl)
+ {
+ struct hol_cluster *next = cl->next;
+ free (cl);
+ cl = next;
+ }
+
+ if (hol->num_entries > 0)
+ {
+ free (hol->entries);
+ free (hol->short_options);
+ }
+
+ free (hol);
+}
+
+static int
+hol_entry_short_iterate (const struct hol_entry *entry,
+ int (*func)(const struct argp_option *opt,
+ const struct argp_option *real,
+ const char *domain, void *cookie),
+ const char *domain, void *cookie)
+{
+ unsigned nopts;
+ int val = 0;
+ const struct argp_option *opt, *real = entry->opt;
+ char *so = entry->short_options;
+
+ for (opt = real, nopts = entry->num; nopts > 0 && !val; opt++, nopts--)
+ if (oshort (opt) && *so == opt->key)
+ {
+ if (!oalias (opt))
+ real = opt;
+ if (ovisible (opt))
+ val = (*func)(opt, real, domain, cookie);
+ so++;
+ }
+
+ return val;
+}
+
+static int
+hol_entry_long_iterate (const struct hol_entry *entry,
+ int (*func)(const struct argp_option *opt,
+ const struct argp_option *real,
+ const char *domain, void *cookie),
+ const char *domain, void *cookie)
+{
+ unsigned nopts;
+ int val = 0;
+ const struct argp_option *opt, *real = entry->opt;
+
+ for (opt = real, nopts = entry->num; nopts > 0 && !val; opt++, nopts--)
+ if (opt->name)
+ {
+ if (!oalias (opt))
+ real = opt;
+ if (ovisible (opt))
+ val = (*func)(opt, real, domain, cookie);
+ }
+
+ return val;
+}
+
+/* Iterator that returns true for the first short option. */
+static int
+until_short (const struct argp_option *opt, const struct argp_option *real,
+ const char *domain, void *cookie)
+{
+ return oshort (opt) ? opt->key : 0;
+}
+
+/* Returns the first valid short option in ENTRY, or 0 if there is none. */
+static char
+hol_entry_first_short (const struct hol_entry *entry)
+{
+ return hol_entry_short_iterate (entry, until_short,
+ entry->argp->ar