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