-
Notifications
You must be signed in to change notification settings - Fork 332
Expand file tree
/
Copy pathgen_python.py
More file actions
254 lines (221 loc) · 8.2 KB
/
gen_python.py
File metadata and controls
254 lines (221 loc) · 8.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
#!/usr/bin/env python3
""" SoLoud Python wrapper generator """
import soloud_codegen
fo = open("../glue/soloud.py", "w")
#
# from ctypes import *
#
# soloud_dll = CDLL("soloud_x86")
#
# myfunc = soloud_dll.myfunc
# myfunc.argtypes = [c_char_p, c_int, c_double]
# myfunc.restype = c_int
#
C_TO_PY_TYPES = {
"int":"ctypes.c_int",
"void":"None",
"const char *":"ctypes.c_char_p",
"char *":"ctypes.c_char_p",
"unsigned int":"ctypes.c_uint",
"float":"ctypes.c_float",
"double":"ctypes.c_double",
"float *":"ctypes.POINTER(ctypes.c_float * 256)",
"File *":"ctypes.c_void_p",
"unsigned char *":"ctypes.POINTER(ctypes.c_ubyte)",
"const unsigned char *":"ctypes.POINTER(ctypes.c_ubyte)",
"unsigned char":"ctypes.c_ubyte",
"short *":"ctypes.POINTER(ctypes.c_short)"
}
for soloud_type in soloud_codegen.soloud_type:
C_TO_PY_TYPES[soloud_type + " *"] = "ctypes.c_void_p"
def fudge_types(origtype):
""" Map ctypes to parameter types """
return C_TO_PY_TYPES[origtype]
def pythonize_camelcase(origstr):
""" Turns camelCase into underscore_style """
ret = ""
for letter in origstr:
if letter.isupper():
ret += '_' + letter.lower()
else:
ret += letter
# kludge, because calc_f_f_t is silly.
ret = ret.replace("_f_f_t", "_fft")
# kludge for 3d calls
ret = ret.replace("3d", "_3d")
return ret
def has_ex_variant(funcname):
""" Checks if this function has an "Ex" variant """
if funcname[-2::] == "Ex":
# Already an Ex..
return False
for func in soloud_codegen.soloud_func:
if func[1] == (funcname + "Ex"):
return True
return False
bootstrap = '''\
# SoLoud wrapper for Python
# This file is autogenerated; any changes will be overwritten
# See: http://sol.gfxile.net/soloud/codegen.html
import ctypes
import sys
import os
soloud_dll = None
try:
for filename in ['soloud_x86','soloud_x64','libsoloud_x64.so']:
try:
soloud_dll = ctypes.CDLL("%s/%s" %(os.path.dirname(os.path.abspath(__file__)), filename))
break
except FileNotFoundError:
# on windows, we get an explicit FileNotFoundError
continue
except OSError as e:
# but on linux, we don't
if 'No such file or directory' in str(e):
continue
else:
raise e
if soloud_dll == None:
raise Exception("SoLoud dynamic library not found in %s " % (os.path.dirname(os.path.abspath(__file__))))
except BaseException as e:
print("Error while loading Soloud dynamic library on %s %sbit" % (sys.platform, sys.maxsize.bit_length()+1))
print(e)
sys.exit()
'''
fo.write(bootstrap)
# Since there's no reason to use the "raw" data anymore,
# skip generating the enum dictionary
#
#fo.write("# Enumerations\n")
#fo.write("soloud_enum = {\n")
#first = True
#for x in soloud_codegen.soloud_enum:
# if first:
# first = False
# else:
# fo.write(",\n")
# fo.write('"' + x + '": ' + str(soloud_codegen.soloud_enum[x]))
#fo.write("\n}\n")
fo.write("\n")
fo.write("# Raw DLL functions\n")
for x in soloud_codegen.soloud_func:
fo.write(x[1] + ' = soloud_dll.' + x[1] + '\n')
fo.write(x[1] + '.restype = ' + fudge_types(x[0]) + '\n')
fo.write(x[1] + '.argtypes = [')
first = True
for y in x[2]:
if len(y) > 0:
if first:
first = False
else:
fo.write(", ")
fo.write(fudge_types(y[0]))
fo.write(']\n')
fo.write('\n')
#################################################################
#
# oop
#
# class cname(object):
# def __init__(self):
# self.objhandle = cname_create()
# def __enter__(self):
# return self
# def __exit__(self, eType, eValue, eTrace):
# cname_destroy(self.objhandle)
# return False
# def close(self)
# cname_destroy(self.objhandle)
#
fo.write('# OOP wrappers\n')
def fix_default_param(defparam, classname):
""" 'fixes' default parameters from C to what python expectes """
if defparam == 'false':
defparam = 'False'
if defparam == 'true':
defparam = 'True'
if (classname + '::') == defparam[0:len(classname)+2:]:
return defparam[len(classname)+2::]
elif defparam.startswith('Soloud::'):
return 'Soloud.%s'%(defparam[8:])
if defparam[len(defparam)-1] == "f":
return defparam[0:len(defparam)-1]
return defparam
for x in soloud_codegen.soloud_type:
first = True
for y in soloud_codegen.soloud_func:
if (x + "_") == y[1][0:len(x)+1:]:
if first:
fo.write('\n')
fo.write('class %s(object):\n'%(x))
for z in soloud_codegen.soloud_enum:
if z[0:len(x)+1] == x.upper()+'_':
s = str(soloud_codegen.soloud_enum[z])
fo.write('\t%s = %s\n'%(z[len(x)+1::], s))
fo.write('\tdef __init__(self):\n')
fo.write('\t\tself.objhandle = %s_create()\n'%(x))
fo.write('\tdef __enter__(self):\n')
fo.write('\t\treturn self\n')
fo.write('\tdef __exit__(self, eType, eValue, eTrace):\n')
fo.write('\t\t%s_destroy(self.objhandle)\n'%(x))
fo.write('\t\tself.objhandle = ctypes.c_void_p(0)\n')
fo.write('\t\treturn False\n')
# Not sure which of the "destroy" funcs would be most suitable,
# so let's generate three equally suitable options
fo.write('\tdef close(self):\n')
fo.write('\t\t%s_destroy(self.objhandle)\n'%(x))
fo.write('\t\tself.objhandle = ctypes.c_void_p(0)\n')
fo.write('\tdef destroy(self):\n')
fo.write('\t\t%s_destroy(self.objhandle)\n'%(x))
fo.write('\t\tself.objhandle = ctypes.c_void_p(0)\n')
fo.write('\tdef quit(self):\n')
fo.write('\t\t%s_destroy(self.objhandle)\n'%(x))
fo.write('\t\tself.objhandle = ctypes.c_void_p(0)\n')
first = False
funcname = y[1][len(x)+1::]
# If the function has the name "Ex", remove the subfix
if funcname[-2::] == "Ex":
funcname = funcname[:len(funcname)-2]
# Skip generating functions that have an Ex variant
if funcname == "create" or funcname == "destroy" or has_ex_variant(y[1]):
pass # omit create/destroy, handled by __exit__ / close
else:
fo.write('\tdef %s(self'%(pythonize_camelcase(funcname)))
for z in y[2]:
if len(z) > 1:
if z[1] == 'a'+x:
pass # skip the 'self' pointer
else:
fo.write(', ' + z[1])
if len(z) > 2:
fo.write(' = ' + fix_default_param(z[2], x))
fo.write('):\n')
fo.write('\t\t')
floatbufreturn = False
if y[0] == 'void':
pass
elif y[0] == 'float *':
floatbufreturn = True
fo.write('floatbuf = ')
else:
fo.write('return ')
fo.write(y[1] + '(self.objhandle')
for z in y[2]:
if len(z) > 1:
if z[1] == 'a'+x:
pass # skip the 'self' pointer
else:
fo.write(', ')
fudged_type = fudge_types(z[0])
if fudged_type == 'ctypes.c_void_p':
fo.write(z[1] + '.objhandle')
else:
if fudged_type == 'ctypes.c_char_p':
fo.write(fudged_type + '(' + z[1] + ".encode('utf-8'))")
else:
fo.write(fudged_type + '(' + z[1] + ')')
fo.write(')\n')
if floatbufreturn:
fo.write('\t\treturn [f for f in floatbuf.contents]\n')
print("soloud.py generated")
fo.close()