Handle multi-line quoted variable assignments.
authorZac Medico <zmedico@gentoo.org>
Wed, 5 Mar 2008 19:51:12 +0000 (19:51 -0000)
committerZac Medico <zmedico@gentoo.org>
Wed, 5 Mar 2008 19:51:12 +0000 (19:51 -0000)
svn path=/main/trunk/; revision=9440

bin/filter-bash-environment.py

index 39aa4059f8b88695aca0d2b19c488273b57db67c..0db77ba5f1d84d5354abe1212ea86a2632c612a2 100755 (executable)
@@ -15,17 +15,50 @@ here_doc_re = re.compile(r'.*\s<<[-]?(\w+)$')
 func_start_re = re.compile(r'^[-\w]+\s*\(\)\s*$')
 func_end_re = re.compile(r'^\}$')
 
-var_assign_re = re.compile(r'(^|^declare\s+-\S+\s+|^export\s+)([^=\s]+)=.*$')
+var_assign_re = re.compile(r'(^|^declare\s+-\S+\s+|^export\s+)([^=\s]+)=("|\')?.*$')
+close_quote_re = re.compile(r'(\\"|"|\')\s*$')
 
 def compile_egrep_pattern(s):
        for k, v in egrep_compat_map.iteritems():
                s = s.replace(k, v)
        return re.compile(s)
 
+def have_end_quote(quote, line):
+       """
+       Check if the line has an end quote (useful for handling multi-line
+       quotes). This handles escaped double quotes that may occur at the
+       end of a line. The posix spec does not allow escaping of single
+       quotes inside of single quotes, so that case is not handled.
+       """
+       close_quote_match = close_quote_re.search(line)
+       return close_quote_match is not None and \
+               close_quote_match.group(0) == quote
+
 def filter_bash_environment(pattern, file_in, file_out):
        here_doc_delim = None
        in_func = None
+       multi_line_quote = None
+       multi_line_quote_filter = None
        for line in file_in:
+               if multi_line_quote is not None:
+                       if not multi_line_quote_filter:
+                               file_out.write(line)
+                       if have_end_quote(multi_line_quote, line):
+                               multi_line_quote = None
+                               multi_line_quote_filter = None
+                       continue
+               if here_doc_delim is None and in_func is None:
+                       var_assign_match = var_assign_re.match(line)
+                       if var_assign_match is not None:
+                               quote = var_assign_match.group(3)
+                               filter_this = pattern.match(var_assign_match.group(2)) \
+                                       is not None
+                               if quote is not None and not have_end_quote(quote, line):
+                                       multi_line_quote = quote
+                                       multi_line_quote_filter = filter_this
+                               if not filter_this:
+                                       file_out.write(line)
+                               continue
                if here_doc_delim is not None:
                        if here_doc_delim.match(line):
                                here_doc_delim = None
@@ -48,13 +81,9 @@ def filter_bash_environment(pattern, file_in, file_out):
                if in_func is not None:
                        file_out.write(line)
                        continue
-               var_assign_match = var_assign_re.match(line)
-               if var_assign_match is not None:
-                       if pattern.match(var_assign_match.group(2)) is None:
-                               file_out.write(line)
-                       continue
-               # TODO: properly handle multi-line variable assignments
-               # like those which the 'export' builtin can produce.
+               # This line is not recognized as part of a variable assignment,
+               # function definition, or here document, so just allow it to
+               # pass through.
                file_out.write(line)
 
 if __name__ == "__main__":