Subject: [PATCH 06/18] checkbashisms: multiple fixes to heredoc handling for convoluted code

From: Raphael Geissert <[email-masked]>
Date: Sun, 21 Oct 2012 13:17:04 -0500

Signed-off-by: Raphael Geissert <[email-masked]>
---
 scripts/checkbashisms.pl |   19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/scripts/checkbashisms.pl b/scripts/checkbashisms.pl
index ecd64f1..8f9b19c 100755
--- a/scripts/checkbashisms.pl
+++ b/scripts/checkbashisms.pl
@@ -433,10 +433,23 @@ foreach my $filename (@ARGV) {
 
 	    # Only look for the beginning of a heredoc here, after we've
 	    # stripped out quoted material, to avoid false positives.
-	    if ($cat_line =~ m/(?:^|[^<])\<\<(\-?)\s*(?:[\\]?([\w-]+)|[\'\"](.*?)[\'\"])/) {
+	    if ($cat_line =~ m/(?:^|[^<])\<\<(\-?)\s*(?:(?!<|'|")((?:[^\s;]+(?:(?<=\\)[\s;])?)+)|[\'\"](.*?)[\'\"])/) {
 		$cat_indented = ($1 && $1 eq '-')? 1 : 0;
-		$cat_string = $2;
-		$cat_string = $3 if not defined $cat_string;
+		my $quoted = defined($3);
+		$cat_string = $quoted? $3 : $2;
+		unless ($quoted) {
+		    # Now strip backslashes. Keep the position of the
+		    # last match in a variable, as s/// resets it back
+		    # to undef, but we don't want that.
+		    my $pos = 0;
+		    pos($cat_string) = $pos;
+		    while ($cat_string =~ s/\G(.*?)\\/$1/) {
+			# postition += length of match + the character
+			# that followed the backslash:
+			$pos += length($1)+1;
+			pos($cat_string) = $pos;
+		    }
+		}
 		$start_lines{'cat_string'} = $.;
             }
 	}
-- 
1.7.10