diff options
author | Jeff Johnston <jjohnstn@redhat.com> | 2008-03-01 00:11:57 +0300 |
---|---|---|
committer | Jeff Johnston <jjohnstn@redhat.com> | 2008-03-01 00:11:57 +0300 |
commit | 76ff710cfaa54aa7a85b15d2d2b0303a53afe83d (patch) | |
tree | 8444c7c9f61800989d7c913ec682e3b0bbe46cb7 /newlib/libc/stdlib | |
parent | 86a4b0c733dab174b9eb1b556b881f565d7bd819 (diff) |
2008-02-29 Gregory Pietsch <gpietsch@comcast.net>
* libc/stdlib/getopt.c (getopt_internal): Rewrite to accept
data area so as to support reentrant calls. Change all callers
to fill in data area with global values and restore any changes
to the global values after call.
(__getopt_r, __getopt_long_r, __getopt_long_only_r): New routines
to support reentrancy that add a data area argument.
* libc/include/getopt.h: Add new _r routines and provide macros
so they can be called with using double-underscores.
Diffstat (limited to 'newlib/libc/stdlib')
-rw-r--r-- | newlib/libc/stdlib/getopt.c | 424 |
1 files changed, 249 insertions, 175 deletions
diff --git a/newlib/libc/stdlib/getopt.c b/newlib/libc/stdlib/getopt.c index 09952db19..eb0a08284 100644 --- a/newlib/libc/stdlib/getopt.c +++ b/newlib/libc/stdlib/getopt.c @@ -83,6 +83,7 @@ Gregory Pietsch's current e-mail address: gpietsch@comcast.net ****************************************************************************/ + /* include files */ #include <stdio.h> #include <stdlib.h> @@ -100,16 +101,19 @@ typedef enum GETOPT_ORDERING_T } GETOPT_ORDERING_T; /* globally-defined variables */ -char *optarg = NULL; +char *optarg = 0; int optind = 0; int opterr = 1; int optopt = '?'; +/* static variables */ +static int optwhere = 0; + /* functions */ /* reverse_argv_elements: reverses num elements starting at argv */ static void -reverse_argv_elements (char ** argv, int num) +reverse_argv_elements (char **argv, int num) { int i; char *tmp; @@ -126,276 +130,346 @@ reverse_argv_elements (char ** argv, int num) static void permute (char *const argv[], int len1, int len2) { - reverse_argv_elements ((char **)argv, len1); - reverse_argv_elements ((char **)argv, len1 + len2); - reverse_argv_elements ((char **)argv, len2); + reverse_argv_elements ((char **) argv, len1); + reverse_argv_elements ((char **) argv, len1 + len2); + reverse_argv_elements ((char **) argv, len2); } /* is_option: is this argv-element an option or the end of the option list? */ static int is_option (char *argv_element, int only) { - return ((argv_element == NULL) - || (argv_element[0] == '-') || (only && argv_element[0] == '+')); + return ((argv_element == 0) + || (argv_element[0] == '-') || (only && argv_element[0] == '+')); +} + +/* read_globals: read the values from the globals into a getopt_data + structure */ +static void +read_globals (struct getopt_data *data) +{ + data->optarg = optarg; + data->optind = optind; + data->opterr = opterr; + data->optopt = optopt; + data->optwhere = optwhere; +} + +/* write_globals: write the values into the globals from a getopt_data + structure */ +static void +write_globals (struct getopt_data *data) +{ + optarg = data->optarg; + optind = data->optind; + opterr = data->opterr; + optopt = data->optopt; + optwhere = data->optwhere; } /* getopt_internal: the function that does all the dirty work */ static int getopt_internal (int argc, char *const argv[], const char *shortopts, - const struct option *longopts, int *longind, int only) + const struct option *longopts, int *longind, int only, + struct getopt_data *data) { GETOPT_ORDERING_T ordering = PERMUTE; - static size_t optwhere = 0; size_t permute_from = 0; int num_nonopts = 0; int optindex = 0; size_t match_chars = 0; - char *possible_arg = NULL; + char *possible_arg = 0; int longopt_match = -1; int has_arg = -1; - char *cp = NULL; + char *cp = 0; int arg_next = 0; /* first, deal with silly parameters and easy stuff */ - if (argc == 0 || argv == NULL || (shortopts == NULL && longopts == NULL)) + if (argc == 0 || argv == 0 || (shortopts == 0 && longopts == 0) + || data->optind >= argc || argv[data->optind] == 0) return EOF; - if (optind >= argc || argv[optind] == NULL) - return EOF; - if (strcmp (argv[optind], "--") == 0) + if (strcmp (argv[data->optind], "--") == 0) { - optind++; + data->optind++; return EOF; } + /* if this is our first time through */ - if (optind == 0) - optind = optwhere = 1; + if (data->optind == 0) + data->optind = data->optwhere = 1; /* define ordering */ - if (shortopts != NULL && (*shortopts == '-' || *shortopts == '+')) + if (shortopts != 0 && (*shortopts == '-' || *shortopts == '+')) { ordering = (*shortopts == '-') ? RETURN_IN_ORDER : REQUIRE_ORDER; shortopts++; } else - ordering = (getenv ("POSIXLY_CORRECT") != NULL) ? REQUIRE_ORDER : PERMUTE; + ordering = (getenv ("POSIXLY_CORRECT") != 0) ? REQUIRE_ORDER : PERMUTE; /* * based on ordering, find our next option, if we're at the beginning of * one */ - if (optwhere == 1) + if (data->optwhere == 1) { switch (ordering) - { - case PERMUTE: - permute_from = optind; - num_nonopts = 0; - while (!is_option (argv[optind], only)) - { - optind++; - num_nonopts++; - } - if (argv[optind] == NULL) - { - /* no more options */ - optind = permute_from; - return EOF; - } - else if (strcmp (argv[optind], "--") == 0) - { - /* no more options, but have to get `--' out of the way */ - permute (argv + permute_from, num_nonopts, 1); - optind = permute_from + 1; - return EOF; - } - break; - case RETURN_IN_ORDER: - if (!is_option (argv[optind], only)) - { - optarg = argv[optind++]; - return (optopt = 1); - } - break; - case REQUIRE_ORDER: - if (!is_option (argv[optind], only)) - return EOF; - break; - } + { + default: /* shouldn't happen */ + case PERMUTE: + permute_from = data->optind; + num_nonopts = 0; + while (!is_option (argv[data->optind], only)) + { + data->optind++; + num_nonopts++; + } + if (argv[data->optind] == 0) + { + /* no more options */ + data->optind = permute_from; + return EOF; + } + else if (strcmp (argv[data->optind], "--") == 0) + { + /* no more options, but have to get `--' out of the way */ + permute (argv + permute_from, num_nonopts, 1); + data->optind = permute_from + 1; + return EOF; + } + break; + case RETURN_IN_ORDER: + if (!is_option (argv[data->optind], only)) + { + data->optarg = argv[data->optind++]; + return (data->optopt = 1); + } + break; + case REQUIRE_ORDER: + if (!is_option (argv[data->optind], only)) + return EOF; + break; + } } /* we've got an option, so parse it */ /* first, is it a long option? */ - if (longopts != NULL - && (memcmp (argv[optind], "--", 2) == 0 - || (only && argv[optind][0] == '+')) && optwhere == 1) + if (longopts != 0 + && (memcmp (argv[data->optind], "--", 2) == 0 + || (only && argv[data->optind][0] == '+')) && data->optwhere == 1) { /* handle long options */ - if (memcmp (argv[optind], "--", 2) == 0) - optwhere = 2; + if (memcmp (argv[data->optind], "--", 2) == 0) + data->optwhere = 2; longopt_match = -1; - possible_arg = strchr (argv[optind] + optwhere, '='); - if (possible_arg == NULL) - { - /* no =, so next argv might be arg */ - match_chars = strlen (argv[optind]); - possible_arg = argv[optind] + match_chars; - match_chars = match_chars - optwhere; - } + possible_arg = strchr (argv[data->optind] + data->optwhere, '='); + if (possible_arg == 0) + { + /* no =, so next argv might be arg */ + match_chars = strlen (argv[data->optind]); + possible_arg = argv[data->optind] + match_chars; + match_chars = match_chars - data->optwhere; + } else - match_chars = (possible_arg - argv[optind]) - optwhere; - for (optindex = 0; longopts[optindex].name != NULL; optindex++) - { - if (memcmp (argv[optind] + optwhere, - longopts[optindex].name, match_chars) == 0) - { - /* do we have an exact match? */ - if (match_chars == (int) (strlen (longopts[optindex].name))) - { - longopt_match = optindex; - break; - } - /* do any characters match? */ - else - { - if (longopt_match < 0) - longopt_match = optindex; - else - { - /* we have ambiguous options */ - if (opterr) - fprintf (stderr, "%s: option `%s' is ambiguous " - "(could be `--%s' or `--%s')\n", - argv[0], - argv[optind], - longopts[longopt_match].name, - longopts[optindex].name); - return (optopt = '?'); - } - } - } - } + match_chars = (possible_arg - argv[data->optind]) - data->optwhere; + for (optindex = 0; longopts[optindex].name != 0; ++optindex) + { + if (memcmp + (argv[data->optind] + data->optwhere, longopts[optindex].name, + match_chars) == 0) + { + /* do we have an exact match? */ + if (match_chars == (int) (strlen (longopts[optindex].name))) + { + longopt_match = optindex; + break; + } + /* do any characters match? */ + else + { + if (longopt_match < 0) + longopt_match = optindex; + else + { + /* we have ambiguous options */ + if (data->opterr) + fprintf (stderr, "%s: option `%s' is ambiguous " + "(could be `--%s' or `--%s')\n", + argv[0], + argv[data->optind], + longopts[longopt_match].name, + longopts[optindex].name); + return (data->optopt = '?'); + } + } + } + } if (longopt_match >= 0) - has_arg = longopts[longopt_match].has_arg; + has_arg = longopts[longopt_match].has_arg; } + /* if we didn't find a long option, is it a short option? */ - if (longopt_match < 0 && shortopts != NULL) + if (longopt_match < 0 && shortopts != 0) { - cp = strchr (shortopts, argv[optind][optwhere]); - if (cp == NULL) - { - /* couldn't find option in shortopts */ - if (opterr) - fprintf (stderr, - "%s: invalid option -- `-%c'\n", - argv[0], argv[optind][optwhere]); - optwhere++; - if (argv[optind][optwhere] == '\0') - { - optind++; - optwhere = 1; - } - return (optopt = '?'); - } + cp = strchr (shortopts, argv[data->optind][data->optwhere]); + if (cp == 0) + { + /* couldn't find option in shortopts */ + if (data->opterr) + fprintf (stderr, + "%s: invalid option -- `-%c'\n", + argv[0], argv[data->optind][data->optwhere]); + data->optwhere++; + if (argv[data->optind][data->optwhere] == '\0') + { + data->optind++; + data->optwhere = 1; + } + return (data->optopt = '?'); + } has_arg = ((cp[1] == ':') - ? ((cp[2] == ':') ? OPTIONAL_ARG : REQUIRED_ARG) : NO_ARG); - possible_arg = argv[optind] + optwhere + 1; - optopt = *cp; + ? ((cp[2] == ':') ? OPTIONAL_ARG : REQUIRED_ARG) : NO_ARG); + possible_arg = argv[data->optind] + data->optwhere + 1; + data->optopt = *cp; } - /* get argument and reset optwhere */ + + /* get argument and reset data->optwhere */ arg_next = 0; switch (has_arg) { case OPTIONAL_ARG: if (*possible_arg == '=') - possible_arg++; - optarg = (*possible_arg != '\0') ? possible_arg : NULL; - optwhere = 1; + possible_arg++; + data->optarg = (*possible_arg != '\0') ? possible_arg : 0; + data->optwhere = 1; break; case REQUIRED_ARG: if (*possible_arg == '=') - possible_arg++; + possible_arg++; if (*possible_arg != '\0') - { - optarg = possible_arg; - optwhere = 1; - } - else if (optind + 1 >= argc) - { - if (opterr) - { - fprintf (stderr, "%s: argument required for option `", argv[0]); - if (longopt_match >= 0) - fprintf (stderr, "--%s'\n", longopts[longopt_match].name); - else - fprintf (stderr, "-%c'\n", *cp); - } - optind++; - return (optopt = ':'); - } + { + data->optarg = possible_arg; + data->optwhere = 1; + } + else if (data->optind + 1 >= argc) + { + if (data->opterr) + { + fprintf (stderr, "%s: argument required for option `", argv[0]); + if (longopt_match >= 0) + fprintf (stderr, "--%s'\n", longopts[longopt_match].name); + else + fprintf (stderr, "-%c'\n", *cp); + } + data->optind++; + return (data->optopt = ':'); + } else - { - optarg = argv[optind + 1]; - arg_next = 1; - optwhere = 1; - } + { + data->optarg = argv[data->optind + 1]; + arg_next = 1; + data->optwhere = 1; + } break; + default: /* shouldn't happen */ case NO_ARG: if (longopt_match < 0) - { - optwhere++; - if (argv[optind][optwhere] == '\0') - optwhere = 1; - } + { + data->optwhere++; + if (argv[data->optind][data->optwhere] == '\0') + data->optwhere = 1; + } else - optwhere = 1; - optarg = NULL; + data->optwhere = 1; + data->optarg = 0; break; } - /* do we have to permute or otherwise modify optind? */ - if (ordering == PERMUTE && optwhere == 1 && num_nonopts != 0) + /* do we have to permute or otherwise modify data->optind? */ + if (ordering == PERMUTE && data->optwhere == 1 && num_nonopts != 0) { permute (argv + permute_from, num_nonopts, 1 + arg_next); - optind = permute_from + 1 + arg_next; + data->optind = permute_from + 1 + arg_next; } - else if (optwhere == 1) - optind = optind + 1 + arg_next; + else if (data->optwhere == 1) + data->optind = data->optind + 1 + arg_next; /* finally return */ if (longopt_match >= 0) { - if (longind != NULL) - *longind = longopt_match; - if (longopts[longopt_match].flag != NULL) - { - *(longopts[longopt_match].flag) = longopts[longopt_match].val; - return 0; - } + if (longind != 0) + *longind = longopt_match; + if (longopts[longopt_match].flag != 0) + { + *(longopts[longopt_match].flag) = longopts[longopt_match].val; + return 0; + } else - return longopts[longopt_match].val; + return longopts[longopt_match].val; } else - return optopt; + return data->optopt; } int getopt (int argc, char *const argv[], const char *optstring) { - return getopt_internal (argc, argv, optstring, NULL, NULL, 0); + struct getopt_data data; + int r; + + read_globals (&data); + r = getopt_internal (argc, argv, optstring, 0, 0, 0, &data); + write_globals (&data); + return r; } int getopt_long (int argc, char *const argv[], const char *shortopts, - const struct option *longopts, int *longind) + const struct option *longopts, int *longind) { - return getopt_internal (argc, argv, shortopts, longopts, longind, 0); + struct getopt_data data; + int r; + + read_globals (&data); + r = getopt_internal (argc, argv, shortopts, longopts, longind, 0, &data); + write_globals (&data); + return r; } int getopt_long_only (int argc, char *const argv[], const char *shortopts, - const struct option *longopts, int *longind) + const struct option *longopts, int *longind) +{ + struct getopt_data data; + int r; + + read_globals (&data); + r = getopt_internal (argc, argv, shortopts, longopts, longind, 1, &data); + write_globals (&data); + return r; +} + +int +__getopt_r (int argc, char *const argv[], const char *optstring, + struct getopt_data *data) +{ + return getopt_internal (argc, argv, optstring, 0, 0, 0, data); +} + +int +__getopt_long_r (int argc, char *const argv[], const char *shortopts, + const struct option *longopts, int *longind, + struct getopt_data *data) +{ + return getopt_internal (argc, argv, shortopts, longopts, longind, 0, data); +} + +int +__getopt_long_only_r (int argc, char *const argv[], const char *shortopts, + const struct option *longopts, int *longind, + struct getopt_data *data) { - return getopt_internal (argc, argv, shortopts, longopts, longind, 1); + return getopt_internal (argc, argv, shortopts, longopts, longind, 1, data); } /* end of file GETOPT.C */ |