summaryrefslogtreecommitdiff
path: root/lib/compat
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2021-03-24 16:21:24 +0100
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2021-03-24 23:35:30 +0100
commitcad65de2a9a9b7d29b98f0d2997772c057f92e29 (patch)
treef3ad209f389acb6499cd3b352e061fe730daa760 /lib/compat
parent87713e563f0005553f8d075d3839d3960d7f17cb (diff)
Provide Musl derived fallbacks for getopt/getopt_long/getsubopt
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib/compat')
-rw-r--r--lib/compat/Makemodule.am2
-rw-r--r--lib/compat/getopt.c96
-rw-r--r--lib/compat/getopt_long.c95
-rw-r--r--lib/compat/getsubopt.c42
4 files changed, 205 insertions, 30 deletions
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 <unistd.h>
+#include <string.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#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 <stddef.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <string.h>
+
+#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 <goliath@infraroot.at>
- */
-#include "config.h"
#include "compat.h"
#include <stdlib.h>
@@ -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