[m-rev.] for review: Use musl getopt implementation.
Peter Wang
novalazy at gmail.com
Fri Jun 7 15:29:54 AEST 2019
LICENSE:
Mention files derived from musl library.
runtime/process_getopt:
Process files from ../getopt/*.[ch] to produce
mercury_getopt.h, mercury_getopt.c, mercury_getopt_long.c.
runtime/mercury_getopt.h:
runtime/mercury_getopt.c:
runtime/mercury_getopt_long.c:
Add files generated by process_getopt.
runtime/Mmakefile:
Update list of source files.
util/Mmakefile:
Use musl getopt if the system C library does not have getopt().
tests/debugger/browser_test.exp:
tests/debugger/browser_test.exp2:
tests/debugger/browser_test.exp3:
tests/hard_coded/runtime_opt.exp:
Update expected error messages to match new getopt() output.
diff --git a/LICENSE b/LICENSE
index 283fba5a4..7735f474f 100644
--- a/LICENSE
+++ b/LICENSE
@@ -27,6 +27,12 @@ entirety.
--------
+The files in the `getopt' directory, as well as runtime/mercury_getopt.c,
+runtime/mercury_getopt_long.c and runtime/mercury_getopt.h, are derived
+from the musl library. See the files for copyright information.
+
+--------
+
A few files (config.guess, config.sub) are derived from code that is
copyright by the Free Software Foundation, Inc, and are distributed
under the GNU General Public License version 2.
diff --git a/runtime/Mmakefile b/runtime/Mmakefile
index 6519383d6..528fd9e53 100644
--- a/runtime/Mmakefile
+++ b/runtime/Mmakefile
@@ -173,7 +173,7 @@ CFILES = \
mercury_file.c \
mercury_float.c \
mercury_getopt.c \
- mercury_getopt1.c \
+ mercury_getopt_long.c \
mercury_grade.c \
mercury_hash_table.c \
mercury_heap_profile.c \
diff --git a/runtime/RESERVED_MACRO_NAMES b/runtime/RESERVED_MACRO_NAMES
index d59fe56d1..39251a071 100644
--- a/runtime/RESERVED_MACRO_NAMES
+++ b/runtime/RESERVED_MACRO_NAMES
@@ -1,5 +1,6 @@
#-----------------------------------------------------------------------------#
# Copyright (C) 2000-2004, 2006, 2011 The University of Melbourne.
+# Copyright (C) 2013-2014, 2019 The Mercury team
# This file may only be copied under the terms of the GNU General
# Public License - see the file COPYING in the Mercury distribution.
#-----------------------------------------------------------------------------#
diff --git a/runtime/mercury_getopt.c b/runtime/mercury_getopt.c
new file mode 100644
index 000000000..2056d5dc1
--- /dev/null
+++ b/runtime/mercury_getopt.c
@@ -0,0 +1,119 @@
+/*
+Copyright © 2005-2014 Rich Felker, et al.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include <string.h>
+#include <stdio.h>
+#define GETOPT_IMPL
+#include "mercury_getopt.h"
+
+char *MR_optarg;
+int MR_optind=1, MR_opterr=1, MR_optopt, MR__optpos, MR_optreset=0;
+
+#define optpos MR__optpos
+
+void MR__getopt_msg(const char *a, const char *b, const char *c, size_t l)
+{
+ FILE *f = stderr;
+ if (
+ fputs(a, f)>=0
+ && fwrite(b, strlen(b), 1, f)
+ && fwrite(c, 1, l, f)==l
+ && putc('\n', f)
+ ) { }
+}
+
+int MR_getopt(int argc, char * const argv[], const char *optstring)
+{
+ int i;
+ int c, d;
+ int k, l;
+ char *optchar;
+
+ if (!MR_optind || MR_optreset) {
+ MR_optreset = 0;
+ MR__optpos = 0;
+ MR_optind = 1;
+ }
+
+ if (MR_optind >= argc || !argv[MR_optind])
+ return -1;
+
+ if (argv[MR_optind][0] != '-') {
+ if (optstring[0] == '-') {
+ MR_optarg = argv[MR_optind++];
+ return 1;
+ }
+ return -1;
+ }
+
+ if (!argv[MR_optind][1])
+ return -1;
+
+ if (argv[MR_optind][1] == '-' && !argv[MR_optind][2])
+ return MR_optind++, -1;
+
+ if (!optpos) optpos++;
+ c = argv[MR_optind][optpos];
+ k = 1;
+ optchar = argv[MR_optind]+optpos;
+ optpos += k;
+
+ if (!argv[MR_optind][optpos]) {
+ MR_optind++;
+ optpos = 0;
+ }
+
+ if (optstring[0] == '-' || optstring[0] == '+')
+ optstring++;
+
+ i = 0;
+ d = 0;
+ do {
+ d = optstring[i];
+ l = d ? 1 : 0;
+ if (l>0) i+=l; else i++;
+ } while (l && d != c);
+
+ if (d != c || c == ':') {
+ MR_optopt = c;
+ if (optstring[0] != ':' && MR_opterr)
+ MR__getopt_msg(argv[0], ": unrecognized option: ", optchar, k);
+ return '?';
+ }
+ if (optstring[i] == ':') {
+ MR_optarg = 0;
+ if (optstring[i+1] != ':' || optpos) {
+ MR_optarg = argv[MR_optind++] + optpos;
+ optpos = 0;
+ }
+ if (MR_optind > argc) {
+ MR_optopt = c;
+ if (optstring[0] == ':') return ':';
+ if (MR_opterr) MR__getopt_msg(argv[0],
+ ": option requires an argument: ",
+ optchar, k);
+ return '?';
+ }
+ }
+ return c;
+}
diff --git a/runtime/mercury_getopt.h b/runtime/mercury_getopt.h
new file mode 100644
index 000000000..85885a60a
--- /dev/null
+++ b/runtime/mercury_getopt.h
@@ -0,0 +1,57 @@
+/*
+Copyright © 2005-2014 Rich Felker, et al.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef MERCURY_GETOPT_H
+#define MERCURY_GETOPT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int MR_getopt(int, char * const [], const char *);
+extern char *MR_optarg;
+extern int MR_optind, MR_opterr, MR_optopt, MR_optreset;
+
+struct MR_option {
+ const char *name;
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+int MR_getopt_long(int, char *const *, const char *, const struct MR_option *, int *);
+int MR_getopt_long_only(int, char *const *, const char *, const struct MR_option *, int *);
+
+#define MR_no_argument 0
+#define MR_required_argument 1
+#define MR_optional_argument 2
+
+#ifdef GETOPT_IMPL
+void MR__getopt_msg(const char *a, const char *b, const char *c, size_t l);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/runtime/mercury_getopt_long.c b/runtime/mercury_getopt_long.c
new file mode 100644
index 000000000..c39a3e9e4
--- /dev/null
+++ b/runtime/mercury_getopt_long.c
@@ -0,0 +1,167 @@
+/*
+Copyright © 2005-2014 Rich Felker, et al.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#define GETOPT_IMPL
+#include "mercury_getopt.h"
+
+extern int MR__optpos;
+
+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;
+}
+
+static int __getopt_long_core(int argc, char *const *argv, const char *optstring, const struct MR_option *longopts, int *idx, int longonly);
+
+static int __getopt_long(int argc, char *const *argv, const char *optstring, const struct MR_option *longopts, int *idx, int longonly)
+{
+ int ret, skipped, resumed;
+ if (!MR_optind || MR_optreset) {
+ MR_optreset = 0;
+ MR__optpos = 0;
+ MR_optind = 1;
+ }
+ if (MR_optind >= argc || !argv[MR_optind]) return -1;
+ skipped = MR_optind;
+ if (optstring[0] != '+' && optstring[0] != '-') {
+ int i;
+ for (i=MR_optind; ; i++) {
+ if (i >= argc || !argv[i]) return -1;
+ if (argv[i][0] == '-' && argv[i][1]) break;
+ }
+ MR_optind = i;
+ }
+ resumed = MR_optind;
+ ret = __getopt_long_core(argc, argv, optstring, longopts, idx, longonly);
+ if (resumed > skipped) {
+ int i, cnt = MR_optind-resumed;
+ for (i=0; i<cnt; i++)
+ permute(argv, skipped, MR_optind-1);
+ MR_optind = skipped + cnt;
+ }
+ return ret;
+}
+
+static int __getopt_long_core(int argc, char *const *argv, const char *optstring, const struct MR_option *longopts, int *idx, int longonly)
+{
+ MR_optarg = 0;
+ if (longopts && argv[MR_optind][0] == '-' &&
+ ((longonly && argv[MR_optind][1] && argv[MR_optind][1] != '-') ||
+ (argv[MR_optind][1] == '-' && argv[MR_optind][2])))
+ {
+ int colon = optstring[optstring[0]=='+'||optstring[0]=='-']==':';
+ int i, cnt, match;
+ char *arg, *opt, *start = argv[MR_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 && longonly && arg-start == 1) {
+ int l = arg-start;
+ for (i=0; optstring[i]; i++) {
+ int j;
+ for (j=0; j<l && start[j]==optstring[i+j]; j++);
+ if (j==l) {
+ cnt++;
+ break;
+ }
+ }
+ }
+ if (cnt==1) {
+ i = match;
+ opt = arg;
+ MR_optind++;
+ if (*opt == '=') {
+ if (!longopts[i].has_arg) {
+ MR_optopt = longopts[i].val;
+ if (colon || !MR_opterr)
+ return '?';
+ MR__getopt_msg(argv[0],
+ ": option does not take an argument: ",
+ longopts[i].name,
+ strlen(longopts[i].name));
+ return '?';
+ }
+ MR_optarg = opt+1;
+ } else if (longopts[i].has_arg == MR_required_argument) {
+ if (!(MR_optarg = argv[MR_optind])) {
+ MR_optopt = longopts[i].val;
+ if (colon) return ':';
+ if (!MR_opterr) return '?';
+ MR__getopt_msg(argv[0],
+ ": option requires an argument: ",
+ longopts[i].name,
+ strlen(longopts[i].name));
+ return '?';
+ }
+ MR_optind++;
+ }
+ if (idx) *idx = i;
+ if (longopts[i].flag) {
+ *longopts[i].flag = longopts[i].val;
+ return 0;
+ }
+ return longopts[i].val;
+ }
+ if (argv[MR_optind][1] == '-') {
+ MR_optopt = 0;
+ if (!colon && MR_opterr)
+ MR__getopt_msg(argv[0], cnt ?
+ ": option is ambiguous: " :
+ ": unrecognized option: ",
+ argv[MR_optind]+2,
+ strlen(argv[MR_optind]+2));
+ MR_optind++;
+ return '?';
+ }
+ }
+ return MR_getopt(argc, argv, optstring);
+}
+
+int MR_getopt_long(int argc, char *const *argv, const char *optstring, const struct MR_option *longopts, int *idx)
+{
+ return __getopt_long(argc, argv, optstring, longopts, idx, 0);
+}
+
+int MR_getopt_long_only(int argc, char *const *argv, const char *optstring, const struct MR_option *longopts, int *idx)
+{
+ return __getopt_long(argc, argv, optstring, longopts, idx, 1);
+}
diff --git a/runtime/process_getopt b/runtime/process_getopt
index 5be8ee95a..6200540fe 100755
--- a/runtime/process_getopt
+++ b/runtime/process_getopt
@@ -1,56 +1,31 @@
#!/bin/sh
+# This generates mercury_getopt*.[ch] from the files in ../getopt
-chmod 644 mercury_getopt.h mercury_getopt.c mercury_getopt1.c
+chmod 644 mercury_getopt.h mercury_getopt.c mercury_getopt_long.c
-for file in getopt.h getopt.c getopt1.c
+for file in getopt.h getopt.c getopt_long.c
do
echo processing mercury_$file
- cp GETOPT/$file mercury_$file
+ cp ../getopt/$file mercury_$file
ex mercury_$file << END
g/#include/s/getopt/mercury_getopt/
- g/\<getopt/s//MR_getopt/g
- g/\<optarg/s//MR_optarg/g
- g/\<optind/s//MR_optind/g
- g/\<opterr/s//MR_opterr/g
- g/\<optopt/s//MR_optopt/g
- g/\<option/s//MR_option/g
- g/\<_getopt/s//MR__getopt/g
- g/\<_GETOPT/s//MERCURY_GETOPT/g
- g/no_argument/s//MR_no_argument/g
- g/required_argument/s//MR_required_argument/g
- g/#ifndef/s/ELIDE_CODE/XXXELIDE_CODEXXX/
+ g/\<getopt\(.*(\)/s//MR_getopt\1/g
+ g/\<optarg\>/s//MR_optarg/g
+ g/\<optind\>/s//MR_optind/g
+ g/\<opterr\>/s//MR_opterr/g
+ g/\<optopt\>/s//MR_optopt/g
+ g/\<optreset\>/s//MR_optreset/g
+ g/\<__optpos\>/s//MR__optpos/g
+ g/\<__optreset\>/s//MR__optreset/g
+ g/\<__getopt_msg\>/s//MR__getopt_msg/g
+ g/\<struct option\>/s//struct MR_option/g
+ g/\<no_argument\>/s//MR_no_argument/g
+ g/\<required_argument\>/s//MR_required_argument/g
+ g/\<optional_argument\>/s//MR_optional_argument/g
+ g/\<_GETOPT_H\>/s//MERCURY_GETOPT_H/g
w
q
END
done
-echo finalizing mercury_getopt.h
-ex mercury_getopt.h << END
-1i
-#undef __GNU_LIBRARY__
-#define __GNU_LIBRARY__
-.
-w
-q
-END
-
-echo finalizing mercury_getopt.c
-ex mercury_getopt.c << END
-1i
-extern char *getenv(const char *);
-.
-g/nextchar/s//MR_nextchar/g
-g/ordering/s//MR_ordering/g
-g/posixly_correct/s//MR_posixly_correct/g
-g/first_nonopt/s//MR_first_nonopt/g
-g/last_nonopt/s//MR_last_nonopt/g
-g/__getopt_initialized/s//MR____getopt_initialized/g
-g/%s: MR_option/s//%s: option/g
-g/%s: unrecognized MR_option/s//%s: unrecognized option/g
-g/%s: illegal MR_option/s//%s: illegal option/g
-g/%s: invalid MR_option/s//%s: invalid option/g
-w
-q
-END
-
-chmod 444 mercury_getopt.h mercury_getopt.c mercury_getopt1.c
+chmod 444 mercury_getopt.h mercury_getopt.c mercury_getopt_long.c
diff --git a/tests/debugger/browser_test.exp b/tests/debugger/browser_test.exp
index 5521cbaa9..e6b38c554 100644
--- a/tests/debugger/browser_test.exp
+++ b/tests/debugger/browser_test.exp
@@ -77,7 +77,7 @@ big(
3,
big(big(small, 4, big(small, 5, small)), 6, small))
mdb> print --xyzzy 1
-print: unrecognized option `--xyzzy'
+print: unrecognized option: xyzzy
mdb: print: usage error -- type `help print' for help.
mdb> browse 1; print; quit
big(
diff --git a/tests/debugger/browser_test.exp2 b/tests/debugger/browser_test.exp2
index d047d8636..3a534cd8a 100644
--- a/tests/debugger/browser_test.exp2
+++ b/tests/debugger/browser_test.exp2
@@ -53,7 +53,7 @@ big(
3,
big(big(small, 4, big(small, 5, small)), 6, small))
mdb> print --xyzzy 1
-print: unrecognized option `--xyzzy'
+print: unrecognized option: xyzzy
mdb: print: usage error -- type `help print' for help.
mdb> browse 1; print; quit
big(big(big(small, 1, small), 2, small), 3, big(big(small, 4, big/3), 6, small))
diff --git a/tests/debugger/browser_test.exp3 b/tests/debugger/browser_test.exp3
index 21b2755b9..f570261f8 100644
--- a/tests/debugger/browser_test.exp3
+++ b/tests/debugger/browser_test.exp3
@@ -62,7 +62,7 @@ big(
3,
big(big(small, 4, big(small, 5, small)), 6, small))
mdb> print --xyzzy 1
-print: unrecognized option `--xyzzy'
+print: unrecognized option: xyzzy
mdb: print: usage error -- type `help print' for help.
mdb> browse 1; print; quit
big(
diff --git a/tests/hard_coded/runtime_opt.exp b/tests/hard_coded/runtime_opt.exp
index 0469d083c..9907a6be7 100644
--- a/tests/hard_coded/runtime_opt.exp
+++ b/tests/hard_coded/runtime_opt.exp
@@ -8,7 +8,7 @@ Option `--detstack-size=128 --small-detstack-size=128':
Hello world (with non-standard options).
Option `--this-is-not-a-real-option':
-mercury_runtime: unrecognized option `--this-is-not-a-real-option'
+mercury_runtime: unrecognized option: this-is-not-a-real-option
The MERCURY_OPTIONS environment variable contains an invalid option.
Please refer to the Environment Variables section of the Mercury
User's Guide for details.
diff --git a/util/Mmakefile b/util/Mmakefile
index 73bbc236a..6854dac51 100644
--- a/util/Mmakefile
+++ b/util/Mmakefile
@@ -2,6 +2,7 @@
# vim: ts=8 sw=8 noexpandtab
#-----------------------------------------------------------------------------#
# Copyright (C) 1995-2002, 2005, 2006-2007, 2010, 2012 The University of Melbourne.
+# Copyright (C) 2013, 2019 The Mercury team.
# This file may only be copied under the terms of the GNU General
# Public License - see the file COPYING in the Mercury distribution.
#-----------------------------------------------------------------------------#
@@ -25,12 +26,10 @@ PROGFILENAMES=$(PROGS:%=%$(EXT_FOR_EXE))
SRC=$(PROGS:%=%.c)
# Link in local copy of getopt() only if required.
-# XXX The files in runtime/GETOPT may not compile cleanly with modern
-# compilers. We should replace it with another implementation.
ifeq ("$(HAVE_GETOPT)","no")
- GETOPT_SRC=$(RUNTIME_DIR)/GETOPT/getopt.c $(RUNTIME_DIR)/GETOPT/getopt1.c
+ GETOPT_SRC=../getopt/getopt.c
else
- GETOPT_SRC=
+ GETOPT_SRC=
endif
# mkinit.c needs `struct stat'
--
2.21.0
More information about the reviews
mailing list