1 | #! /usr/bin/env python
|
---|
2 |
|
---|
3 | # Read #define's and translate to Python code.
|
---|
4 | # Handle #include statements.
|
---|
5 | # Handle #define macros with one argument.
|
---|
6 | # Anything that isn't recognized or doesn't translate into valid
|
---|
7 | # Python is ignored.
|
---|
8 |
|
---|
9 | # Without filename arguments, acts as a filter.
|
---|
10 | # If one or more filenames are given, output is written to corresponding
|
---|
11 | # filenames in the local directory, translated to all uppercase, with
|
---|
12 | # the extension replaced by ".py".
|
---|
13 |
|
---|
14 | # By passing one or more options of the form "-i regular_expression"
|
---|
15 | # you can specify additional strings to be ignored. This is useful
|
---|
16 | # e.g. to ignore casts to u_long: simply specify "-i '(u_long)'".
|
---|
17 |
|
---|
18 | # XXX To do:
|
---|
19 | # - turn trailing C comments into Python comments
|
---|
20 | # - turn C Boolean operators "&& || !" into Python "and or not"
|
---|
21 | # - what to do about #if(def)?
|
---|
22 | # - what to do about macros with multiple parameters?
|
---|
23 |
|
---|
24 | import sys, re, getopt, os
|
---|
25 |
|
---|
26 | p_define = re.compile('^[\t ]*#[\t ]*define[\t ]+([a-zA-Z0-9_]+)[\t ]+')
|
---|
27 |
|
---|
28 | p_macro = re.compile(
|
---|
29 | '^[\t ]*#[\t ]*define[\t ]+'
|
---|
30 | '([a-zA-Z0-9_]+)\(([_a-zA-Z][_a-zA-Z0-9]*)\)[\t ]+')
|
---|
31 |
|
---|
32 | p_include = re.compile('^[\t ]*#[\t ]*include[\t ]+<([a-zA-Z0-9_/\.]+)')
|
---|
33 |
|
---|
34 | p_comment = re.compile(r'/\*([^*]+|\*+[^/])*(\*+/)?')
|
---|
35 | p_cpp_comment = re.compile('//.*')
|
---|
36 |
|
---|
37 | ignores = [p_comment, p_cpp_comment]
|
---|
38 |
|
---|
39 | p_char = re.compile(r"'(\\.[^\\]*|[^\\])'")
|
---|
40 |
|
---|
41 | p_hex = re.compile(r"0x([0-9a-fA-F]+)L?")
|
---|
42 |
|
---|
43 | filedict = {}
|
---|
44 | importable = {}
|
---|
45 |
|
---|
46 | try:
|
---|
47 | searchdirs=os.environ['include'].split(';')
|
---|
48 | except KeyError:
|
---|
49 | try:
|
---|
50 | searchdirs=os.environ['INCLUDE'].split(';')
|
---|
51 | except KeyError:
|
---|
52 | try:
|
---|
53 | if sys.platform.find("beos") == 0:
|
---|
54 | searchdirs=os.environ['BEINCLUDES'].split(';')
|
---|
55 | elif sys.platform.startswith("atheos"):
|
---|
56 | searchdirs=os.environ['C_INCLUDE_PATH'].split(':')
|
---|
57 | else:
|
---|
58 | raise KeyError
|
---|
59 | except KeyError:
|
---|
60 | searchdirs=['/usr/include']
|
---|
61 | try:
|
---|
62 | searchdirs.insert(0, os.path.join('/usr/include',
|
---|
63 | os.environ['MULTIARCH']))
|
---|
64 | except KeyError:
|
---|
65 | pass
|
---|
66 |
|
---|
67 |
|
---|
68 | def main():
|
---|
69 | global filedict
|
---|
70 | opts, args = getopt.getopt(sys.argv[1:], 'i:')
|
---|
71 | for o, a in opts:
|
---|
72 | if o == '-i':
|
---|
73 | ignores.append(re.compile(a))
|
---|
74 | if not args:
|
---|
75 | args = ['-']
|
---|
76 | for filename in args:
|
---|
77 | if filename == '-':
|
---|
78 | sys.stdout.write('# Generated by h2py from stdin\n')
|
---|
79 | process(sys.stdin, sys.stdout)
|
---|
80 | else:
|
---|
81 | fp = open(filename, 'r')
|
---|
82 | outfile = os.path.basename(filename)
|
---|
83 | i = outfile.rfind('.')
|
---|
84 | if i > 0: outfile = outfile[:i]
|
---|
85 | modname = outfile.upper()
|
---|
86 | outfile = modname + '.py'
|
---|
87 | outfp = open(outfile, 'w')
|
---|
88 | outfp.write('# Generated by h2py from %s\n' % filename)
|
---|
89 | filedict = {}
|
---|
90 | for dir in searchdirs:
|
---|
91 | if filename[:len(dir)] == dir:
|
---|
92 | filedict[filename[len(dir)+1:]] = None # no '/' trailing
|
---|
93 | importable[filename[len(dir)+1:]] = modname
|
---|
94 | break
|
---|
95 | process(fp, outfp)
|
---|
96 | outfp.close()
|
---|
97 | fp.close()
|
---|
98 |
|
---|
99 | def pytify(body):
|
---|
100 | # replace ignored patterns by spaces
|
---|
101 | for p in ignores:
|
---|
102 | body = p.sub(' ', body)
|
---|
103 | # replace char literals by ord(...)
|
---|
104 | body = p_char.sub("ord('\\1')", body)
|
---|
105 | # Compute negative hexadecimal constants
|
---|
106 | start = 0
|
---|
107 | UMAX = 2*(sys.maxint+1)
|
---|
108 | while 1:
|
---|
109 | m = p_hex.search(body, start)
|
---|
110 | if not m: break
|
---|
111 | s,e = m.span()
|
---|
112 | val = long(body[slice(*m.span(1))], 16)
|
---|
113 | if val > sys.maxint:
|
---|
114 | val -= UMAX
|
---|
115 | body = body[:s] + "(" + str(val) + ")" + body[e:]
|
---|
116 | start = s + 1
|
---|
117 | return body
|
---|
118 |
|
---|
119 | def process(fp, outfp, env = {}):
|
---|
120 | lineno = 0
|
---|
121 | while 1:
|
---|
122 | line = fp.readline()
|
---|
123 | if not line: break
|
---|
124 | lineno = lineno + 1
|
---|
125 | match = p_define.match(line)
|
---|
126 | if match:
|
---|
127 | # gobble up continuation lines
|
---|
128 | while line[-2:] == '\\\n':
|
---|
129 | nextline = fp.readline()
|
---|
130 | if not nextline: break
|
---|
131 | lineno = lineno + 1
|
---|
132 | line = line + nextline
|
---|
133 | name = match.group(1)
|
---|
134 | body = line[match.end():]
|
---|
135 | body = pytify(body)
|
---|
136 | ok = 0
|
---|
137 | stmt = '%s = %s\n' % (name, body.strip())
|
---|
138 | try:
|
---|
139 | exec stmt in env
|
---|
140 | except:
|
---|
141 | sys.stderr.write('Skipping: %s' % stmt)
|
---|
142 | else:
|
---|
143 | outfp.write(stmt)
|
---|
144 | match = p_macro.match(line)
|
---|
145 | if match:
|
---|
146 | macro, arg = match.group(1, 2)
|
---|
147 | body = line[match.end():]
|
---|
148 | body = pytify(body)
|
---|
149 | stmt = 'def %s(%s): return %s\n' % (macro, arg, body)
|
---|
150 | try:
|
---|
151 | exec stmt in env
|
---|
152 | except:
|
---|
153 | sys.stderr.write('Skipping: %s' % stmt)
|
---|
154 | else:
|
---|
155 | outfp.write(stmt)
|
---|
156 | match = p_include.match(line)
|
---|
157 | if match:
|
---|
158 | regs = match.regs
|
---|
159 | a, b = regs[1]
|
---|
160 | filename = line[a:b]
|
---|
161 | if importable.has_key(filename):
|
---|
162 | outfp.write('from %s import *\n' % importable[filename])
|
---|
163 | elif not filedict.has_key(filename):
|
---|
164 | filedict[filename] = None
|
---|
165 | inclfp = None
|
---|
166 | for dir in searchdirs:
|
---|
167 | try:
|
---|
168 | inclfp = open(dir + '/' + filename)
|
---|
169 | break
|
---|
170 | except IOError:
|
---|
171 | pass
|
---|
172 | if inclfp:
|
---|
173 | outfp.write(
|
---|
174 | '\n# Included from %s\n' % filename)
|
---|
175 | process(inclfp, outfp, env)
|
---|
176 | else:
|
---|
177 | sys.stderr.write('Warning - could not find file %s\n' %
|
---|
178 | filename)
|
---|
179 |
|
---|
180 | if __name__ == '__main__':
|
---|
181 | main()
|
---|