blob: f30f3fd5a12c0b42dd6f3f200b6fadbd7a665eee [file] [log] [blame]
Guido van Rossum5dd52d31995-04-10 11:47:11 +00001# Utility module for 'icache.py': interpret tag tables and indirect nodes.
2
3# (This module is a bit chatty when confronted with the unexpected.)
4
5
6import regexp
7import string
8import ifile
9
10
11# Get the tag table of an open file, as a dictionary.
12# Seeks around in the file; after reading, the position is undefined.
13# Return an empty tag table if none is found.
14#
15def get_tags(f):
16 #
17 # First see if the last "node" is the end of tag table marker.
18 #
19 f.seek(0, 2) # Seek to EOF
20 end = f.tell()
21 buf = ifile.backup_node(f, end)
22 if not labelmatch(buf, 0, 'end tag table\n'):
23 return {} # No succes
24 #
25 # Next backup to the previous "node" -- the tag table itself.
26 #
27 ###print 'Getting prebuilt tag table...'
28 end = f.tell() - len(buf)
29 buf = ifile.backup_node(f, end)
30 label = 'tag table:\n'
31 if not labelmatch(buf, 0, label):
32 print 'Weird: end tag table marker but no tag table?'
33 print 'Node begins:', `buf[:50]`
34 return {}
35 #
36 # Now read the whole tag table.
37 #
38 end = f.tell() - len(buf) # Do this first!
39 buf = ifile.read_node(f, buf)
40 #
41 # First check for an indirection table.
42 #
43 indirlist = []
44 if labelmatch(buf, len(label), '(indirect)\n'):
45 indirbuf = ifile.backup_node(f, end)
46 if not labelmatch(indirbuf, 0, 'indirect:\n'):
47 print 'Weird: promised indirection table not found'
48 print 'Node begins:', `indirbuf[:50]`
49 # Carry on. Things probably won't work though.
50 else:
51 indirbuf = ifile.read_node(f, indirbuf)
52 indirlist = parse_indirlist(indirbuf)
53 #
54 # Now parse the tag table.
55 #
56 findtag = regexp.compile('^(.*[nN]ode:[ \t]*(.*))\177([0-9]+)$').match
57 i = 0
58 tags = {}
59 while 1:
60 match = findtag(buf, i)
61 if not match:
62 break
63 (a,b), (a1,b1), (a2,b2), (a3,b3) = match
64 i = b
65 line = buf[a1:b1]
66 node = string.lower(buf[a2:b2])
67 offset = eval(buf[a3:b3]) # XXX What if it overflows?
68 if tags.has_key(node):
69 print 'Duplicate key in tag table:', `node`
70 file, offset = map_offset(offset, indirlist)
71 tags[node] = file, offset, line
72 #
73 return tags
74
75
76# Return true if buf[i:] begins with a label, after lower case conversion.
77# The label argument must be in lower case.
78#
79def labelmatch(buf, i, label):
80 return string.lower(buf[i:i+len(label)]) == label
81
82
83# Parse the indirection list.
84# Return a list of (filename, offset) pairs ready for use.
85#
86def parse_indirlist(buf):
87 list = []
88 findindir = regexp.compile('^(.+):[ \t]*([0-9]+)$').match
89 i = 0
90 while 1:
91 match = findindir(buf, i)
92 if not match:
93 break
94 (a,b), (a1,b1), (a2,b2) = match
95 file = buf[a1:b1]
96 offset = eval(buf[a2:b2]) # XXX What if this gets overflow?
97 list.append(file, offset)
98 i = b
99 return list
100
101
102# Map an offset through the indirection list.
103# Return (filename, new_offset).
104# If the list is empty, return the given offset and an empty file name.
105#
106def map_offset(offset, indirlist):
107 if not indirlist:
108 return '', offset
109 #
110 # XXX This could be done more elegant.
111 #
112 filex, offx = indirlist[0]
113 for i in range(len(indirlist)):
114 file1, off1 = indirlist[i]
115 if i+1 >= len(indirlist):
116 file2, off2 = '', 0x7fffffff
117 else:
118 file2, off2 = indirlist[i+1]
119 if off1 <= offset < off2:
120 # Add offx+2 to compensate for extra header.
121 # No idea whether this is always correct.
122 return file1, offset-off1 + offx+2
123 #
124 # XXX Shouldn't get here.
125 #
126 print 'Oops, map_offset fell through'
127 return '', offset # Not likely to get good results