diff --git a/newlib/ChangeLog b/newlib/ChangeLog index 2f9d41e83..a5003ebbd 100644 --- a/newlib/ChangeLog +++ b/newlib/ChangeLog @@ -1,3 +1,14 @@ +2008-02-29 Gregory Pietsch + + * 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. + 2008-02-21 Eric Blake Fix strtod("-0x", NULL). diff --git a/newlib/libc/include/getopt.h b/newlib/libc/include/getopt.h index 7179298ae..7861ec300 100644 --- a/newlib/libc/include/getopt.h +++ b/newlib/libc/include/getopt.h @@ -82,6 +82,7 @@ Gregory Pietsch's current e-mail address: gpietsch@comcast.net ****************************************************************************/ + #ifndef GETOPT_H #define GETOPT_H @@ -90,30 +91,46 @@ gpietsch@comcast.net /* include files needed by this include file */ /* macros defined by this include file */ -#define NO_ARG 0 -#define REQUIRED_ARG 1 -#define OPTIONAL_ARG 2 - -/* types defined by this include file */ - -struct option -{ - char *name; /* the name of the long option */ - int has_arg; /* one of the above macros */ - int *flag; /* determines if getopt_long() returns a - * value for a long option; if it is - * non-NULL, 0 is returned as a function - * value and the value of val is stored in - * the area pointed to by flag. Otherwise, - * val is returned. */ - int val; /* determines the value to return if flag is - * NULL. */ -}; +#define NO_ARG 0 +#define REQUIRED_ARG 1 +#define OPTIONAL_ARG 2 + /* The GETOPT_DATA_INITIALIZER macro is used to initialize a statically- + allocated variable of type struct getopt_data. */ +#define GETOPT_DATA_INITIALIZER {0,0,0,0,0} + /* These #defines are to keep the namespace clear... */ +#define getopt_r __getopt_r +#define getopt_long_r __getopt_long_r +#define getopt_long_only_r __getopt_long_only_r #ifdef __cplusplus extern "C" { -#endif + +#endif /* __cplusplus */ + +/* types defined by this include file */ + struct option + { + char *name; /* the name of the long option */ + int has_arg; /* one of the above macros */ + int *flag; /* determines if getopt_long() returns a + * value for a long option; if it is + * non-NULL, 0 is returned as a function + * value and the value of val is stored in + * the area pointed to by flag. Otherwise, + * val is returned. */ + int val; /* determines the value to return if flag is + * NULL. */ + + }; + + /* The getopt_data structure is for reentrancy. Its members are similar to + the externally-defined variables. */ + typedef struct getopt_data + { + char *optarg; + int optind, opterr, optopt, optwhere; + } getopt_data; /* externally-defined variables */ extern char *optarg; @@ -122,14 +139,35 @@ extern "C" extern int optopt; /* function prototypes */ - int _EXFUN (getopt, (int __argc, char *const __argv[], const char *__optstring)); - int _EXFUN (getopt_long, (int __argc, char *const __argv[], const char *__shortopts, const struct option *__longopts, int *__longind)); - int _EXFUN (getopt_long_only, (int __argc, char *const __argv[], const char *__shortopts, const struct option *__longopts, int *__longind)); + int _EXFUN (getopt, + (int __argc, char *const __argv[], const char *__optstring)); + + int _EXFUN (getopt_long, + (int __argc, char *const __argv[], const char *__shortopts, + const struct option * __longopts, int *__longind)); + + int _EXFUN (getopt_long_only, + (int __argc, char *const __argv[], const char *__shortopts, + const struct option * __longopts, int *__longind)); + + int _EXFUN (__getopt_r, + (int __argc, char *const __argv[], const char *__optstring, + struct getopt_data * __data)); + + int _EXFUN (__getopt_long_r, + (int __argc, char *const __argv[], const char *__shortopts, + const struct option * __longopts, int *__longind, + struct getopt_data * __data)); + + int _EXFUN (__getopt_long_only_r, + (int __argc, char *const __argv[], const char *__shortopts, + const struct option * __longopts, int *__longind, + struct getopt_data * __data)); #ifdef __cplusplus }; -#endif +#endif /* __cplusplus */ #endif /* GETOPT_H */ 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 #include @@ -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) { - return getopt_internal (argc, argv, shortopts, longopts, longind, 1); + 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, data); } /* end of file GETOPT.C */