/* Hierarchial argument parsing, layered over getopt
- Copyright (C) 1995-2000, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1995-2019 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Written by Miles Bader <miles@gnu.ai.mit.edu>.
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 USA. */
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
+/* AIX requires this to be the first thing in the file. */
+#ifndef __GNUC__
+# if HAVE_ALLOCA_H || defined _LIBC
+# include <alloca.h>
+# else
+# ifdef _AIX
+#pragma alloca
+# else
+# ifndef alloca /* predefined by HP cc +Olibcalls */
+char *alloca ();
+# endif
+# endif
+# endif
+#endif
+
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <getopt.h>
+#include <getopt_int.h>
#ifndef _
/* This is for other GNU distributions with internationalized messages.
# ifdef _LIBC
# undef dgettext
# define dgettext(domain, msgid) \
- INTUSE(__dcgettext) (domain, msgid, LC_MESSAGES)
+ __dcgettext (domain, msgid, LC_MESSAGES)
# endif
# else
# define dgettext(domain, msgid) (msgid)
# define N_(msgid) (msgid)
#endif
-#if _LIBC - 0
-#include <bits/libc-lock.h>
-#else
-#ifdef HAVE_CTHREADS_H
-#include <cthreads.h>
-#endif
-#endif /* _LIBC */
-
-#include "argp.h"
+#include <argp.h>
#include "argp-namefrob.h"
/* Getopt return values. */
/* When argp is given the --HANG switch, _ARGP_HANG is set and argp will sleep
for one second intervals, decrementing _ARGP_HANG until it's zero. Thus
you can force the program to continue by attaching a debugger and setting
- it to 0 yourself.
-
- XXX This variable used to be exported. But there seems to be no
- need, at least not inside libc. */
-#ifdef _LIBC
-static
-#endif
-volatile int _argp_hang;
+ it to 0 yourself. */
+static volatile int _argp_hang;
#define OPT_PROGNAME -2
#define OPT_USAGE -3
static const struct argp_option argp_default_options[] =
{
- {"help", '?', 0, 0, N_("Give this help list"), -1},
+ {"help", '?', 0, 0, N_("Give this help list"), -1},
{"usage", OPT_USAGE, 0, 0, N_("Give a short usage message")},
- {"program-name",OPT_PROGNAME,"NAME", OPTION_HIDDEN, N_("Set the program name")},
- {"HANG", OPT_HANG, "SECS", OPTION_ARG_OPTIONAL | OPTION_HIDDEN,
- N_("Hang for SECS seconds (default 3600)")},
+ {"program-name",OPT_PROGNAME, N_("NAME"), OPTION_HIDDEN,
+ N_("Set the program name")},
+ {"HANG", OPT_HANG, N_("SECS"), OPTION_ARG_OPTIONAL | OPTION_HIDDEN,
+ N_("Hang for SECS seconds (default 3600)")},
{0, 0}
};
break;
case OPT_PROGNAME: /* Set the program name. */
+#if defined _LIBC || HAVE_DECL_PROGRAM_INVOCATION_NAME
program_invocation_name = arg;
-
+#endif
/* [Note that some systems only have PROGRAM_INVOCATION_SHORT_NAME (aka
__PROGNAME), in which case, PROGRAM_INVOCATION_NAME is just defined
to be that, so we have to be a bit careful here.] */
- arg = strrchr (arg, '/');
- if (arg)
- program_invocation_short_name = arg + 1;
- else
- program_invocation_short_name = program_invocation_name;
/* Update what we use for messages. */
- state->name = program_invocation_short_name;
+ state->name = strrchr (arg, '/');
+ if (state->name)
+ state->name++;
+ else
+ state->name = arg;
+
+#if defined _LIBC || HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME
+ program_invocation_short_name = state->name;
+#endif
if ((state->flags & (ARGP_PARSE_ARGV0 | ARGP_NO_ERRS))
== ARGP_PARSE_ARGV0)
/* Update what getopt uses too. */
- state->argv[0] = program_invocation_name;
+ state->argv[0] = arg;
break;
\f
static const struct argp_option argp_version_options[] =
{
- {"version", 'V', 0, 0, N_("Print program version"), -1},
+ {"version", 'V', 0, 0, N_("Print program version"), -1},
{0, 0}
};
else
return -1;
}
-\f
-/* If we can, we regulate access to getopt, which is non-reentrant, with a
- mutex. Since the case we're trying to guard against is two different
- threads interfering, and it's possible that someone might want to call
- argp_parse recursively (they're careful), we use a recursive lock if
- possible. */
-
-#if _LIBC - 0
-
-__libc_lock_define_initialized_recursive (static, getopt_lock)
-#define LOCK_GETOPT __libc_lock_lock_recursive (getopt_lock)
-#define UNLOCK_GETOPT __libc_lock_unlock_recursive (getopt_lock)
-
-#else /* !_LIBC */
-#ifdef HAVE_CTHREADS_H
-
-static struct mutex getopt_lock = MUTEX_INITIALIZER;
-#define LOCK_GETOPT mutex_lock (&getopt_lock)
-#define UNLOCK_GETOPT mutex_unlock (&getopt_lock)
-
-#else /* !HAVE_CTHREADS_H */
-#define LOCK_GETOPT (void)0
-#define UNLOCK_GETOPT (void)0
-
-#endif /* HAVE_CTHREADS_H */
-#endif /* _LIBC */
-
-/* This hack to allow programs that know what's going on to call argp
- recursively. If someday argp is changed not to use the non-reentrant
- getopt interface, we can get rid of this shit. XXX */
-void
-_argp_unlock_xxx (void)
-{
- UNLOCK_GETOPT;
-}
\f
/* The state of a `group' during parsing. Each group corresponds to a
particular argp structure from the tree of such descending from the top
/* LONG_OPTS is the array of getop long option structures for the union of
all the groups of options. */
struct option *long_opts;
+ /* OPT_DATA is the getopt data used for the re-entrant getopt. */
+ struct _getopt_data opt_data;
/* States of the various parsing groups. */
struct group *groups;
values (the sign of the lower bits is preserved
however)... */
cvt->long_end->val =
- ((opt->key | real->key) & USER_MASK)
+ ((opt->key ? opt->key : real->key) & USER_MASK)
+ (((group - cvt->parser->groups) + 1) << USER_BITS);
/* Keep the LONG_OPTS list terminated. */
if (children)
/* Assign GROUP's CHILD_INPUTS field some space from
- CVT->child_inputs_end.*/
+ CVT->child_inputs_end.*/
{
unsigned num_children = 0;
while (children[num_children].argp)
return group;
}
-/* Find the merged set of getopt options, with keys appropiately prefixed. */
+/* Find the merged set of getopt options, with keys appropriately prefixed. */
static void
parser_convert (struct parser *parser, const struct argp *argp, int flags)
{
error_t err = 0;
struct group *group;
struct parser_sizes szs;
+ struct _getopt_data opt_data = _GETOPT_DATA_INITIALIZER;
szs.short_len = (flags & ARGP_NO_ARGS) ? 0 : 1;
szs.long_len = 0;
parser->child_inputs = parser->storage + GLEN;
parser->long_opts = parser->storage + GLEN + CLEN;
parser->short_opts = parser->storage + GLEN + CLEN + LLEN;
+ parser->opt_data = opt_data;
memset (parser->child_inputs, 0, szs.num_child_inputs * sizeof (void *));
parser_convert (parser, argp, flags);
if (err)
return err;
- /* Getopt is (currently) non-reentrant. */
- LOCK_GETOPT;
-
if (parser->state.flags & ARGP_NO_ERRS)
{
- opterr = 0;
+ parser->opt_data.opterr = 0;
if (parser->state.flags & ARGP_PARSE_ARGV0)
/* getopt always skips ARGV[0], so we have to fake it out. As long
as OPTERR is 0, then it shouldn't actually try to access it. */
parser->state.argv--, parser->state.argc++;
}
else
- opterr = 1; /* Print error messages. */
+ parser->opt_data.opterr = 1; /* Print error messages. */
if (parser->state.argv == argv && argv[0])
/* There's an argv[0]; use it for messages. */
parser->state.name = short_name ? short_name + 1 : argv[0];
}
else
- parser->state.name = program_invocation_short_name;
+ parser->state.name = __argp_short_program_name ();
return 0;
}
{
struct group *group;
- UNLOCK_GETOPT;
-
if (err == EBADKEY && arg_ebadkey)
/* Suppress errors generated by unparsed arguments. */
err = 0;
for (group = parser->groups; group < parser->egroup; group++)
if (group->short_end > short_index)
{
- err = group_parse (group, &parser->state, opt, optarg);
+ err = group_parse (group, &parser->state, opt,
+ parser->opt_data.optarg);
break;
}
}
the user value in order to preserve the sign. */
err =
group_parse (&parser->groups[group_key - 1], &parser->state,
- (opt << GROUP_BITS) >> GROUP_BITS, optarg);
+ (opt << GROUP_BITS) >> GROUP_BITS,
+ parser->opt_data.optarg);
if (err == EBADKEY)
/* At least currently, an option not recognized is an error in the
if (parser->try_getopt && !parser->state.quoted)
/* Give getopt a chance to parse this. */
{
- optind = parser->state.next; /* Put it back in OPTIND for getopt. */
- optopt = KEY_END; /* Distinguish KEY_ERR from a real option. */
+ /* Put it back in OPTIND for getopt. */
+ parser->opt_data.optind = parser->state.next;
+ /* Distinguish KEY_ERR from a real option. */
+ parser->opt_data.optopt = KEY_END;
if (parser->state.flags & ARGP_LONG_ONLY)
- opt = getopt_long_only (parser->state.argc, parser->state.argv,
- parser->short_opts, parser->long_opts, 0);
+ opt = _getopt_long_only_r (parser->state.argc, parser->state.argv,
+ parser->short_opts, parser->long_opts, 0,
+ &parser->opt_data);
else
- opt = getopt_long (parser->state.argc, parser->state.argv,
- parser->short_opts, parser->long_opts, 0);
- parser->state.next = optind; /* And see what getopt did. */
+ opt = _getopt_long_r (parser->state.argc, parser->state.argv,
+ parser->short_opts, parser->long_opts, 0,
+ &parser->opt_data);
+ /* And see what getopt did. */
+ parser->state.next = parser->opt_data.optind;
if (opt == KEY_END)
/* Getopt says there are no more options, so stop using
parser->try_getopt = 0;
if (parser->state.next > 1
&& strcmp (parser->state.argv[parser->state.next - 1], QUOTE)
- == 0)
+ == 0)
/* Not only is this the end of the options, but it's a
`quoted' region, which may have args that *look* like
options, so we definitely shouldn't try to use getopt past
here, whatever happens. */
parser->state.quoted = parser->state.next;
}
- else if (opt == KEY_ERR && optopt != KEY_END)
+ else if (opt == KEY_ERR && parser->opt_data.optopt != KEY_END)
/* KEY_ERR can have the same value as a valid user short
option, but in the case of a real error, getopt sets OPTOPT
to the offending character, which can never be KEY_END. */
/* A non-option arg; simulate what getopt might have done. */
{
opt = KEY_ARG;
- optarg = parser->state.argv[parser->state.next++];
+ parser->opt_data.optarg = parser->state.argv[parser->state.next++];
}
}
if (opt == KEY_ARG)
/* A non-option argument; try each parser in turn. */
- err = parser_parse_arg (parser, optarg);
+ err = parser_parse_arg (parser, parser->opt_data.optarg);
else
- err = parser_parse_opt (parser, opt, optarg);
+ err = parser_parse_opt (parser, opt, parser->opt_data.optarg);
if (err == EBADKEY)
*arg_ebadkey = (opt == KEY_END || opt == KEY_ARG);