From: Mark Wooding Date: Sat, 1 Jun 2024 03:27:54 +0000 (+0100) Subject: fshash.in: Implement the `string_escape' conversion explicitly. X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/rsync-backup/commitdiff_plain/b6c1cd97598bd5180ebf34a9e243eb5cf7e1babd?ds=inline fshash.in: Implement the `string_escape' conversion explicitly. It's not available in Python 3. --- diff --git a/fshash.in b/fshash.in index ad6ff58..75d004f 100644 --- a/fshash.in +++ b/fshash.in @@ -41,8 +41,11 @@ VERSION = '@VERSION@' ###-------------------------------------------------------------------------- ### Utilities. +from cStringIO import StringIO; BytesIO = StringIO def bin(x): return x def text(x): return x +def bytechr(x): return chr(x) +def byteord(x): return ord(x) def excval(): return exc_info()[1] QUIS = OS.path.basename(argv[0]) @@ -60,6 +63,44 @@ def syserr(msg): moan(msg) SYSERR += 1 +def escapify(x): + out = StringIO() + for ch in bin(x): + k = byteord(ch) + if k == 9: out.write("\\t") + elif k == 10: out.write("\\n") + elif k == 13: out.write("\\r") + elif k == 39: out.write("\\'") + elif k == 92: out.write("\\\\") + elif 20 <= k <= 126: out.write(chr(k)) + else: out.write("\\x%02x" % k) + return out.getvalue() + +R_STRESC = RX.compile(r"\\ (?: x ([0-9A-Fa-f]{2}) | (.))", + RX.VERBOSE) +def unescapify(x): + str = BytesIO() + i, n = 0, len(x) + while True: + m = R_STRESC.search(x, i) + if m is not None: j = m.start(0) + else: j = n + str.write(bin(str[i:j])) + if m is None: break + k, e = m.group(1), m.group(2) + if k is not None: ch = int(k, 16) + elif ch == "a": ch = 7 + elif ch == "b": ch = 8 + elif ch == "f": ch = 12 + elif ch == "n": ch = 10 + elif ch == "r": ch = 13 + elif ch == "t": ch = 9 + elif ch == "v": ch = 11 + else: ch = byteord(e) + str.write(bytechr(ch)) + i = m.end(0) + return text(out.getvalue()) + ###-------------------------------------------------------------------------- ### File system enumeration. @@ -364,7 +405,7 @@ class GenericFormatter (object): tm = T.gmtime(t) return T.strftime('%Y-%m-%dT%H:%M:%SZ', tm) def _enc_name(me, n): - return ' \\-> '.join(n.encode('string_escape').split(' -> ')) + return ' \\-> '.join(escapify(n).split(' -> ')) def name(me): return me._enc_name(me.fi.name) def info(me): @@ -501,8 +542,8 @@ def clear_entry(db, lno, line): moan("failed to parse file entry (name split; line %d)" % lno) return False name, target = nn - target = target.decode('string_escape') - name = name.decode('string_escape') + target = unescapify(target) + name = unescapify(name) try: st = OS.lstat(name)