From a47e2df0ce833e06fa3e4034e64ec084a2bbb2d3 Mon Sep 17 00:00:00 2001 From: Peter Powell Date: Sun, 8 Dec 2019 19:39:02 +0000 Subject: Replace our Windows getopt_long wrapper with ya_getopt. Closes #546. --- vendor/ya_getopt/ya_getopt.c | 318 +++++++++++++++++++++++++++++++++++++++++++ vendor/ya_getopt/ya_getopt.h | 77 +++++++++++ 2 files changed, 395 insertions(+) create mode 100644 vendor/ya_getopt/ya_getopt.c create mode 100644 vendor/ya_getopt/ya_getopt.h (limited to 'vendor/ya_getopt') diff --git a/vendor/ya_getopt/ya_getopt.c b/vendor/ya_getopt/ya_getopt.c new file mode 100644 index 000000000..0c3ddf2ab --- /dev/null +++ b/vendor/ya_getopt/ya_getopt.c @@ -0,0 +1,318 @@ +/* -*- indent-tabs-mode: nil -*- + * + * ya_getopt - Yet another getopt + * https://github.com/kubo/ya_getopt + * + * Copyright 2015 Kubo Takehiro + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of the authors. + * + */ +#include +#include +#include +#include +#include "ya_getopt.h" + +char *ya_optarg = NULL; +int ya_optind = 1; +int ya_opterr = 1; +int ya_optopt = '?'; +static char *ya_optnext = NULL; +static int posixly_correct = -1; +static int handle_nonopt_argv = 0; + +static void ya_getopt_error(const char *optstring, const char *format, ...); +static void check_gnu_extension(const char *optstring); +static int ya_getopt_internal(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex, int long_only); +static int ya_getopt_shortopts(int argc, char * const argv[], const char *optstring, int long_only); +static int ya_getopt_longopts(int argc, char * const argv[], char *arg, const char *optstring, const struct option *longopts, int *longindex, int *long_only_flag); + +static void ya_getopt_error(const char *optstring, const char *format, ...) +{ + if (ya_opterr && optstring[0] != ':') { + va_list ap; + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + } +} + +static void check_gnu_extension(const char *optstring) +{ + if (optstring[0] == '+' || getenv("POSIXLY_CORRECT") != NULL) { + posixly_correct = 1; + } else { + posixly_correct = 0; + } + if (optstring[0] == '-') { + handle_nonopt_argv = 1; + } else { + handle_nonopt_argv = 0; + } +} + +static int is_option(const char *arg) +{ + return arg[0] == '-' && arg[1] != '\0'; +} + +int ya_getopt(int argc, char * const argv[], const char *optstring) +{ + return ya_getopt_internal(argc, argv, optstring, NULL, NULL, 0); +} + +int ya_getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex) +{ + return ya_getopt_internal(argc, argv, optstring, longopts, longindex, 0); +} + +int ya_getopt_long_only(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex) +{ + return ya_getopt_internal(argc, argv, optstring, longopts, longindex, 1); +} + +static int ya_getopt_internal(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex, int long_only) +{ + static int start, end; + + if (ya_optopt == '?') { + ya_optopt = 0; + } + + if (posixly_correct == -1) { + check_gnu_extension(optstring); + } + + if (ya_optind == 0) { + check_gnu_extension(optstring); + ya_optind = 1; + ya_optnext = NULL; + } + + switch (optstring[0]) { + case '+': + case '-': + optstring++; + } + + if (ya_optnext == NULL && start != 0) { + int last_pos = ya_optind - 1; + + ya_optind -= end - start; + if (ya_optind <= 0) { + ya_optind = 1; + } + while (start < end--) { + int i; + char *arg = argv[end]; + + for (i = end; i < last_pos; i++) { + ((char **)argv)[i] = argv[i + 1]; + } + ((char const **)argv)[i] = arg; + last_pos--; + } + start = 0; + } + + if (ya_optind >= argc) { + ya_optarg = NULL; + return -1; + } + if (ya_optnext == NULL) { + const char *arg = argv[ya_optind]; + if (!is_option(arg)) { + if (handle_nonopt_argv) { + ya_optarg = argv[ya_optind++]; + start = 0; + return 1; + } else if (posixly_correct) { + ya_optarg = NULL; + return -1; + } else { + int i; + + start = ya_optind; + for (i = ya_optind + 1; i < argc; i++) { + if (is_option(argv[i])) { + end = i; + break; + } + } + if (i == argc) { + ya_optarg = NULL; + return -1; + } + ya_optind = i; + arg = argv[ya_optind]; + } + } + if (strcmp(arg, "--") == 0) { + ya_optind++; + return -1; + } + if (longopts != NULL && arg[1] == '-') { + return ya_getopt_longopts(argc, argv, argv[ya_optind] + 2, optstring, longopts, longindex, NULL); + } + } + + if (ya_optnext == NULL) { + ya_optnext = argv[ya_optind] + 1; + } + if (long_only) { + int long_only_flag = 0; + int rv = ya_getopt_longopts(argc, argv, ya_optnext, optstring, longopts, longindex, &long_only_flag); + if (!long_only_flag) { + ya_optnext = NULL; + return rv; + } + } + + return ya_getopt_shortopts(argc, argv, optstring, long_only); +} + +static int ya_getopt_shortopts(int argc, char * const argv[], const char *optstring, int long_only) +{ + int opt = *ya_optnext; + const char *os = strchr(optstring, opt); + + if (os == NULL) { + ya_optarg = NULL; + if (long_only) { + ya_getopt_error(optstring, "%s: unrecognized option '-%s'\n", argv[0], ya_optnext); + ya_optind++; + ya_optnext = NULL; + } else { + ya_optopt = opt; + ya_getopt_error(optstring, "%s: invalid option -- '%c'\n", argv[0], opt); + if (*(++ya_optnext) == 0) { + ya_optind++; + ya_optnext = NULL; + } + } + return '?'; + } + if (os[1] == ':') { + if (ya_optnext[1] == 0) { + ya_optind++; + ya_optnext = NULL; + if (os[2] == ':') { + /* optional argument */ + ya_optarg = NULL; + } else { + if (ya_optind == argc) { + ya_optarg = NULL; + ya_optopt = opt; + ya_getopt_error(optstring, "%s: option requires an argument -- '%c'\n", argv[0], opt); + if (optstring[0] == ':') { + return ':'; + } else { + return '?'; + } + } + ya_optarg = argv[ya_optind]; + ya_optind++; + } + } else { + ya_optarg = ya_optnext + 1; + ya_optind++; + } + ya_optnext = NULL; + } else { + ya_optarg = NULL; + if (ya_optnext[1] == 0) { + ya_optnext = NULL; + ya_optind++; + } else { + ya_optnext++; + } + } + return opt; +} + +static int ya_getopt_longopts(int argc, char * const argv[], char *arg, const char *optstring, const struct option *longopts, int *longindex, int *long_only_flag) +{ + char *val = NULL; + const struct option *opt; + size_t namelen; + int idx; + + for (idx = 0; longopts[idx].name != NULL; idx++) { + opt = &longopts[idx]; + namelen = strlen(opt->name); + if (strncmp(arg, opt->name, namelen) == 0) { + switch (arg[namelen]) { + case '\0': + switch (opt->has_arg) { + case ya_required_argument: + ya_optind++; + if (ya_optind == argc) { + ya_optarg = NULL; + ya_optopt = opt->val; + ya_getopt_error(optstring, "%s: option '--%s' requires an argument\n", argv[0], opt->name); + if (optstring[0] == ':') { + return ':'; + } else { + return '?'; + } + } + val = argv[ya_optind]; + break; + } + goto found; + case '=': + if (opt->has_arg == ya_no_argument) { + const char *hyphens = (argv[ya_optind][1] == '-') ? "--" : "-"; + + ya_optind++; + ya_optarg = NULL; + ya_optopt = opt->val; + ya_getopt_error(optstring, "%s: option '%s%s' doesn't allow an argument\n", argv[0], hyphens, opt->name); + return '?'; + } + val = arg + namelen + 1; + goto found; + } + } + } + if (long_only_flag) { + *long_only_flag = 1; + } else { + ya_getopt_error(optstring, "%s: unrecognized option '%s'\n", argv[0], argv[ya_optind]); + ya_optind++; + } + return '?'; +found: + ya_optarg = val; + ya_optind++; + if (opt->flag) { + *opt->flag = opt->val; + } + if (longindex) { + *longindex = idx; + } + return opt->flag ? 0 : opt->val; +} diff --git a/vendor/ya_getopt/ya_getopt.h b/vendor/ya_getopt/ya_getopt.h new file mode 100644 index 000000000..4244c67d0 --- /dev/null +++ b/vendor/ya_getopt/ya_getopt.h @@ -0,0 +1,77 @@ +/* -*- indent-tabs-mode: nil -*- + * + * ya_getopt - Yet another getopt + * https://github.com/kubo/ya_getopt + * + * Copyright 2015 Kubo Takehiro + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of the authors. + * + */ +#ifndef YA_GETOPT_H +#define YA_GETOPT_H 1 + +#if defined(__cplusplus) +extern "C" { +#endif + +#define ya_no_argument 0 +#define ya_required_argument 1 +#define ya_optional_argument 2 + +struct option { + const char *name; + int has_arg; + int *flag; + int val; +}; + +int ya_getopt(int argc, char * const argv[], const char *optstring); +int ya_getopt_long(int argc, char * const argv[], const char *optstring, + const struct option *longopts, int *longindex); +int ya_getopt_long_only(int argc, char * const argv[], const char *optstring, + const struct option *longopts, int *longindex); + +extern char *ya_optarg; +extern int ya_optind, ya_opterr, ya_optopt; + +#ifndef YA_GETOPT_NO_COMPAT_MACRO +#define getopt ya_getopt +#define getopt_long ya_getopt_long +#define getopt_long_only ya_getopt_long_only +#define optarg ya_optarg +#define optind ya_optind +#define opterr ya_opterr +#define optopt ya_optopt +#define no_argument ya_no_argument +#define required_argument ya_required_argument +#define optional_argument ya_optional_argument +#endif + +#if defined(__cplusplus) +} +#endif + +#endif -- cgit v1.2.3