Implement a safer and more predictable interpolation approach.
Closes SF bug #511737.
diff --git a/Lib/ConfigParser.py b/Lib/ConfigParser.py
index c623ec9..6077022 100644
--- a/Lib/ConfigParser.py
+++ b/Lib/ConfigParser.py
@@ -538,3 +538,51 @@
         if value.find("%(") != -1:
             raise InterpolationDepthError(option, section, rawval)
         return value
+
+
+class SafeConfigParser(ConfigParser):
+
+    def _interpolate(self, section, option, rawval, vars):
+        # do the string interpolation
+        L = []
+        self._interpolate_some(option, L, rawval, section, vars, 1)
+        return ''.join(L)
+
+    _interpvar_match = re.compile(r"%\(([^)]+)\)s").match
+
+    def _interpolate_some(self, option, accum, rest, section, map, depth):
+        if depth > MAX_INTERPOLATION_DEPTH:
+            raise InterpolationDepthError(option, section, rest)
+        while rest:
+            p = rest.find("%")
+            if p < 0:
+                accum.append(rest)
+                return
+            if p > 0:
+                accum.append(rest[:p])
+                rest = rest[p:]
+            # p is no longer used
+            c = rest[1:2]
+            if c == "%":
+                accum.append("%")
+                rest = rest[2:]
+            elif c == "(":
+                m = self._interpvar_match(rest)
+                if m is None:
+                    raise InterpolationSyntaxError(
+                        "bad interpolation variable syntax at: %r" % rest)
+                var = m.group(1)
+                rest = rest[m.end():]
+                try:
+                    v = map[var]
+                except KeyError:
+                    raise InterpolationError(
+                        "no value found for %r" % var)
+                if "%" in v:
+                    self._interpolate_some(option, accum, v,
+                                           section, map, depth + 1)
+                else:
+                    accum.append(v)
+            else:
+                raise InterpolationSyntaxError(
+                    "'%' must be followed by '%' or '('")
diff --git a/Lib/test/test_cfgparser.py b/Lib/test/test_cfgparser.py
index 6d93c61..b221598 100644
--- a/Lib/test/test_cfgparser.py
+++ b/Lib/test/test_cfgparser.py
@@ -289,10 +289,25 @@
                                  ('name', 'value')])
 
 
+class SafeConfigParserTestCase(ConfigParserTestCase):
+    config_class = ConfigParser.SafeConfigParser
+
+    def test_safe_interpolation(self):
+        # See http://www.python.org/sf/511737
+        cf = self.fromstring("[section]\n"
+                             "option1=xxx\n"
+                             "option2=%(option1)s/xxx\n"
+                             "ok=%(option1)s/%%s\n"
+                             "not_ok=%(option2)s/%%s")
+        self.assertEqual(cf.get("section", "ok"), "xxx/%s")
+        self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s")
+
+
 def test_main():
     suite = unittest.TestSuite()
     suite.addTests([unittest.makeSuite(ConfigParserTestCase),
-                    unittest.makeSuite(RawConfigParserTestCase)])
+                    unittest.makeSuite(RawConfigParserTestCase),
+                    unittest.makeSuite(SafeConfigParserTestCase)])
     test_support.run_suite(suite)
 
 if __name__ == "__main__":