blob: 4f50d31e6baf921757a757c41aafa6eca9d360d8 [file] [log] [blame]
Martin v. Löwisef04c442008-03-19 05:04:44 +00001# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved.
2# Licensed to PSF under a Contributor Agreement.
3
4"""Safely evaluate Python string literals without using eval()."""
5
6import re
7
8simple_escapes = {"a": "\a",
9 "b": "\b",
10 "f": "\f",
11 "n": "\n",
12 "r": "\r",
13 "t": "\t",
14 "v": "\v",
15 "'": "'",
16 '"': '"',
17 "\\": "\\"}
18
19def escape(m):
20 all, tail = m.group(0, 1)
21 assert all.startswith("\\")
22 esc = simple_escapes.get(tail)
23 if esc is not None:
24 return esc
25 if tail.startswith("x"):
26 hexes = tail[1:]
27 if len(hexes) < 2:
28 raise ValueError("invalid hex string escape ('\\%s')" % tail)
29 try:
30 i = int(hexes, 16)
31 except ValueError:
32 raise ValueError("invalid hex string escape ('\\%s')" % tail)
33 else:
34 try:
35 i = int(tail, 8)
36 except ValueError:
37 raise ValueError("invalid octal string escape ('\\%s')" % tail)
38 return chr(i)
39
40def evalString(s):
41 assert s.startswith("'") or s.startswith('"'), repr(s[:1])
42 q = s[0]
43 if s[:3] == q*3:
44 q = q*3
45 assert s.endswith(q), repr(s[-len(q):])
46 assert len(s) >= 2*len(q)
47 s = s[len(q):-len(q)]
48 return re.sub(r"\\(\'|\"|\\|[abfnrtv]|x.{0,2}|[0-7]{1,3})", escape, s)
49
50def test():
51 for i in range(256):
52 c = chr(i)
53 s = repr(c)
54 e = evalString(s)
55 if e != c:
Martin v. Löwis8a5f8ca2008-03-19 05:33:36 +000056 print(i, c, s, e)
Martin v. Löwisef04c442008-03-19 05:04:44 +000057
58
59if __name__ == "__main__":
60 test()