diff options
author | Arnold D. Robbins <arnold@skeeve.com> | 2020-09-21 17:02:23 +0300 |
---|---|---|
committer | Arnold D. Robbins <arnold@skeeve.com> | 2020-09-21 17:02:23 +0300 |
commit | 55eee619ac637e29c0fe847cc89cda78cc18c28d (patch) | |
tree | 3910fc6b193f91f72c280002033d128fd30e9e85 | |
parent | 166848a1579181875e6ac696fd004037441b6b75 (diff) | |
download | egawk-55eee619ac637e29c0fe847cc89cda78cc18c28d.tar.gz egawk-55eee619ac637e29c0fe847cc89cda78cc18c28d.tar.bz2 egawk-55eee619ac637e29c0fe847cc89cda78cc18c28d.zip |
Add lint checks for same redirection used multiple ways.
-rw-r--r-- | ChangeLog | 10 | ||||
-rw-r--r-- | awk.h | 2 | ||||
-rw-r--r-- | io.c | 92 | ||||
-rw-r--r-- | pc/ChangeLog | 4 | ||||
-rw-r--r-- | pc/Makefile.tst | 9 | ||||
-rw-r--r-- | test/ChangeLog | 6 | ||||
-rw-r--r-- | test/Makefile.am | 45 | ||||
-rw-r--r-- | test/Makefile.in | 45 | ||||
-rw-r--r-- | test/iolint.awk | 71 | ||||
-rw-r--r-- | test/iolint.ok | 37 |
10 files changed, 269 insertions, 52 deletions
@@ -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 @@ -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 */ @@ -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 |