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