Hi --
Updated diff attached. Wrapped everything up in an m4_warnx() call
and added a regress test for single -E. Thanks!
The one fatal_warns check in eval.c seems like a special case, so
I left that one as it was.
~Brian
Index: usr.bin/m4/eval.c
===================================================================
RCS file: /cvs/src/usr.bin/m4/eval.c,v
retrieving revision 1.74
diff -u -p -u -p -r1.74 eval.c
--- usr.bin/m4/eval.c 5 Feb 2015 12:59:57 -0000 1.74
+++ usr.bin/m4/eval.c 13 Jun 2017 20:22:09 -0000
@@ -269,6 +269,12 @@ expand_builtin(const char *argv[], int a
warn("%s at line %lu: include(%s)",
CURRENT_NAME, CURRENT_LINE,
argv[2]);
exit_code = 1;
+ /* exit immediately if multiple -E flags
+ */
+ if (fatal_warns == 2) {
+ killdiv();
+ exit(exit_code);
+ }
} else
err(1, "%s at line %lu: include(%s)",
CURRENT_NAME, CURRENT_LINE,
argv[2]);
Index: usr.bin/m4/extern.h
===================================================================
RCS file: /cvs/src/usr.bin/m4/extern.h,v
retrieving revision 1.54
diff -u -p -u -p -r1.54 extern.h
--- usr.bin/m4/extern.h 12 May 2014 19:11:19 -0000 1.54
+++ usr.bin/m4/extern.h 13 Jun 2017 20:22:09 -0000
@@ -58,6 +58,8 @@ extern void doesyscmd(const char *);
extern void getdivfile(const char *);
extern void doformat(const char *[], int);
+extern void m4_warnx(const char *, ...);
+
/* look.c */
#define FLAG_UNTRACED 0
@@ -175,4 +177,5 @@ extern int synch_lines; /* line synchro
extern int mimic_gnu; /* behaves like gnu-m4 */
extern int prefix_builtins; /* prefix builtin macros with m4_ */
+extern int fatal_warns; /* make warnings fatal */
Index: usr.bin/m4/gnum4.c
===================================================================
RCS file: /cvs/src/usr.bin/m4/gnum4.c,v
retrieving revision 1.50
diff -u -p -u -p -r1.50 gnum4.c
--- usr.bin/m4/gnum4.c 29 Apr 2015 00:13:26 -0000 1.50
+++ usr.bin/m4/gnum4.c 13 Jun 2017 20:22:09 -0000
@@ -35,6 +35,7 @@
#include <err.h>
#include <paths.h>
#include <regex.h>
+#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdint.h>
@@ -234,7 +235,7 @@ addchar(int c)
}
static char *
-getstring()
+getstring(void)
{
addchar('\0');
current = 0;
@@ -255,11 +256,35 @@ exit_regerror(int er, regex_t *re, const
m4errx(1, "regular expression error in %s: %s.", source, errbuf);
}
+/* warnx() plus check to see if we need to change exit code or exit.
+ * -E flag functionality.
+ */
+void
+m4_warnx(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vwarnx(fmt, ap);
+ va_end(ap);
+
+ /* Do nothing if no -E flags, set exit_code > 0 but keep going
+ * if one -E flag, exit immediately with exit status > 0 if
+ * two or more -E flags.
+ */
+ if (fatal_warns == 0)
+ return;
+ else if (fatal_warns == 1)
+ exit_code = 1;
+ else
+ exit(1);
+}
+
static void
add_sub(int n, const char *string, regex_t *re, regmatch_t *pm)
{
if (n > re->re_nsub)
- warnx("No subexpression %d", n);
+ m4_warnx("No subexpression %d", n);
/* Subexpressions that did not match are
* not an error. */
else if (pm[n].rm_so != -1 &&
@@ -442,7 +467,7 @@ void
dopatsubst(const char *argv[], int argc)
{
if (argc <= 3) {
- warnx("Too few arguments to patsubst");
+ m4_warnx("Too few arguments to patsubst");
return;
}
/* special case: empty regexp */
@@ -494,7 +519,7 @@ doregexp(const char *argv[], int argc)
const char *source;
if (argc <= 3) {
- warnx("Too few arguments to regexp");
+ m4_warnx("Too few arguments to regexp");
return;
}
/* special gnu case */
Index: usr.bin/m4/m4.1
===================================================================
RCS file: /cvs/src/usr.bin/m4/m4.1,v
retrieving revision 1.63
diff -u -p -u -p -r1.63 m4.1
--- usr.bin/m4/m4.1 14 Sep 2015 20:06:58 -0000 1.63
+++ usr.bin/m4/m4.1 13 Jun 2017 20:22:09 -0000
@@ -38,7 +38,7 @@
.Nd macro language processor
.Sh SYNOPSIS
.Nm
-.Op Fl gPs
+.Op Fl EgPs
.Oo
.Sm off
.Fl D Ar name Op No = Ar value
@@ -127,6 +127,19 @@ turn on all options.
.Pp
By default, trace is set to
.Qq eq .
+.It Fl E
+Set warnings to be fatal.
+When a single
+.Fl E
+flag is specified, if warnings are issued, execution continues but
+.Nm
+will exit with a non-zero exit status.
+When multiple
+.Fl E
+flags are specified, execution will halt upon issuing the first warning and
+.Nm
+will exit with a non-zero exit status.
+This behaviour matches GNU-m4 1.4.9 and later.
.It Fl g
Activate GNU-m4 compatibility mode.
In this mode, translit handles simple character
@@ -434,7 +447,9 @@ Returns the current file's name.
.Pp
But note that the
.Ic m4exit
-macro can modify the exit status.
+macro can modify the exit status, as can the
+.Fl E
+flag.
.Sh STANDARDS
The
.Nm
@@ -443,7 +458,7 @@ utility is compliant with the
specification.
.Pp
The flags
-.Op Fl dgIPot
+.Op Fl dEgIPot
and the macros
.Ic builtin ,
.Ic esyscmd ,
Index: usr.bin/m4/main.c
===================================================================
RCS file: /cvs/src/usr.bin/m4/main.c,v
retrieving revision 1.86
diff -u -p -u -p -r1.86 main.c
--- usr.bin/m4/main.c 3 Nov 2015 16:21:47 -0000 1.86
+++ usr.bin/m4/main.c 13 Jun 2017 20:22:09 -0000
@@ -77,6 +77,7 @@ char scommt[MAXCCHARS+1] = {SCOMMT}; /*
char ecommt[MAXCCHARS+1] = {ECOMMT}; /* end character for comment */
int synch_lines = 0; /* line synchronisation for C preprocessor */
int prefix_builtins = 0; /* -P option to prefix builtin keywords */
+int fatal_warns = 0; /* -E option to make warnings fatal */
struct keyblk {
char *knam; /* keyword name */
@@ -185,7 +186,7 @@ main(int argc, char *argv[])
outfile = NULL;
resizedivs(MAXOUT);
- while ((c = getopt(argc, argv, "gst:d:D:U:o:I:P")) != -1)
+ while ((c = getopt(argc, argv, "gst:d:D:EU:o:I:P")) != -1)
switch(c) {
case 'D': /* define something..*/
@@ -195,6 +196,10 @@ main(int argc, char *argv[])
if (*p)
*p++ = EOS;
dodefine(optarg, p);
+ break;
+ case 'E': /* like GNU m4 1.4.9+ */
+ if (fatal_warns < 2)
+ fatal_warns++;
break;
case 'I':
addtoincludepath(optarg);
Index: usr.bin/m4/misc.c
===================================================================
RCS file: /cvs/src/usr.bin/m4/misc.c,v
retrieving revision 1.46
diff -u -p -u -p -r1.46 misc.c
--- usr.bin/m4/misc.c 7 Dec 2015 14:12:46 -0000 1.46
+++ usr.bin/m4/misc.c 13 Jun 2017 20:22:09 -0000
@@ -379,9 +379,9 @@ xstrdup(const char *s)
}
void
-usage()
+usage(void)
{
- fprintf(stderr, "usage: m4 [-gPs] [-Dname[=value]] [-d flags] "
+ fprintf(stderr, "usage: m4 [-EgPs] [-Dname[=value]] [-d flags] "
"[-I dirname] [-o filename]\n"
"\t[-t macro] [-Uname] [file ...]\n");
exit(1);
Index: usr.bin/m4/tokenizer.l
===================================================================
RCS file: /cvs/src/usr.bin/m4/tokenizer.l,v
retrieving revision 1.8
diff -u -p -u -p -r1.8 tokenizer.l
--- usr.bin/m4/tokenizer.l 12 Apr 2012 17:00:11 -0000 1.8
+++ usr.bin/m4/tokenizer.l 13 Jun 2017 20:22:09 -0000
@@ -22,6 +22,7 @@
#include <stdint.h>
#include <limits.h>
+extern void m4_warnx(const char *, ...);
extern int mimic_gnu;
extern int32_t yylval;
@@ -65,9 +66,8 @@ number()
errno = 0;
l = strtol(yytext, NULL, 0);
if (((l == LONG_MAX || l == LONG_MIN) && errno == ERANGE) ||
- l > INT32_MAX || l < INT32_MIN) {
- fprintf(stderr, "m4: numeric overflow in expr: %s\n", yytext);
- }
+ l > INT32_MAX || l < INT32_MIN)
+ m4_warnx("m4: numeric overflow in expr: %s\n", yytext);
return l;
}
@@ -82,7 +82,7 @@ parse_radix()
l = 0;
base = strtol(yytext+2, &next, 0);
if (base > 36 || next == NULL) {
- fprintf(stderr, "m4: error in number %s\n", yytext);
+ m4_warnx("m4: error in number %s\n", yytext);
} else {
next++;
while (*next != 0) {
@@ -95,8 +95,7 @@ parse_radix()
d = *next - 'A' + 10;
}
if (d >= base) {
- fprintf(stderr,
- "m4: error in number %s\n", yytext);
+ m4_warnx("m4: error in number %s\n", yytext);
return 0;
}
l = base * l + d;
Index: regress/usr.bin/m4/Makefile
===================================================================
RCS file: /cvs/src/regress/usr.bin/m4/Makefile,v
retrieving revision 1.32
diff -u -p -u -p -r1.32 Makefile
--- regress/usr.bin/m4/Makefile 1 Nov 2016 00:35:34 -0000 1.32
+++ regress/usr.bin/m4/Makefile 13 Jun 2017 20:22:09 -0000
@@ -13,7 +13,7 @@ REGRESS_TARGETS= test-ff_after_dnl test-
test-gnupatterns2 test-comments test-synch1 test-synch1bis \
test-gnuformat test-includes test-dumpdef test-gnuprefix \
test-translit test-translit2 test-gnutranslit2 \
- test-gnueval test-gnusofterror
+ test-gnueval test-gnusofterror test-fatalwarnings test-fatalwarnings2
test-ff_after_dnl: ff_after_dnl.m4
${M4} ff_after_dnl.m4 | diff - ${.CURDIR}/ff_after_dnl.out
@@ -119,6 +119,12 @@ test-gnueval:
test-gnusofterror:
${M4} -g ${.CURDIR}/gnusofterror.m4 2>/dev/null| diff -u -
${.CURDIR}/gnusofterror.out
! ${M4} -g ${.CURDIR}/gnusofterror.m4 2>/dev/null >/dev/null
+
+test-fatalwarnings:
+ ${M4} -E -g ${.CURDIR}/fatalwarnings.m4 >/dev/null 2>&1 || if test $$?
-ne 1; then false; fi
+
+test-fatalwarnings2:
+ ${M4} -E -E -g ${.CURDIR}/fatalwarnings.m4 2>&1 | diff -u -
${.CURDIR}/fatalwarnings.out
.PHONY: ${REGRESS_TARGETS}
Index: regress/usr.bin/m4/fatalwarnings.m4
===================================================================
RCS file: regress/usr.bin/m4/fatalwarnings.m4
diff -N regress/usr.bin/m4/fatalwarnings.m4
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ regress/usr.bin/m4/fatalwarnings.m4 13 Jun 2017 20:22:09 -0000
@@ -0,0 +1,3 @@
+patsubst(`a')
+patsubst(`b')
+patsubst(`c')
Index: regress/usr.bin/m4/fatalwarnings.out
===================================================================
RCS file: regress/usr.bin/m4/fatalwarnings.out
diff -N regress/usr.bin/m4/fatalwarnings.out
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ regress/usr.bin/m4/fatalwarnings.out 13 Jun 2017 20:22:09 -0000
@@ -0,0 +1 @@
+m4: Too few arguments to patsubst