diff options
| author | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2021-03-24 16:21:24 +0100 | 
|---|---|---|
| committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2021-03-24 23:35:30 +0100 | 
| commit | cad65de2a9a9b7d29b98f0d2997772c057f92e29 (patch) | |
| tree | f3ad209f389acb6499cd3b352e061fe730daa760 | |
| parent | 87713e563f0005553f8d075d3839d3960d7f17cb (diff) | |
Provide Musl derived fallbacks for getopt/getopt_long/getsubopt
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
| -rw-r--r-- | COPYING.md | 10 | ||||
| -rw-r--r-- | configure.ac | 2 | ||||
| -rw-r--r-- | include/compat.h | 25 | ||||
| -rw-r--r-- | lib/compat/Makemodule.am | 2 | ||||
| -rw-r--r-- | lib/compat/getopt.c | 96 | ||||
| -rw-r--r-- | lib/compat/getopt_long.c | 95 | ||||
| -rw-r--r-- | lib/compat/getsubopt.c | 42 | 
7 files changed, 239 insertions, 33 deletions
@@ -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  | 
