varexpand: handle backslashes like more like bash
authorZac Medico <zmedico@gentoo.org>
Tue, 28 Jun 2011 09:06:36 +0000 (02:06 -0700)
committerZac Medico <zmedico@gentoo.org>
Tue, 28 Jun 2011 09:06:36 +0000 (02:06 -0700)
For backslash expansion, this function used to behave like echo
-e, but that's not needed for our purposes. We want to behave like
bash does when expanding a variable assignment in a sourced file,
in which case it performs backslash removal for \\ and \$ but nothing
more. This will fix bash compatibility for the case reported in
bug #365033.

pym/portage/tests/util/test_varExpand.py
pym/portage/util/__init__.py

index 30aa390bff952506873e2a4bd68679b99445863f..9dd488ea3a04bcf0536ef8102ab074dc1f700bcf 100644 (file)
@@ -1,5 +1,5 @@
 # test_varExpand.py -- Portage Unit Testing Functionality
-# Copyright 2006 Gentoo Foundation
+# Copyright 2006-2010 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 from portage.tests import TestCase
@@ -21,6 +21,37 @@ class VarExpandTestCase(TestCase):
                                msg="Got %s != %s, from varexpand( %s, %s )" % \
                                        ( result, varDict[key], "${%s}" % key, varDict ) )
 
+       def testVarExpandBackslashes(self):
+               """
+               We want to behave like bash does when expanding a variable
+               assignment in a sourced file, in which case it performs
+               backslash removal for \\ and \$ but nothing more. Note that
+               we don't handle escaped quotes here, since genconfig() uses
+               shlex to handle that earlier.
+               """
+
+               varDict = {}
+               tests = [
+                       ("\\", "\\"),
+                       ("\\\\", "\\"),
+                       ("\\\\\\", "\\\\"),
+                       ("\\\\\\\\", "\\\\"),
+                       ("\\$", "$"),
+                       ("\\\\$", "\\$"),
+                       ("\\a", "\\a"),
+                       ("\\b", "\\b"),
+                       ("\\n", "\\n"),
+                       ("\\r", "\\r"),
+                       ("\\t", "\\t"),
+                       ("\\\"", "\\\""),
+                       ("\\'", "\\'"),
+               ]
+               for test in tests:
+                       result = varexpand( test[0], varDict )
+                       self.assertFalse( result != test[1],
+                               msg="Got %s != %s from varexpand( %s, %s )" \
+                               % ( result, test[1], test[0], varDict ) )
+
        def testVarExpandDoubleQuotes(self):
                
                varDict = { "a":"5" }
index 8c5352239836a0330a3c2b381a55437bf13f2de8..ece0806e20eff1aeaf194bd36ee0c98ac52587b6 100644 (file)
@@ -683,37 +683,24 @@ def varexpand(mystring, mydict=None):
                                newstring=newstring+" "
                                pos=pos+1
                        elif (mystring[pos]=="\\"):
-                               #backslash expansion time
+                               # For backslash expansion, this function used to behave like
+                               # echo -e, but that's not needed for our purposes. We want to
+                               # behave like bash does when expanding a variable assignment
+                               # in a sourced file, in which case it performs backslash
+                               # removal for \\ and \$ but nothing more. Note that we don't
+                               # handle escaped quotes here, since genconfig() uses shlex
+                               # to handle that earlier.
                                if (pos+1>=len(mystring)):
                                        newstring=newstring+mystring[pos]
                                        break
                                else:
-                                       a=mystring[pos+1]
-                                       pos=pos+2
-                                       if a=='a':
-                                               newstring=newstring+chr(0o07)
-                                       elif a=='b':
-                                               newstring=newstring+chr(0o10)
-                                       elif a=='e':
-                                               newstring=newstring+chr(0o33)
-                                       elif (a=='f') or (a=='n'):
-                                               newstring=newstring+chr(0o12)
-                                       elif a=='r':
-                                               newstring=newstring+chr(0o15)
-                                       elif a=='t':
-                                               newstring=newstring+chr(0o11)
-                                       elif a=='v':
-                                               newstring=newstring+chr(0o13)
-                                       elif a in ('\'', '"'):
-                                               # Quote removal is handled by shlex.
+                                       a = mystring[pos + 1]
+                                       pos = pos + 2
+                                       if a in ("\\", "$"):
+                                               newstring = newstring + a
+                                       else:
                                                newstring = newstring + mystring[pos-2:pos]
-                                               continue
-                                       elif a!='\n':
-                                               # Remove backslash only, as bash does. This takes care
-                                               # of \\. Note that we don't handle quotes here since
-                                               # quote removal is handled by shlex.
-                                               newstring=newstring+mystring[pos-1:pos]
-                                               continue
+                                       continue
                        elif (mystring[pos]=="$") and (mystring[pos-1]!="\\"):
                                pos=pos+1
                                if mystring[pos]=="{":