From cad65de2a9a9b7d29b98f0d2997772c057f92e29 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Wed, 24 Mar 2021 16:21:24 +0100 Subject: Provide Musl derived fallbacks for getopt/getopt_long/getsubopt Signed-off-by: David Oberhollenzer --- lib/compat/Makemodule.am | 2 + lib/compat/getopt.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/compat/getopt_long.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++ lib/compat/getsubopt.c | 42 ++++++--------------- 4 files changed, 205 insertions(+), 30 deletions(-) create mode 100644 lib/compat/getopt.c create mode 100644 lib/compat/getopt_long.c (limited to 'lib/compat') diff --git a/lib/compat/Makemodule.am b/lib/compat/Makemodule.am index 6c3c2b4..6ea0750 100644 --- a/lib/compat/Makemodule.am +++ b/lib/compat/Makemodule.am @@ -4,5 +4,7 @@ libcompat_a_SOURCES += lib/compat/chdir.c include/compat.h libcompat_a_SOURCES += lib/compat/path_to_windows.c libcompat_a_SOURCES += lib/compat/w32_perror.c libcompat_a_SOURCES += lib/compat/fnmatch.c +libcompat_a_SOURCES += lib/compat/getopt.c +libcompat_a_SOURCES += lib/compat/getopt_long.c noinst_LIBRARIES += libcompat.a diff --git a/lib/compat/getopt.c b/lib/compat/getopt.c new file mode 100644 index 0000000..9876a87 --- /dev/null +++ b/lib/compat/getopt.c @@ -0,0 +1,96 @@ +#include "compat.h" + +#include +#include +#include +#include + +#ifndef HAVE_GETOPT +char *optarg; +int optind=1, opterr=1, optopt, optpos, optreset=0; + +void __getopt_msg(const char *a, const char *b, const char *c, size_t l) +{ + fputs(a, stderr); + fwrite(b, strlen(b), 1, stderr); + fwrite(c, 1, l, stderr); + putc('\n', stderr); +} + +int getopt(int argc, char * const argv[], const char *optstring) +{ + int i; + wchar_t c, d; + int k, l; + char *optchar; + + if (!optind || __optreset) { + optreset = 0; + optpos = 0; + optind = 1; + } + + if (optind >= argc || !argv[optind]) + return -1; + + if (argv[optind][0] != '-') { + if (optstring[0] == '-') { + optarg = argv[optind++]; + return 1; + } + return -1; + } + + if (!argv[optind][1]) + return -1; + + if (argv[optind][1] == '-' && !argv[optind][2]) + return optind++, -1; + + if (!optpos) optpos++; + if ((k = mbtowc(&c, argv[optind]+optpos, MB_LEN_MAX)) < 0) { + k = 1; + c = 0xfffd; /* replacement char */ + } + optchar = argv[optind]+optpos; + optpos += k; + + if (!argv[optind][optpos]) { + optind++; + optpos = 0; + } + + if (optstring[0] == '-' || optstring[0] == '+') + optstring++; + + i = 0; + d = 0; + do { + l = mbtowc(&d, optstring+i, MB_LEN_MAX); + if (l>0) i+=l; else i++; + } while (l && d != c); + + if (d != c || c == ':') { + optopt = c; + if (optstring[0] != ':' && opterr) + __getopt_msg(argv[0], ": unrecognized option: ", optchar, k); + return '?'; + } + if (optstring[i] == ':') { + optarg = 0; + if (optstring[i+1] != ':' || optpos) { + optarg = argv[optind++] + optpos; + optpos = 0; + } + if (optind > argc) { + optopt = c; + if (optstring[0] == ':') return ':'; + if (opterr) __getopt_msg(argv[0], + ": option requires an argument: ", + optchar, k); + return '?'; + } + } + return c; +} +#endif diff --git a/lib/compat/getopt_long.c b/lib/compat/getopt_long.c new file mode 100644 index 0000000..58354c3 --- /dev/null +++ b/lib/compat/getopt_long.c @@ -0,0 +1,95 @@ +#include "compat.h" + +#include +#include +#include +#include +#include +#include + +#ifndef HAVE_GETOPT_LONG +static void permute(char *const *argv, int dest, int src) +{ + char **av = (char **)argv; + char *tmp = av[src]; + int i; + for (i=src; i>dest; i--) + av[i] = av[i-1]; + av[dest] = tmp; +} + +int getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx) +{ + optarg = 0; + if (longopts && argv[optind][0] == '-' && + (argv[optind][1] == '-' && argv[optind][2])) + { + int colon = optstring[optstring[0]=='+'||optstring[0]=='-']==':'; + int i, cnt, match; + char *arg, *opt, *start = argv[optind]+1; + for (cnt=i=0; longopts[i].name; i++) { + const char *name = longopts[i].name; + opt = start; + if (*opt == '-') opt++; + while (*opt && *opt != '=' && *opt == *name) + name++, opt++; + if (*opt && *opt != '=') continue; + arg = opt; + match = i; + if (!*name) { + cnt = 1; + break; + } + cnt++; + } + if (cnt==1) { + i = match; + opt = arg; + optind++; + if (*opt == '=') { + if (!longopts[i].has_arg) { + optopt = longopts[i].val; + if (colon || !opterr) + return '?'; + __getopt_msg(argv[0], + ": option does not take an argument: ", + longopts[i].name, + strlen(longopts[i].name)); + return '?'; + } + optarg = opt+1; + } else if (longopts[i].has_arg == required_argument) { + if (!(optarg = argv[optind])) { + optopt = longopts[i].val; + if (colon) return ':'; + if (!opterr) return '?'; + __getopt_msg(argv[0], + ": option requires an argument: ", + longopts[i].name, + strlen(longopts[i].name)); + return '?'; + } + optind++; + } + if (idx) *idx = i; + if (longopts[i].flag) { + *longopts[i].flag = longopts[i].val; + return 0; + } + return longopts[i].val; + } + if (argv[optind][1] == '-') { + optopt = 0; + if (!colon && opterr) + __getopt_msg(argv[0], cnt ? + ": option is ambiguous: " : + ": unrecognized option: ", + argv[optind]+2, + strlen(argv[optind]+2)); + optind++; + return '?'; + } + } + return getopt(argc, argv, optstring); +} +#endif diff --git a/lib/compat/getsubopt.c b/lib/compat/getsubopt.c index d53a37d..e6fea1a 100644 --- a/lib/compat/getsubopt.c +++ b/lib/compat/getsubopt.c @@ -1,10 +1,3 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * getsubopt.c - * - * Copyright (C) 2019 David Oberhollenzer - */ -#include "config.h" #include "compat.h" #include @@ -13,33 +6,22 @@ #ifndef HAVE_GETSUBOPT int getsubopt(char **opt, char *const *keys, char **val) { - char *str = *opt; - size_t i, len; + char *s = *opt; + int i; *val = NULL; - *opt = strchr(str, ','); - - if (*opt == NULL) { - *opt = str + strlen(str); - } else { - *(*opt)++ = '\0'; - } - - for (i = 0; keys[i]; ++i) { - len = strlen(keys[i]); - - if (strncmp(keys[i], str, len) != 0) - continue; - - if (str[len] != '=' && str[len] != '\0') - continue; - - if (str[len] == '=') - *val = str + len + 1; - + *opt = strchr(s, ','); + if (*opt) *(*opt)++ = 0; + else *opt = s + strlen(s); + + for (i=0; keys[i]; i++) { + size_t l = strlen(keys[i]); + if (strncmp(keys[i], s, l)) continue; + if (s[l] == '=') + *val = s + l + 1; + else if (s[l]) continue; return i; } - return -1; } #endif -- cgit v1.2.3