11#! /usr/local/bin/python
22
3- # Read #define's from stdin and translate to Python code on stdout.
4- # Very primitive: non-#define's are ignored, as is anything that isn't
5- # valid Python as it stands.
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.
610# If one or more filenames are given, output is written to corresponding
711# filenames in the local directory, translated to all uppercase, with
812# the extension replaced by ".py".
13+
914# By passing one or more options of the form "-i regular_expression"
1015# you can specify additional strings to be ignored. This is useful
1116# e.g. to ignore casts to u_long: simply specify "-i '(u_long)'".
1217
1318# XXX To do:
1419# - turn trailing C comments into Python comments
15- # - turn C string quotes into Python comments
1620# - turn C Boolean operators "&& || !" into Python "and or not"
1721# - what to do about #if(def)?
18- # - what to do about #include?
19- # - what to do about macros with parameters?
20- # - reject definitions with semicolons in them
22+ # - what to do about macros with multiple parameters?
2123
22- import sys , regex , string , getopt , os
24+ import sys , regex , regsub , string , getopt , os
2325
2426p_define = regex .compile ('^#[\t ]*define[\t ]+\([a-zA-Z0-9_]+\)[\t ]+' )
2527
28+ p_macro = regex .compile (
29+ '^#[\t ]*define[\t ]+\([a-zA-Z0-9_]+\)(\([_a-zA-Z][_a-zA-Z0-9]*\))[\t ]+' )
30+
31+ p_include = regex .compile ('^#[\t ]*include[\t ]+<\([a-zA-Z0-9_/\.]+\)' )
32+
2633p_comment = regex .compile ('/\*\([^*]+\|\*+[^/]\)*\(\*+/\)?' )
2734
2835ignores = [p_comment ]
2936
37+ p_char = regex .compile ("'\(\\ \\ .[^\\ \\ ]*\|[^\\ \\ ]\)'" )
38+
39+ filedict = {}
40+
3041def main ():
3142 opts , args = getopt .getopt (sys .argv [1 :], 'i:' )
3243 for o , a in opts :
@@ -47,40 +58,65 @@ def main():
4758 outfile = outfile + '.py'
4859 outfp = open (outfile , 'w' )
4960 outfp .write ('# Generated by h2py from %s\n ' % filename )
61+ filedict = {}
62+ if filename [:13 ] == '/usr/include/' :
63+ filedict [filename [13 :]] = None
5064 process (fp , outfp )
5165 outfp .close ()
5266 fp .close ()
5367
54- def process (fp , outfp ):
55- env = {}
68+ def process (fp , outfp , env = {}):
5669 lineno = 0
5770 while 1 :
5871 line = fp .readline ()
5972 if not line : break
6073 lineno = lineno + 1
61- # gobble up continuation lines
62- while line [- 2 :] == '\\ \n ' :
63- nextline = fp .readline ()
64- if not nextline : break
65- lineno = lineno + 1
66- line = line + nextline
6774 n = p_define .match (line )
6875 if n >= 0 :
76+ # gobble up continuation lines
77+ while line [- 2 :] == '\\ \n ' :
78+ nextline = fp .readline ()
79+ if not nextline : break
80+ lineno = lineno + 1
81+ line = line + nextline
6982 name = p_define .group (1 )
7083 body = line [n :]
7184 # replace ignored patterns by spaces
7285 for p in ignores :
73- while p . search ( body ) >= 0 :
74- a , b = p . regs [ 0 ]
75- body = body [: a ] + ' ' + body [ b :]
86+ body = regsub . gsub ( p , ' ' , body )
87+ # replace char literals by ord(...)
88+ body = regsub . gsub ( p_char , 'ord( \\ 0)' , body )
7689 stmt = '%s = %s\n ' % (name , string .strip (body ))
7790 ok = 0
7891 try :
7992 exec stmt in env
80- ok = 1
8193 except :
8294 sys .stderr .write ('Skipping: %s' % stmt )
83- if ok :
95+ else :
8496 outfp .write (stmt )
85-
97+ n = p_macro .match (line )
98+ if n >= 0 :
99+ macro , arg = p_macro .group (1 , 2 )
100+ body = line [n :]
101+ for p in ignores :
102+ body = regsub .gsub (p , ' ' , body )
103+ body = regsub .gsub (p_char , 'ord(\\ 0)' , body )
104+ stmt = 'def %s(%s): return %s\n ' % (macro , arg , body )
105+ try :
106+ exec stmt in env
107+ except :
108+ sys .stderr .write ('Skipping: %s' % stmt )
109+ else :
110+ outfp .write (stmt )
111+ if p_include .match (line ) >= 0 :
112+ regs = p_include .regs
113+ a , b = regs [1 ]
114+ filename = line [a :b ]
115+ if not filedict .has_key (filename ):
116+ filedict [filename ] = None
117+ outfp .write (
118+ '\n # Included from %s\n ' % filename )
119+ inclfp = open ('/usr/include/' + filename , 'r' )
120+ process (inclfp , outfp , env )
86121main ()
122+
0 commit comments