summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--awk.h2
-rw-r--r--io.c92
-rw-r--r--pc/ChangeLog4
-rw-r--r--pc/Makefile.tst9
-rw-r--r--test/ChangeLog6
-rw-r--r--test/Makefile.am45
-rw-r--r--test/Makefile.in45
-rw-r--r--test/iolint.awk71
-rw-r--r--test/iolint.ok37
10 files changed, 269 insertions, 52 deletions
diff --git a/ChangeLog b/ChangeLog
index e5e1f367..dacc02a8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2020-09-21 Arnold D. Robbins <arnold@skeeve.com>
+
+ * awk.h (enum redirect_flags): Add RED_NONE.
+ (redirect_flags_t): New typedef.
+ * io.c (redflags2str): Handle RED_NONE.
+ (check_duplicated_redirections): New function.
+ (redirect_string): Use new typedef. Call new function if do_lint
+ instead of using inline code.
+ (close_redir): Add error message for failure on close of two-way pipe.
+
2020-09-04 Arnold D. Robbins <arnold@skeeve.com>
* awkgram.y [GRAMMAR]: Install arrays as Node_var_array. Improves
diff --git a/awk.h b/awk.h
index c2218cd8..cf06d490 100644
--- a/awk.h
+++ b/awk.h
@@ -957,6 +957,7 @@ typedef void (*Func_ptr)(void);
/* structure used to dynamically maintain a linked-list of open files/pipes */
struct redirect {
enum redirect_flags {
+ RED_NONE = 0,
RED_FILE = 1,
RED_PIPE = 2,
RED_READ = 4,
@@ -980,6 +981,7 @@ struct redirect {
const char *mode;
awk_output_buf_t output;
};
+typedef enum redirect_flags redirect_flags_t;
/* values for BINMODE, used as bit flags */
diff --git a/io.c b/io.c
index 2478f0c1..1fb95873 100644
--- a/io.c
+++ b/io.c
@@ -725,9 +725,72 @@ redflags2str(int flags)
{ 0, NULL }
};
+ if (flags == RED_NONE)
+ return "RED_NONE";
+
return genflags2str(flags, redtab);
}
+/* check_duplicated_redirections --- see if the same name used differently */
+
+static void
+check_duplicated_redirections(const char *name, size_t len,
+ redirect_flags_t oldflags, redirect_flags_t newflags)
+{
+ static struct mixture {
+ redirect_flags_t common;
+ redirect_flags_t mode;
+ redirect_flags_t other_mode;
+ const char *message;
+ } mixtures[] = {
+ { RED_FILE, RED_READ, RED_WRITE,
+ gettext_noop("`%.*s' used for input file and for output file") },
+ { RED_READ, RED_FILE, RED_PIPE,
+ gettext_noop("`%.*s' used for input file and input pipe") },
+ { RED_READ, RED_FILE, RED_TWOWAY,
+ gettext_noop("`%.*s' used for input file and two-way pipe") },
+ { RED_NONE, (RED_FILE|RED_READ), (RED_PIPE|RED_WRITE),
+ gettext_noop("`%.*s' used for input file and output pipe") },
+ { (RED_FILE|RED_WRITE), (RED_FILE|RED_WRITE), RED_APPEND,
+ gettext_noop("unnecessary mixing of `>' and `>>' for file `%.*s'") },
+ { RED_NONE, (RED_FILE|RED_WRITE), (RED_PIPE|RED_READ),
+ gettext_noop("`%.*s' used for input pipe and output file") },
+ { RED_WRITE, RED_FILE, RED_PIPE,
+ gettext_noop("`%.*s' used for output file and output pipe") },
+ { RED_WRITE, RED_FILE, RED_TWOWAY,
+ gettext_noop("`%.*s' used for output file and two-way pipe") },
+ { RED_PIPE, RED_READ, RED_WRITE,
+ gettext_noop("`%.*s' used for input pipe and output pipe") },
+ { RED_READ, RED_PIPE, RED_TWOWAY,
+ gettext_noop("`%.*s' used for input pipe and two-way pipe") },
+ { RED_WRITE, RED_PIPE, RED_TWOWAY,
+ gettext_noop("`%.*s' used for output pipe and two-way pipe") },
+ };
+ int i = 0, j = sizeof(mixtures) / sizeof(mixtures[0]);
+
+ oldflags &= ~(RED_NOBUF|RED_EOF|RED_PTY);
+ newflags &= ~(RED_NOBUF|RED_EOF|RED_PTY);
+
+ for (i = 0; i < j; i++) {
+ bool both_have_common = \
+ ( (oldflags & mixtures[i].common) == mixtures[i].common
+ && (newflags & mixtures[i].common) == mixtures[i].common);
+ bool old_has_mode = (oldflags & mixtures[i].mode) == mixtures[i].mode;
+ bool new_has_mode = (newflags & mixtures[i].mode) == mixtures[i].mode;
+ bool old_has_other_mode = (oldflags & mixtures[i].other_mode) == mixtures[i].other_mode;
+ bool new_has_other_mode = (newflags & mixtures[i].other_mode) == mixtures[i].other_mode;
+
+ if ( both_have_common
+ && oldflags != newflags
+ && ( (old_has_mode || new_has_mode)
+ && (old_has_other_mode || new_has_other_mode)))
+ {
+ lintwarn(_(mixtures[i].message), len, name);
+ return;
+ }
+ }
+}
+
/* redirect_string --- Redirection for printf and print commands, use string info */
struct redirect *
@@ -735,8 +798,8 @@ redirect_string(const char *str, size_t explen, bool not_string,
int redirtype, int *errflg, int extfd, bool failure_fatal)
{
struct redirect *rp;
- int tflag = 0;
- int outflag = 0;
+ redirect_flags_t tflag = RED_NONE;
+ redirect_flags_t outflag = RED_NONE;
const char *direction = "to";
const char *mode;
int fd;
@@ -831,20 +894,16 @@ redirect_string(const char *str, size_t explen, bool not_string,
/* now check for a match */
if (strlen(rp->value) == explen
- && memcmp(rp->value, str, explen) == 0
- && ((rp->flag & ~(RED_NOBUF|RED_EOF|RED_PTY)) == tflag
- || (outflag != 0
- && (rp->flag & (RED_FILE|RED_WRITE)) == outflag))) {
-
- int rpflag = (rp->flag & ~(RED_NOBUF|RED_EOF|RED_PTY));
- int newflag = (tflag & ~(RED_NOBUF|RED_EOF|RED_PTY));
-
- if (do_lint && rpflag != newflag)
- lintwarn(
- _("unnecessary mixing of `>' and `>>' for file `%.*s'"),
- (int) explen, rp->value);
+ && memcmp(rp->value, str, explen) == 0) {
+ if (do_lint) {
+ check_duplicated_redirections(rp->value, explen, rp->flag, tflag);
+ }
- break;
+ if (((rp->flag & ~(RED_NOBUF|RED_EOF|RED_PTY)) == tflag
+ || (outflag != 0
+ && (rp->flag & (RED_FILE|RED_WRITE)) == outflag))) {
+ break;
+ }
}
}
@@ -1341,6 +1400,9 @@ close_redir(struct redirect *rp, bool exitwarn, two_way_close_type how)
if ((rp->flag & RED_PIPE) != 0)
lintwarn(_("failure status (%d) on pipe close of `%s': %s"),
status, rp->value, s);
+ else if ((rp->flag & RED_TWOWAY) != 0)
+ lintwarn(_("failure status (%d) on two-way pipe close of `%s': %s"),
+ status, rp->value, s);
else
lintwarn(_("failure status (%d) on file close of `%s': %s"),
status, rp->value, s);
diff --git a/pc/ChangeLog b/pc/ChangeLog
index d58d2958..428ba03f 100644
--- a/pc/ChangeLog
+++ b/pc/ChangeLog
@@ -1,3 +1,7 @@
+2020-09-21 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.tst: Rebuilt.
+
2020-08-17 Arnold D. Robbins <arnold@skeeve.com>
* Makefile.tst: Rebuilt.
diff --git a/pc/Makefile.tst b/pc/Makefile.tst
index 98841191..a09b8d1e 100644
--- a/pc/Makefile.tst
+++ b/pc/Makefile.tst
@@ -202,7 +202,7 @@ GAWK_EXT_TESTS = \
genpot gensub gensub2 gensub3 getlndir gnuops2 gnuops3 gnureops gsubind \
icasefs icasers id igncdym igncfs ignrcas2 ignrcas4 ignrcase incdupe \
incdupe2 incdupe3 incdupe4 incdupe5 incdupe6 incdupe7 include include2 \
- indirectbuiltin indirectcall indirectcall2 intarray isarrayunset \
+ indirectbuiltin indirectcall indirectcall2 intarray iolint isarrayunset \
lint lintexp lintindex lintint lintlength lintplus lintold lintset lintwarn \
manyfiles match1 match2 match3 mbstr1 mbstr2 mixed1 mktime muldimposix \
nastyparm negtime next nondec nondec2 nonfatal1 nonfatal2 nonfatal3 \
@@ -1229,6 +1229,13 @@ typedregex4:
@echo $@
@$(AWK) -v x=@$(SLASH)foo/ -f "$(srcdir)"/$@.awk y=@$(SLASH)bar/ /dev/null >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+iolint:
+ @echo $@
+ @echo hello > 'echo hello'
+ @$(AWK) -f "$(srcdir)"/$@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+ @-$(RM) -f cat 'echo hello' f1 f2 md5sum
Gt-dummy:
# file Maketests, generated from Makefile.am by the Gentests program
addcomma:
diff --git a/test/ChangeLog b/test/ChangeLog
index e9199f85..eb3899ca 100644
--- a/test/ChangeLog
+++ b/test/ChangeLog
@@ -1,3 +1,9 @@
+2020-09-21 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.am (EXTRA_DIST): New test iolint. Sort the list of
+ files beginning with 'i'.
+ * iolint.awk, iolint.ok: New files.
+
2020-09-04 Arnold D. Robbins <arnold@skeeve.com>
* id.ok: Updated after code changes.
diff --git a/test/Makefile.am b/test/Makefile.am
index dcef19cb..ff2ba120 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -522,9 +522,6 @@ EXTRA_DIST = \
icasers.awk \
icasers.in \
icasers.ok \
- inpref.awk \
- inpref.in \
- inpref.ok \
id.awk \
id.ok \
igncdym.awk \
@@ -542,53 +539,56 @@ EXTRA_DIST = \
ignrcase.awk \
ignrcase.in \
ignrcase.ok \
- incdupe.ok \
incdupe2.ok \
incdupe3.ok \
incdupe4.ok \
incdupe5.ok \
incdupe6.ok \
incdupe7.ok \
+ incdupe.ok \
inchello.awk \
inclib.awk \
+ include2.ok \
include.awk \
include.ok \
- include2.ok \
indirectbuiltin.awk \
indirectbuiltin.ok \
+ indirectcall2.awk \
+ indirectcall2.ok \
indirectcall.awk \
indirectcall.in \
indirectcall.ok \
- indirectcall2.awk \
- indirectcall2.ok \
inftest.awk \
inftest.ok \
- inplace.in \
- inplace.1.in \
- inplace.2.in \
- inplace1.ok \
inplace1.1.ok \
inplace1.2.ok \
- inplace2.ok \
- inplace2.1.ok \
+ inplace.1.in \
+ inplace1.ok \
inplace2.1.bak.ok \
- inplace2.2.ok \
+ inplace2.1.ok \
inplace2.2.bak.ok \
+ inplace2.2.ok \
inplace2bcomp.1.ok \
inplace2bcomp.1.orig.ok \
inplace2bcomp.2.ok \
inplace2bcomp.2.orig.ok \
inplace2bcomp.ok \
- inplace3.ok \
- inplace3.1.ok \
+ inplace.2.in \
+ inplace2.ok \
inplace3.1.bak.ok \
- inplace3.2.ok \
+ inplace3.1.ok \
inplace3.2.bak.ok \
+ inplace3.2.ok \
inplace3bcomp.1.ok \
inplace3bcomp.1.orig.ok \
inplace3bcomp.2.ok \
inplace3bcomp.2.orig.ok \
inplace3bcomp.ok \
+ inplace3.ok \
+ inplace.in \
+ inpref.awk \
+ inpref.in \
+ inpref.ok \
inputred.awk \
inputred.ok \
intarray.awk \
@@ -601,6 +601,8 @@ EXTRA_DIST = \
intprec.ok \
iobug1.awk \
iobug1.ok \
+ iolint.awk \
+ iolint.ok \
isarrayunset.awk \
isarrayunset.ok \
jarebug.awk \
@@ -1420,7 +1422,7 @@ GAWK_EXT_TESTS = \
genpot gensub gensub2 gensub3 getlndir gnuops2 gnuops3 gnureops gsubind \
icasefs icasers id igncdym igncfs ignrcas2 ignrcas4 ignrcase incdupe \
incdupe2 incdupe3 incdupe4 incdupe5 incdupe6 incdupe7 include include2 \
- indirectbuiltin indirectcall indirectcall2 intarray isarrayunset \
+ indirectbuiltin indirectcall indirectcall2 intarray iolint isarrayunset \
lint lintexp lintindex lintint lintlength lintplus lintold lintset lintwarn \
manyfiles match1 match2 match3 mbstr1 mbstr2 mixed1 mktime muldimposix \
nastyparm negtime next nondec nondec2 nonfatal1 nonfatal2 nonfatal3 \
@@ -2448,6 +2450,13 @@ typedregex4:
@$(AWK) -v x=@/foo/ -f "$(srcdir)"/$@.awk y=@/bar/ /dev/null >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+iolint:
+ @echo $@
+ @echo hello > 'echo hello'
+ @$(AWK) -f "$(srcdir)"/$@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+ @-$(RM) -f cat 'echo hello' f1 f2 md5sum
+
# Targets generated for other tests:
include Maketests
diff --git a/test/Makefile.in b/test/Makefile.in
index 491daedc..a8848e85 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -785,9 +785,6 @@ EXTRA_DIST = \
icasers.awk \
icasers.in \
icasers.ok \
- inpref.awk \
- inpref.in \
- inpref.ok \
id.awk \
id.ok \
igncdym.awk \
@@ -805,53 +802,56 @@ EXTRA_DIST = \
ignrcase.awk \
ignrcase.in \
ignrcase.ok \
- incdupe.ok \
incdupe2.ok \
incdupe3.ok \
incdupe4.ok \
incdupe5.ok \
incdupe6.ok \
incdupe7.ok \
+ incdupe.ok \
inchello.awk \
inclib.awk \
+ include2.ok \
include.awk \
include.ok \
- include2.ok \
indirectbuiltin.awk \
indirectbuiltin.ok \
+ indirectcall2.awk \
+ indirectcall2.ok \
indirectcall.awk \
indirectcall.in \
indirectcall.ok \
- indirectcall2.awk \
- indirectcall2.ok \
inftest.awk \
inftest.ok \
- inplace.in \
- inplace.1.in \
- inplace.2.in \
- inplace1.ok \
inplace1.1.ok \
inplace1.2.ok \
- inplace2.ok \
- inplace2.1.ok \
+ inplace.1.in \
+ inplace1.ok \
inplace2.1.bak.ok \
- inplace2.2.ok \
+ inplace2.1.ok \
inplace2.2.bak.ok \
+ inplace2.2.ok \
inplace2bcomp.1.ok \
inplace2bcomp.1.orig.ok \
inplace2bcomp.2.ok \
inplace2bcomp.2.orig.ok \
inplace2bcomp.ok \
- inplace3.ok \
- inplace3.1.ok \
+ inplace.2.in \
+ inplace2.ok \
inplace3.1.bak.ok \
- inplace3.2.ok \
+ inplace3.1.ok \
inplace3.2.bak.ok \
+ inplace3.2.ok \
inplace3bcomp.1.ok \
inplace3bcomp.1.orig.ok \
inplace3bcomp.2.ok \
inplace3bcomp.2.orig.ok \
inplace3bcomp.ok \
+ inplace3.ok \
+ inplace.in \
+ inpref.awk \
+ inpref.in \
+ inpref.ok \
inputred.awk \
inputred.ok \
intarray.awk \
@@ -864,6 +864,8 @@ EXTRA_DIST = \
intprec.ok \
iobug1.awk \
iobug1.ok \
+ iolint.awk \
+ iolint.ok \
isarrayunset.awk \
isarrayunset.ok \
jarebug.awk \
@@ -1683,7 +1685,7 @@ GAWK_EXT_TESTS = \
genpot gensub gensub2 gensub3 getlndir gnuops2 gnuops3 gnureops gsubind \
icasefs icasers id igncdym igncfs ignrcas2 ignrcas4 ignrcase incdupe \
incdupe2 incdupe3 incdupe4 incdupe5 incdupe6 incdupe7 include include2 \
- indirectbuiltin indirectcall indirectcall2 intarray isarrayunset \
+ indirectbuiltin indirectcall indirectcall2 intarray iolint isarrayunset \
lint lintexp lintindex lintint lintlength lintplus lintold lintset lintwarn \
manyfiles match1 match2 match3 mbstr1 mbstr2 mixed1 mktime muldimposix \
nastyparm negtime next nondec nondec2 nonfatal1 nonfatal2 nonfatal3 \
@@ -2894,6 +2896,13 @@ typedregex4:
@echo $@
@$(AWK) -v x=@/foo/ -f "$(srcdir)"/$@.awk y=@/bar/ /dev/null >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+iolint:
+ @echo $@
+ @echo hello > 'echo hello'
+ @$(AWK) -f "$(srcdir)"/$@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+ @-$(RM) -f cat 'echo hello' f1 f2 md5sum
Gt-dummy:
# file Maketests, generated from Makefile.am by the Gentests program
addcomma:
diff --git a/test/iolint.awk b/test/iolint.awk
new file mode 100644
index 00000000..e7408151
--- /dev/null
+++ b/test/iolint.awk
@@ -0,0 +1,71 @@
+BEGIN {
+ LINT = 1
+
+ # `%.*s' used for input file and for output file
+ print "hi" > "f1"
+ fflush("f1")
+ getline x < "f1"
+ print close("f1")
+ print close("f1")
+ fflush()
+
+ # `%.*s' used for input file and input pipe
+ # `%.*s' used for input file and two-way pipe
+ # `%.*s' used for input pipe and two-way pipe
+ getline data3 < "echo hello"
+ "echo hello" |& getline data2
+ "echo hello" | getline data
+
+ print data, data2, data3
+
+ print close("echo hello")
+ print close("echo hello")
+ print close("echo hello")
+ fflush()
+
+ # `%.*s' used for input file and output pipe
+ getline x < "cat"
+ print "foo" | "cat"
+ print close("cat")
+ print close("cat")
+ fflush()
+
+ # unnecessary mixing of `>' and `>>' for file `%.*s'
+ print "foo" > "f2"
+ print "bar" >> "f2"
+ print close("f2")
+ print close("f2") # -1 expected here
+ fflush()
+
+ # `%.*s' used for output file and output pipe"
+ print "junk" > "md5sum"
+ print "hello" | "md5sum"
+ print close("md5sum")
+ print close("md5sum")
+ fflush()
+
+ # `%.*s' used for input pipe and output file
+ "echo hello" | getline junk
+ print "hello" > "echo hello"
+ print close("echo hello")
+ print close("echo hello")
+ fflush()
+
+ # `%.*s' used for output file and output pipe
+ # `%.*s' used for output file and two-way pipe
+ # `%.*s' used for output pipe and two-way pipe
+ print "hello" > "cat"
+ print "hello" | "cat"
+ print "hello" |& "cat"
+ print close("cat")
+ print close("cat")
+ print close("cat")
+ fflush()
+
+ # `%.*s' used for input pipe and output pipe
+ "echo hello" | getline junk
+ print "hello" | "echo hello"
+ print close("echo hello")
+ print close("echo hello")
+ fflush()
+}
diff --git a/test/iolint.ok b/test/iolint.ok
new file mode 100644
index 00000000..1e325aab
--- /dev/null
+++ b/test/iolint.ok
@@ -0,0 +1,37 @@
+gawk: ./iolint.awk:7: warning: `f1' used for input file and for output file
+0
+0
+gawk: ./iolint.awk:16: warning: `echo hello' used for input file and two-way pipe
+gawk: ./iolint.awk:17: warning: `echo hello' used for input pipe and two-way pipe
+gawk: ./iolint.awk:17: warning: `echo hello' used for input file and input pipe
+hello hello hello
+0
+0
+0
+foo
+0
+gawk: ./iolint.awk:30: warning: close: `cat' is not an open file, pipe or co-process
+-1
+gawk: ./iolint.awk:35: warning: unnecessary mixing of `>' and `>>' for file `f2'
+0
+gawk: ./iolint.awk:37: warning: close: `f2' is not an open file, pipe or co-process
+-1
+gawk: ./iolint.awk:42: warning: `md5sum' used for output file and output pipe
+b1946ac92492d2347c6235b4d2611184 -
+0
+0
+gawk: ./iolint.awk:49: warning: `echo hello' used for input pipe and output file
+0
+0
+gawk: ./iolint.awk:58: warning: `cat' used for output file and output pipe
+gawk: ./iolint.awk:59: warning: `cat' used for output pipe and two-way pipe
+gawk: ./iolint.awk:59: warning: `cat' used for output file and two-way pipe
+hello
+gawk: ./iolint.awk:60: warning: failure status (141) on two-way pipe close of `cat': Success
+141
+0
+0
+gawk: ./iolint.awk:67: warning: `echo hello' used for input pipe and output pipe
+hello
+0
+0