]> git.tdb.fi Git - gldbg.git/blob - genwrap.py
f507ce2aab80c792bf2d3656e47b6a41ee68da62
[gldbg.git] / genwrap.py
1 #!/usr/bin/python
2 # $Id$
3
4 import sys
5 import os
6
7 def strip_name(name):
8         """Strips any vendor suffix and GL prefix from a name (but not GLX prefix)"""
9
10         suffix = ""
11         if name.endswith(" *"):
12                 suffix = " *"
13                 name = name[:-2]
14         elif name.endswith("Pointer"):
15                 suffix = "Pointer"
16                 name = name[:-7]
17
18         prefix = ""
19         if name.startswith("const "):
20                 prefix = "const "
21                 name = name[6:]
22
23         if name.startswith("GL") and not name.startswith("GLX"):
24                 name = name[2:]
25         if name.endswith(("EXT", "ARB", "SGI", "IBM", "ATI")):
26                 return prefix+name[:-3]+suffix
27         elif name.endswith("SGIX"):
28                 return prefix+name[:-4]+suffix
29         elif name.endswith(("NV", "HP")):
30                 return prefix+name[:-2]+suffix
31         else:
32                 return prefix+name+suffix
33
34
35 class Typemap:
36         def __init__(self, fn):
37                 self.map = {}
38                 for line in open(fn):
39                         if line[0]=='#':
40                                 continue
41                         parts = [p.strip() for p in line.split(',')]
42                         if parts[3]=="*":
43                                 parts[3] = parts[0]
44                         elif parts[3][-1]=='*' and parts[3][-2]!=' ':
45                                 parts[3] = parts[3][:-1]+" *"
46                         self.map[tuple(parts[0:3])] = tuple(parts[3:6])
47
48         def wildcard_match(self, a, b):
49                 if a=="*" or b=="*":
50                         return True
51                 return a==b
52
53         def __getitem__(self, key):
54                 return self.map[(key[0], "*", "*")]
55                 for k, v in self.map.iteritems():
56                         if strip_name(k[0])==strip_name(key[0]) and self.wildcard_match(k[1], key[1]) and self.wildcard_match(k[2], key[2]):
57                                 return v
58                 raise KeyError, key
59
60         def update(self, other):
61                 self.map.update(other.map)
62
63
64 class IOmap:
65         def __init__(self, fn):
66                 self.map = {}
67                 self.map["void"] = None
68                 for line in open(fn):
69                         if line[0]=='#':
70                                 continue
71                         parts = [p.strip() for p in line.split(',')]
72                         self.map[parts[0]] = tuple(parts[1:])
73
74         def __getitem__(self, key):
75                 return self.map[strip_name(key)]
76
77
78 class Function:
79         class Parameter:
80                 def __init__(self, func, name):
81                         self.func = func
82                         self.name = name
83                         self.type = None
84                         self.direction = "in"
85                         self.kind = "value"
86                         self.size = None
87                         self.ctype = None
88                         self.csize = None
89                         self.io = None
90
91                 def set_type(self, type, dir, kind):
92                         self.type = type
93                         self.direction = dir
94                         self.kind = kind
95                         self.ctype = typemap[(type, dir, kind)][0]
96                         self.base_ctype = self.ctype
97                         if self.kind=="value":
98                                 if self.base_ctype.startswith("const "):
99                                         self.base_ctype = self.base_ctype[6:]
100                                 self.io = iomap[self.base_ctype]
101                         else:
102                                 if self.direction=="in":
103                                         self.ctype = "const "+self.ctype
104                                 self.ctype = self.ctype+" *"
105                         #print "%s | %s | %s | %s | %s"%(self.func.name, self.name, self.type, self.ctype, self.base_ctype)
106
107                 def set_size(self, size):
108                         if type(size)==str and size.isdigit():
109                                 self.size = int(size)
110                         else:
111                                 self.size = size
112
113                 def finalize(self):
114                         if self.kind=="array":
115                                 self.csize = None
116                                 if type(self.size)==int:
117                                         self.csize = "%d*sizeof(%s)"%(self.size, self.base_ctype)
118                                 elif self.size.startswith("COMPSIZE("):
119                                         self.csize = compsize(self.func, self.size[9:-1], self.base_ctype)
120                                 elif self.size=="" and (self.type=="charARB" or self.type=="Char"):
121                                         self.csize = "strlen"
122                                 else:
123                                         s = self.func.get_param(self.size.split('*')[0])
124                                         if (s.type=="SizeI" or s.type.endswith("Int32") or s.type.startswith("BufferSize")) and s.kind=="value":
125                                                 self.csize = "%s*sizeof(%s)"%(self.size, self.base_ctype)
126                                                 if self.func.name.startswith("Uniform") and self.func.name[7].isdigit():
127                                                         self.csize += "*%s"%func.name[7]
128                                         if not self.csize:
129                                                 sys.stderr.write("Could not determine size for array parameter '%s[%s]' of function '%s'\n"%(self.name, self.size, self.func.name))
130                         elif self.kind=="reference":
131                                 self.csize = "sizeof(%s)"%self.base_ctype
132
133         def __init__(self, name, pnames):
134                 self.name = name
135                 self.ret = Function.Parameter(self, "ret")
136                 self.params = [Function.Parameter(self, n) for n in pnames]
137                 self.category = None
138
139         def get_param(self, pname):
140                 for p in self.params:
141                         if p.name==pname:
142                                 return p
143                 raise KeyError, pname
144
145         def set_category(self, cat):
146                 self.category = cat
147
148         def finalize(self):
149                 for p in self.params:
150                         p.finalize()
151
152
153 def read_spec(fn, prefix):
154         funcs = []
155         cur_func = None
156         for line in open(fn):
157                 if line[0]=='#' or line.find(':')>=0:
158                         continue
159                 elif line[0]=='\t' and cur_func:
160                         parts = line.split()
161                         if parts[0]=="return":
162                                 cur_func.ret.set_type(parts[1], "out", "value")
163                         elif parts[0]=="param":
164                                 bracket = parts[4].find('[')
165                                 if bracket>=0:
166                                         parts.insert(5, parts[4][bracket:])
167                                         parts[4] = parts[4][:bracket]
168
169                                 param = cur_func.get_param(parts[1])
170                                 param.set_type(parts[2], parts[3], parts[4])
171                                 if len(parts)>=6:
172                                         param.set_size(parts[5][1:-1])
173                         elif parts[0]=="category":
174                                 cur_func.set_category(parts[1])
175                         elif parts[0]=="glxvendorglx" and cur_func.category=="glx":
176                                 cur_func.set_category("glxext")
177                 else:
178                         paren = line.find('(')
179                         if paren>0:
180                                 cparen = line.rfind(')')
181                                 if cparen>paren+1:
182                                         pnames = [n.strip() for n in line[paren+1:cparen].split(",")]
183                                 else:
184                                         pnames = []
185                                 cur_func = Function(prefix+line[:paren], pnames)
186                                 funcs.append(cur_func)
187         for f in funcs:
188                 f.finalize()
189         return funcs
190
191 typemap = None
192 iomap = None
193 functions = []
194 sections = []
195
196 def add_section(text, literal):
197         global sections
198
199         if literal:
200                 sections.append(text)
201         else:
202                 sections.append(compile(text, "-", "exec"))
203
204 def read_template(fn):
205         global typemap
206         global iomap
207         global functions
208
209         literal = True
210         text = ""
211         for line in open(fn):
212                 if line[0]=='#':
213                         continue
214                 elif line[0]=='^':
215                         parts = line[1:].split()
216                         if parts[0]=="typemap":
217                                 typemap = Typemap(parts[1])
218                         elif parts[0]=="iomap":
219                                 iomap = IOmap(parts[1])
220                         elif parts[0]=="spec":
221                                 functions = read_spec(parts[2], parts[1])
222                 elif line[0]==':':
223                         if not literal and text:
224                                 add_section(text, literal)
225                                 text = ""
226                         text += line[1:]
227                         literal = True
228                 else:
229                         if literal and text:
230                                 add_section(text, literal)
231                                 text = ""
232                         text += line
233                         literal = False
234         if text:
235                 add_section(text, literal)
236
237 def compsize(func, size, btype):
238         if not size:
239                 return
240
241         res = ""
242         have_type = False
243         for c in size.replace(',', '/').split('/'):
244                 param = func.get_param(c)
245                 if not param:
246                         sys.stderr.write("Compsize '%s' for function '%s' failed: No parameter '%s'\n"%(size, func.name, c))
247                         return
248
249                 if res:
250                         res += "*"
251
252                 cn = strip_name(param.type)
253                 if cn.endswith("Type"):
254                         res += "typesize(%s)"%param.name
255                         have_type = True
256                 elif cn.endswith("Format"):
257                         res += "formatsize(%s)"%param.name
258                 elif cn.endswith(("Parameter", "ParameterPName", "ParameterName")) or cn=="GetPName":
259                         res += "paramsize(%s)"%param.name
260                 elif cn=="MapTarget":
261                         res += "mapsize(%s)"%param.name
262                 elif (cn=="SizeI" or cn.endswith("Int32")) and not param.size:
263                         res += param.name
264                 else:
265                         sys.stderr.write("Compsize '%s' for function '%s' failed: Parameter '%s' has unknown type '%s'\n"%(size, func.name, param.name, param.type))
266                         return
267         if not have_type:
268                 res += "*sizeof(%s)"%param.ctype
269         return res
270
271 read_template(sys.argv[1])
272
273 def write(str, *args):
274         sys.stdout.write(str%args)
275
276 def writeln(str, *args):
277         sys.stdout.write(str%args+"\n")
278
279 for sect in sections:
280         if type(sect)==str:
281                 print sect
282         else:
283                 for func in functions:
284                         globals = {
285                                 "w": write,
286                                 "wl": writeln,
287                                 "func": func,
288                                 "ret": func.ret,
289                                 "params": func.params
290                         }
291                         eval(sect, globals)