[v2] check-non-portable-shell: support Perl versions older than 5.10
diff mbox series

Message ID 20190511001853.23011-1-sunshine@sunshineco.com
State New
Headers show
  • [v2] check-non-portable-shell: support Perl versions older than 5.10
Related show

Commit Message

Eric Sunshine May 11, 2019, 12:18 a.m. UTC
For thoroughness when checking for one-shot environment variable
assignments at shell function call sites, check-non-portable-shell
stitches together incomplete lines (those ending with backslash). This
allows it to correctly flag such undesirable usage even when the
variable assignment and function call are split across lines, for

    FOO=bar \

where 'func' is a shell function.

The stitching is accomplished like this:

    while (<>) {
        # stitch together incomplete lines (those ending with "\")
        while (s/\\$//) {
            $_ .= readline;
        # detect unportable/undesirable shell constructs

Although this implementation is well supported in reasonably modern Perl
versions (5.10 and later), it fails with older versions (such as Perl
5.8 shipped with ancient Mac OS 10.5). In particular, in older Perl
versions, 'readline' is not connected to the file handle associated with
the "magic" while (<>) {...} construct, so 'readline' throws a
"readline() on unopened filehandle" error. Work around this problem by
dropping readline() and instead incorporating the stitching of
incomplete lines directly into the existing while (<>) {...} loop.

Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>

This is a re-roll of [1]. The only change since v1 is to drop
localization of $_ as suggested by Ævar in [2], and rewriting the commit
message to avoid misleadingly talking about $_ as being problematic.

[1]: http://public-inbox.org/git/20190509102037.27044-1-sunshine@sunshineco.com/
[2]: http://public-inbox.org/git/87ftpnhknn.fsf@evledraar.gmail.com/

 t/check-non-portable-shell.pl | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff mbox series

diff --git a/t/check-non-portable-shell.pl b/t/check-non-portable-shell.pl
index 166d64d4a2..38bfeebd88 100755
--- a/t/check-non-portable-shell.pl
+++ b/t/check-non-portable-shell.pl
@@ -27,14 +27,14 @@  sub err {
 	close $f;
+my $line = '';
 while (<>) {
+	$line .= $_;
 	# stitch together incomplete lines (those ending with "\")
-	while (s/\\$//) {
-		$_ .= readline;
-		chomp;
-	}
+	next if $line =~ s/\\$//;
+	$_ = $line;
 	/\bcp\s+-a/ and err 'cp -a is not portable';
 	/\bsed\s+-[^efn]\s+/ and err 'sed option not portable (use only -n, -e, -f)';
 	/\becho\s+-[neE]/ and err 'echo with option is not portable (use printf)';
@@ -48,6 +48,7 @@  sub err {
 	/\bexport\s+[A-Za-z0-9_]*=/ and err '"export FOO=bar" is not portable (use FOO=bar && export FOO)';
 	/^\s*([A-Z0-9_]+=(\w+|(["']).*?\3)\s+)+(\w+)/ and exists($func{$4}) and
 		err '"FOO=bar shell_func" assignment extends beyond "shell_func"';
+	$line = '';
 	# this resets our $. for each file
 	close ARGV if eof;