diff options
Diffstat (limited to 'libshouldbeinlibc/argp-parse.c')
-rw-r--r-- | libshouldbeinlibc/argp-parse.c | 662 |
1 files changed, 0 insertions, 662 deletions
diff --git a/libshouldbeinlibc/argp-parse.c b/libshouldbeinlibc/argp-parse.c deleted file mode 100644 index 73b28f06..00000000 --- a/libshouldbeinlibc/argp-parse.c +++ /dev/null @@ -1,662 +0,0 @@ -/* Hierarchial argument parsing, layered over getopt - - Copyright (C) 1995, 1996 Free Software Foundation, Inc. - - Written by Miles Bader <miles@gnu.ai.mit.edu> - - This file is part of the GNU Hurd. - - The GNU Hurd is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2, or (at - your option) any later version. - - The GNU Hurd 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 - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <limits.h> -#include <getopt.h> -#include <cthreads.h> - -#include "argp.h" - -/* Getopt return values. */ -#define KEY_END (-1) /* The end of the options. */ -#define KEY_ARG 1 /* A non-option argument. */ -#define KEY_ERR '?' /* An error parsing the options. */ - -/* The meta-argument used to prevent any further arguments being interpreted - as options. */ -#define QUOTE "--" - -/* The number of bits we steal in a long-option value for our own use. */ -#define GROUP_BITS CHAR_BIT - -/* The number of bits available for the user value. */ -#define USER_BITS ((sizeof ((struct option *)0)->val * CHAR_BIT) - GROUP_BITS) -#define USER_MASK ((1 << USER_BITS) - 1) - -/* EZ alias for ARGP_ERR_UNKNOWN. */ -#define EBADKEY ARGP_ERR_UNKNOWN - -/* ---------------------------------------------------------------- */ -/* Default options. */ - -/* 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. */ -volatile int _argp_hang = 0; - -#define OPT_PROGNAME -2 -#define OPT_USAGE -3 -#define OPT_HANG -4 - -static const struct argp_option argp_default_options[] = -{ - {"help", '?', 0, 0, "Give this help list", -1}, - {"usage", OPT_USAGE, 0, 0, "Give a short usage message"}, - {"program-name",OPT_PROGNAME,"NAME", OPTION_HIDDEN, "Set the program name"}, - {"HANG", OPT_HANG, "SECS", OPTION_ARG_OPTIONAL | OPTION_HIDDEN, - "Hang for SECS seconds (default 3600)"}, - {0, 0} -}; - -static error_t -argp_default_parser (int key, char *arg, struct argp_state *state) -{ - switch (key) - { - case '?': - argp_state_help (state, state->out_stream, ARGP_HELP_STD_HELP); - break; - case OPT_USAGE: - argp_state_help (state, state->out_stream, - ARGP_HELP_USAGE | ARGP_HELP_EXIT_OK); - break; - - case OPT_PROGNAME: /* Set the program name. */ - program_invocation_name = arg; - program_invocation_short_name = rindex (arg, '/'); - if (program_invocation_short_name) - program_invocation_short_name++; - else - program_invocation_short_name = program_invocation_name; - - if ((state->flags & (ARGP_PARSE_ARGV0 | ARGP_NO_ERRS)) - == ARGP_PARSE_ARGV0) - state->argv[0] = arg; /* Update what getopt uses too. */ - - break; - - case OPT_HANG: - _argp_hang = atoi (arg ?: "3600"); - while (_argp_hang-- > 0) - sleep (1); - break; - - default: - return EBADKEY; - } - return 0; -} - -static const struct argp argp_default_argp = - {argp_default_options, &argp_default_parser}; - - -static const struct argp_option argp_version_options[] = -{ - {"version", 'V', 0, 0, "Print program version", -1}, - {0, 0} -}; - -static error_t -argp_version_parser (int key, char *arg, struct argp_state *state) -{ - switch (key) - { - case 'V': - if (argp_program_version_hook) - (*argp_program_version_hook) (state->out_stream, state); - else if (argp_program_version) - fprintf (state->out_stream, "%s\n", argp_program_version); - else - argp_error (state, "No version known!?"); - if (! (state->flags & ARGP_NO_EXIT)) - exit (0); - break; - default: - return EBADKEY; - } - return 0; -} - -static const struct argp argp_version_argp = - {argp_version_options, &argp_version_parser}; - -/* ---------------------------------------------------------------- */ - -/* Returns the offset into the getopt long options array LONG_OPTIONS of a - long option with called NAME, or -1 if none is found. Passing NULL as - NAME will return the number of options. */ -static int -find_long_option (struct option *long_options, const char *name) -{ - struct option *l = long_options; - while (l->name != NULL) - if (name != NULL && strcmp (l->name, name) == 0) - return l - long_options; - else - l++; - if (name == NULL) - return l - long_options; - else - return -1; -} - -/* ---------------------------------------------------------------- */ - -/* Used to regulate access to the getopt routines, which are non-reentrant. */ -static struct mutex getopt_lock = MUTEX_INITIALIZER; - -/* 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 () -{ - mutex_unlock (&getopt_lock); -} - -/* The state of a `group' during parsing. Each group corresponds to a - particular argp structure from the tree of such descending from the top - level argp passed to argp_parse. */ -struct group -{ - /* This group's parsing function. */ - argp_parser_t parser; - - /* Points to the point in SHORT_OPTS corresponding to the end of the short - options for this group. We use it to determine from which group a - particular short options is from. */ - char *short_end; - - /* The number of non-option args sucessfully handled by this parser. */ - unsigned args_processed; - - /* This group's parser's parent's group. */ - struct group *parent; - unsigned parent_index; /* And the our position in the parent. */ - - /* These fields are swapped into and out of the state structure when - calling this group's parser. */ - void *input, **child_inputs; - void *hook; -}; - -/* Parse the options strings in ARGC & ARGV according to the argp in - ARGP. FLAGS is one of the ARGP_ flags above. If OPTIND is - non-NULL, the index in ARGV of the first unparsed option is returned in - it. If an unknown option is present, EINVAL is returned; if some parser - routine returned a non-zero value, it is returned; otherwise 0 is - returned. */ -error_t -argp_parse (const struct argp *argp, int argc, char **argv, unsigned flags, - int *end_index, void *input) -{ - error_t err = 0; - /* True if we think using getopt is still useful; if false, then - remaining arguments are just passed verbatim with ARGP_KEY_ARG. This is - cleared whenever getopt returns KEY_END, but may be set again if the user - moves the next argument pointer backwards. */ - int try_getopt = 1; - /* If true, then err == EBADKEY is a result of a non-option argument failing - to be parsed (which in some cases isn't actually an error). */ - int arg_ebadkey = 0; - /* SHORT_OPTS is the getopt short options string for the union of all the - groups of options. */ - char *short_opts; - /* LONG_OPTS is the array of getop long option structures for the union of - all the groups of options. */ - struct option *long_opts; - /* States of the various parsing groups. */ - struct group *groups; - /* The end of the GROUPS array. */ - struct group *egroup; - /* A pointer for people to use for iteration over GROUPS. */ - struct group *group; - /* An vector containing storage for the CHILD_INPUTS field in all groups. */ - void **child_inputs; - /* State block supplied to parsing routines. */ - struct argp_state state = - { argp, argc, argv, 0, flags, err_stream: stderr, out_stream: stdout }; - - /* Call GROUP's parser with KEY and ARG, swapping any group-specific info - from STATE before calling, and back into state afterwards. If GROUP has - no parser, EBADKEY is returned. */ - error_t group_parse (struct group *group, int key, char *arg) - { - if (group->parser) - { - error_t err; - state.hook = group->hook; - state.input = group->input; - state.child_inputs = group->child_inputs; - state.arg_num = group->args_processed; - err = (*group->parser)(key, arg, &state); - group->hook = state.hook; - return err; - } - else - return EBADKEY; - } - - /* Parse the non-option argument ARG, at the current position. Returns - any error, and sets ARG_EBADKEY to true if return EBADKEY. */ - error_t process_arg (char *val, int *arg_ebadkey) - { - int index = state.next; - error_t err = EBADKEY; - - for (group = groups; group < egroup && err == EBADKEY; group++) - err = group_parse (group, ARGP_KEY_ARG, val); - - if (!err) - if (state.next >= index) - /* Remember that we successfully processed a non-option - argument -- but only if the user hasn't gotten tricky and set - the clock back. */ - (--group)->args_processed++; - else - /* The user wants to reparse some args, give getopt another try. */ - try_getopt = 1; - - if (err == EBADKEY) - *arg_ebadkey = 1; - - return err; - } - - /* Parse the option OPT (with argument ARG), at the current position. - Returns any error, and sets ARG_EBADKEY to true if it was actually an - argument and the parser returned EBADKEY. */ - error_t process_opt (int opt, char *val, int *arg_ebadkey) - { - /* The group key encoded in the high bits; 0 for short opts or - group_number + 1 for long opts. */ - int group_key = opt >> USER_BITS; - error_t err = EBADKEY; /* until otherwise asserted */ - - if (group_key == 0) - /* A short option. */ - { - /* By comparing OPT's position in SHORT_OPTS to the various - starting positions in each group's SHORT_END field, we can - determine which group OPT came from. */ - char *short_index = index (short_opts, opt); - if (short_index) - for (group = groups; group < egroup; group++) - if (group->short_end > short_index) - { - err = group_parse (group, opt, optarg); - break; - } - } - else - /* A long option. We use shifts instead of masking for extracting - the user value in order to preserve the sign. */ - err = - group_parse (&groups[group_key - 1], - (opt << GROUP_BITS) >> GROUP_BITS, optarg); - - return err; - } - - if (! (state.flags & ARGP_NO_HELP)) - /* Add our own options. */ - { - const struct argp **plist = alloca (3 * sizeof (struct argp *)); - struct argp *top_argp = alloca (sizeof (struct argp)); - - /* TOP_ARGP has no options, it just serves to group the user & default - argps. */ - bzero (top_argp, sizeof (*top_argp)); - top_argp->children = plist; - - if (state.argp) - *plist++ = state.argp; - *plist++ = &argp_default_argp; - if (argp_program_version || argp_program_version_hook) - *plist++ = &argp_version_argp; - *plist = 0; - - state.argp = top_argp; - } - - /* Find the merged set of getopt options, with keys appropiately prefixed. */ - { - char *short_end; - unsigned short_len = (state.flags & ARGP_NO_ARGS) ? 0 : 1; - struct option *long_end; - unsigned long_len = 0; - unsigned num_groups = 0; - unsigned num_child_inputs = 0; - - /* For ARGP, increments NUM_GROUPS by the total number of argp structures - descended from it, and SHORT_LEN & LONG_LEN by the maximum lengths of - the resulting merged getopt short options string and long-options - array, respectively. */ - void calc_lengths (const struct argp *argp) - { - const struct argp **children = argp->children; - const struct argp_option *opt = argp->options; - - if (opt || argp->parser) - { - num_groups++; - if (opt) - { - int num_opts = 0; - while (!_option_is_end (opt++)) - num_opts++; - short_len += num_opts * 3; /* opt + up to 2 `:'s */ - long_len += num_opts; - } - } - - if (children) - while (*children) - { - calc_lengths (*children++); - num_child_inputs++; - } - } - - /* Converts all options in ARGP (which is put in GROUP) and ancestors - into getopt options stored in SHORT_OPTS and LONG_OPTS; SHORT_END and - LONG_END are the points at which new options are added. Returns the - next unused group entry. */ - struct group *convert_options (const struct argp *argp, - struct group *parent, unsigned parent_index, - struct group *group) - { - /* REAL is the most recent non-alias value of OPT. */ - const struct argp_option *real = argp->options; - const struct argp **children = argp->children; - - if (real || argp->parser) - { - const struct argp_option *opt; - - if (real) - for (opt = real; !_option_is_end (opt); opt++) - { - if (! (opt->flags & OPTION_ALIAS)) - /* OPT isn't an alias, so we can use values from it. */ - real = opt; - - if (_option_is_short (opt)) - /* OPT can be used as a short option. */ - { - *short_end++ = opt->key; - if (real->arg) - { - *short_end++ = ':'; - if (real->flags & OPTION_ARG_OPTIONAL) - *short_end++ = ':'; - } - *short_end = '\0'; /* keep 0 terminated */ - } - - if (opt->name && find_long_option (long_opts, opt->name) < 0) - /* OPT can be used as a long option. */ - { - long_end->name = opt->name; - long_end->has_arg = - (real->arg - ? (real->flags & OPTION_ARG_OPTIONAL - ? optional_argument - : required_argument) - : no_argument); - long_end->flag = 0; - /* we add a disambiguating code to all the user's - values (which is removed before we actually call - the function to parse the value); this means that - the user loses use of the high 8 bits in all his - values (the sign of the lower bits is preserved - however)... */ - long_end->val = - ((opt->key | real->key) & USER_MASK) - + (((group - groups) + 1) << USER_BITS); - - /* Keep the LONG_OPTS list terminated. */ - (++long_end)->name = NULL; - } - } - - group->parser = argp->parser; - group->short_end = short_end; - group->args_processed = 0; - group->parent = parent; - group->parent_index = parent_index; - group->input = 0; - group->hook = 0; - group->child_inputs = 0; - - if (children) - /* Assign GROUP's CHILD_INPUTS field a slice from CHILD_INPUTS.*/ - { - unsigned num_children = 0; - while (children[num_children]) - num_children++; - group->child_inputs = child_inputs; - child_inputs += num_children; - } - - parent = group++; - } - else - parent = 0; - - if (children) - { - unsigned index = 0; - while (*children) - group = convert_options (*children++, parent, index++, group); - } - - return group; - } - - if (state.argp) - calc_lengths (state.argp); - - short_opts = short_end = alloca (short_len + 1); - if (state.flags & ARGP_IN_ORDER) - *short_end++ = '-'; - else if (state.flags & ARGP_NO_ARGS) - *short_end++ = '+'; - *short_end = '\0'; - - long_opts = long_end = alloca ((long_len + 1) * sizeof (struct option)); - long_end->name = NULL; - - groups = alloca ((num_groups + 1) * sizeof (struct group)); - - child_inputs = alloca (num_child_inputs * sizeof (void *)); - bzero (child_inputs, num_child_inputs * sizeof (void *)); - - if (state.argp) - egroup = convert_options (state.argp, 0, 0, groups); - else - egroup = groups; /* No parsers at all! */ - } - - /* Call each parser for the first time, giving it a chance to propagate - values to child parsers. */ - if (groups < egroup) - groups->input = input; - for (group = groups ; group < egroup && (!err || err == EBADKEY); group++) - { - if (group->parent) - /* If a child parser, get the initial input value from the parent. */ - group->input = group->parent->child_inputs[group->parent_index]; - err = group_parse (group, ARGP_KEY_INIT, 0); - } - if (err == EBADKEY) - err = 0; /* Some parser didn't understand. */ - - /* Getopt is (currently) non-reentrant. */ - mutex_lock (&getopt_lock); - - /* Tell getopt to initialize. */ - state.next = 0; - - if (state.flags & ARGP_NO_ERRS) - { - opterr = 0; - if (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. */ - state.argv--, state.argc++; - } - else - opterr = 1; /* Print error messages. */ - - if (state.argv == argv && argv[0]) - /* There's an argv[0]; use it for messages. */ - state.name = argv[0]; - else - state.name = program_invocation_name; - - /* Now use getopt on our coalesced options lists. */ - while (! err) - { - int opt; - - if (state.quoted && state.next < state.quoted) - /* The next argument pointer has been moved to before the quoted - region, so pretend we never saw the quoting `--', and give getopt - another chance. If the user hasn't removed it, getopt will just - process it again. */ - state.quoted = 0; - - if (try_getopt && !state.quoted) - /* Give getopt a chance to parse this. */ - { - optind = state.next; /* Put it back in OPTIND for getopt. */ - optopt = KEY_END; /* Distinguish KEY_ERR from a real option. */ - opt = getopt_long (state.argc, state.argv, short_opts, long_opts, 0); - state.next = optind; /* And see what getopt did. */ - - if (opt == KEY_END) - /* Getopt says there are no more options, so stop using - getopt; we'll continue if necessary on our own. */ - { - try_getopt = 0; - if (state.next > 1 - && strcmp (state.argv[state.next - 1], QUOTE) == 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. */ - state.quoted = state.next; - } - else if (opt == KEY_ERR && 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. */ - { - err = EBADKEY; - break; - } - } - else - opt = KEY_END; - - if (opt == KEY_END) - /* We're past what getopt considers the options. */ - if (state.next >= state.argc || (state.flags & ARGP_NO_ARGS)) - break; /* done */ - else - /* A non-option arg. */ - err = process_arg (state.argv[state.next++], &arg_ebadkey); - else if (opt == KEY_ARG) - /* A non-option argument; try each parser in turn. */ - err = process_arg (optarg, &arg_ebadkey); - else - err = process_opt (opt, optarg, &arg_ebadkey); - } - - mutex_unlock (&getopt_lock); - - if (err == EBADKEY && arg_ebadkey) - /* Suppress errors generated by unparsed arguments. */ - err = 0; - - if (!err) - if (state.next == state.argc) - /* We successfully parsed all arguments! Call all the parsers again, - just a few more times... */ - { - for (group = groups; group < egroup && (!err || err==EBADKEY); group++) - if (group->args_processed == 0) - err = group_parse (group, ARGP_KEY_NO_ARGS, 0); - for (group = groups; group < egroup && (!err || err==EBADKEY); group++) - err = group_parse (group, ARGP_KEY_END, 0); - if (err == EBADKEY) - err = 0; /* Some parser didn't understand. */ - } - else if (end_index) - /* Return any remaining arguments to the user. */ - *end_index = state.next; - else - /* No way to return the remaining arguments, they must be bogus. */ - { - if (!(state.flags & ARGP_NO_ERRS) && state.err_stream) - fprintf (state.err_stream, "%s: Too many arguments\n", state.name); - err = EBADKEY; - } - - /* Okay, we're all done, with either an error or success. We only call the - parsers once more, to indicate which one. */ - - if (err) - { - /* Maybe print an error message. */ - if (err == EBADKEY) - argp_state_help (&state, state.err_stream, ARGP_HELP_STD_ERR); - - /* Since we didn't exit, give each parser an error indication. */ - for (group = groups; group < egroup; group++) - group_parse (group, ARGP_KEY_ERROR, 0); - } - else - /* Do final cleanup, including propagating back values from parsers. */ - { - /* We pass over the groups in reverse order so that child groups are - given a chance to do there processing before passing back a value to - the parent. */ - for (group = egroup - 1 - ; group >= groups && (!err || err == EBADKEY) - ; group--) - err = group_parse (group, ARGP_KEY_SUCCESS, 0); - if (err == EBADKEY) - err = 0; /* Some parser didn't understand. */ - } - - if (err == EBADKEY) - err = EINVAL; - - return err; -} |