diff options
Diffstat (limited to 'src/getopt.c')
-rw-r--r-- | src/getopt.c | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/src/getopt.c b/src/getopt.c new file mode 100644 index 0000000..321dd9f --- /dev/null +++ b/src/getopt.c @@ -0,0 +1,199 @@ +/* $Id: getopt.c 4022 2008-03-31 06:11:07Z rra $ + * + * Replacement implementation of getopt. + * + * This is a replacement implementation for getopt based on the my_getopt + * distribution by Benjamin Sittler. Only the getopt interface is included, + * since remctl doesn't use GNU long options, and the code has been rearranged + * and reworked somewhat to fit with the remctl coding style. + * + * Copyright 1997, 2000, 2001, 2002 Benjamin Sittler + * Copyright 2008 Russ Allbery <rra@stanford.edu> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <config.h> +#include <portable/system.h> +#include <portable/getopt.h> + +/* + * If we're running the test suite, rename getopt and the global variables to + * avoid conflicts with the system version. + */ +#if TESTING +# define getopt test_getopt +int test_getopt(int, char **, const char *); +# define optind test_optind +# define opterr test_opterr +# define optopt test_optopt +# define optarg test_optarg +#endif + +/* Initialize global interface variables. */ +int optind = 1; +int opterr = 1; +int optopt = 0; +char *optarg = NULL; + +/* + * This is the plain old UNIX getopt, with GNU-style extensions. If you're + * porting some piece of UNIX software, this is all you need. It supports + * GNU-style permutation and optional arguments, but does not support the GNU + * -W extension. + * + * This function is not re-entrant or thread-safe, has static variables, and + * generally isn't a great interface, but normally you only call it once. + */ +int +getopt(int argc, char *argv[], const char *optstring) +{ + const char *p; + size_t offset = 0; + char mode = '\0'; + int colon_mode = 0; + int option = -1; + + /* Holds the current position in the parameter being parsed. */ + static int charind = 0; + + /* + * By default, getopt permutes argv as it scans and leaves all non-options + * at the end. This can be changed with the first character of optstring + * or the environment variable POSIXLY_CORRECT. With a first character of + * '+' or when POSIXLY_CORRECT is set, option processing stops at the + * first non-option. If the first character is '-', each non-option argv + * element is handled as if it were the argument of an option with + * character code 1. mode holds this character. + * + * After the optional leading '+' and '-', optstring may contain ':'. If + * present, missing arguments return ':' instead of '?'. colon_mode holds + * this setting. + */ + if (getenv("POSIXLY_CORRECT") != NULL) { + mode = '+'; + colon_mode = '+'; + } else { + if (optstring[offset] == '+' || optstring[offset] == '-') { + mode = optstring[offset]; + offset++; + } + if (optstring[offset] == ':') { + colon_mode = 1; + offset++; + } + } + + /* + * charind holds where we left off. If it's set, we were in the middle + * of an argv element; if not, we pick up with the next element of + * optind. + */ + optarg = NULL; + if (charind == 0) { + if (optind >= argc) + option = -1; + else if (strcmp(argv[optind], "--") == 0) { + optind++; + option = -1; + } else if (argv[optind][0] != '-' || argv[optind][1] == '\0') { + char *tmp; + int i, j, k, end; + + if (mode == '+') + option = -1; + else if (mode == '-') { + optarg = argv[optind]; + optind++; + option = 1; + } else { + for (i = optind + 1, j = optind; i < argc; i++) + if ((argv[i][0] == '-') && (argv[i][1] != '\0')) { + optind = i; + option = getopt(argc, argv, optstring); + while (i > j) { + --i; + tmp = argv[i]; + end = (charind == 0) ? optind - 1 : optind; + for (k = i; k + 1 <= end; k++) { + argv[k] = argv[k + 1]; + } + argv[end] = tmp; + --optind; + } + break; + } + if (i == argc) + option = -1; + } + return option; + } else { + charind = 1; + } + } + if (charind != 0) { + optopt = argv[optind][charind]; + for (p = optstring + offset; *p != '\0'; p++) + if (optopt == *p) { + p++; + if (*p == ':') { + if (argv[optind][charind + 1] != '\0') { + optarg = &argv[optind][charind + 1]; + optind++; + charind = 0; + } else { + p++; + if (*p != ':') { + charind = 0; + optind++; + if (optind >= argc) { + if (opterr) + fprintf(stderr, "%s: option requires" + " an argument -- %c\n", argv[0], + optopt); + option = colon_mode ? ':' : '?'; + goto done; + } else { + optarg = argv[optind]; + optind++; + } + } + } + } + option = optopt; + } + if (option == -1) { + if (opterr) + fprintf(stderr, "%s: illegal option -- %c\n", argv[0], optopt); + option = '?'; + } + } + +done: + if (charind != 0) { + charind++; + if (argv[optind][charind] == '\0') { + optind++; + charind = 0; + } + } + if (optind > argc) + optind = argc; + return option; +} |