summaryrefslogtreecommitdiff
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
parent87713e563f0005553f8d075d3839d3960d7f17cb (diff)
Provide Musl derived fallbacks for getopt/getopt_long/getsubopt
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
-rw-r--r--COPYING.md10
-rw-r--r--configure.ac2
-rw-r--r--include/compat.h25
-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
7 files changed, 239 insertions, 33 deletions
diff --git a/COPYING.md b/COPYING.md
index 107fabd..19f8c5d 100644
--- a/COPYING.md
+++ b/COPYING.md
@@ -22,8 +22,14 @@ The rest of squashfs-tools-ng is released under the terms and conditions of
the **GNU General Public License version 3 or later**, with the following
exceptions:
- - `lib/compat/fnmatch.c` has been copied from Musl libc, which is subject to
- an MIT style license. See `liceneses/musl.txt` for details.
+ - `lib/compat/fnmatch.c` has been copied from Musl libc.
+ - `lib/compat/getopt.c` has been copied from Musl libc.
+ - `lib/compat/getopt_long.c` has been copied from Musl libc.
+ - `lib/compat/getsubopt.c` has been copied from Musl libc.
+
+The components copied from Musl libc are subejct to an MIT style license.
+See `liceneses/musl.txt` for details and only compiled into executable programs
+if the target system does not provide an implementation.
Copies of the LGPLv3 and GPLv3 are included in `licenses/LGPLv3.txt` and
`licenses/GPLv3.txt` respectively.
diff --git a/configure.ac b/configure.ac
index 593734b..ddef2c5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -269,7 +269,7 @@ AC_CHECK_HEADERS([sys/xattr.h], [], [])
AC_CHECK_HEADERS([sys/sysinfo.h], [], [])
AC_CHECK_HEADERS([alloca.h], [], [])
-AC_CHECK_FUNCS([strndup getsubopt fnmatch])
+AC_CHECK_FUNCS([strndup getopt getopt_long getsubopt fnmatch])
##### generate output #####
diff --git a/include/compat.h b/include/compat.h
index e5785d3..8a2522e 100644
--- a/include/compat.h
+++ b/include/compat.h
@@ -181,6 +181,31 @@ void w32_perror(const char *str);
char *strndup(const char *str, size_t max_len);
#endif
+#ifndef HAVE_GETOPT
+extern char *optarg;
+extern int optind, opterr, optopt, optpos, optreset;
+
+void __getopt_msg(const char *a, const char *b, const char *c, size_t l);
+
+int getopt(int argc, char * const argv[], const char *optstring);
+#endif
+
+#ifndef HAVE_GETOPT_LONG
+struct option {
+ const char *name;
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+int getopt_long(int, char *const *, const char *,
+ const struct option *, int *);
+#endif
+
#ifndef HAVE_GETSUBOPT
int getsubopt(char **opt, char *const *keys, char **val);
#endif
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