]> git.tdb.fi Git - gldbg.git/blob - generate.py
Fix things for 64-bit systems
[gldbg.git] / generate.py
1 #!/usr/bin/python
2
3 import sys
4 import os
5 import optparse
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, typemap, iomap):
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")):
146                                                 if s.kind=="value":
147                                                         self.csize = "%s"%self.size
148                                                         if strip_name(self.base_ctype)!="void":
149                                                                 self.csize += "*sizeof(%s)"%self.base_ctype
150                                                 elif s.kind=="array" and s.size==1:
151                                                         self.csize = "*%s"%s.name
152                                         if not self.csize:
153                                                 sys.stderr.write("Could not determine size for array parameter '%s[%s]' of function '%s'\n"%(self.name, self.size, self.func.name))
154                         elif self.kind=="reference":
155                                 self.csize = "sizeof(%s)"%self.base_ctype
156
157         def __init__(self, name, pnames):
158                 self.name = name
159                 self.ret = Function.Parameter(self, "ret")
160                 self.params = [Function.Parameter(self, n) for n in pnames]
161                 self.category = None
162
163         def get_param(self, pname):
164                 for p in self.params:
165                         if p.name==pname:
166                                 return p
167                 raise KeyError, pname
168
169         def set_category(self, cat):
170                 self.category = cat
171
172         def compsize(self, size, btype):
173                 if not size:
174                         return
175
176                 res = ""
177                 have_type = False
178                 for c in size.replace(',', '/').split('/'):
179                         param = self.get_param(c)
180                         if not param:
181                                 sys.stderr.write("Compsize '%s' for function '%s' failed: No parameter '%s'\n"%(size, self.name, c))
182                                 return
183
184                         if res:
185                                 res += "*"
186
187                         cn = strip_name(param.type)
188                         if cn.endswith("Type"):
189                                 res += "typesize(%s)"%param.name
190                                 have_type = True
191                         elif cn.endswith("Format"):
192                                 res += "formatsize(%s)"%param.name
193                         elif param.name=="pname" or cn.endswith("Parameter") or (param.name=="target" and cn=="enum"):
194                                 res += "paramsize(%s)"%param.name
195                         elif param.name=="buffer" and cn=="enum":
196                                 res += "buffersize(%s)"%param.name
197                         elif (cn=="SizeI" or cn.endswith("Int32")) and not param.size:
198                                 res += param.name
199                         else:
200                                 sys.stderr.write("Compsize '%s' for function '%s' failed: Parameter '%s' has unknown type '%s'\n"%(size, self.name, param.name, param.type))
201                                 return
202                 if not have_type:
203                         res += "*sizeof(%s)"%btype
204                 return res
205
206         def finalize(self, typemap, iomap):
207                 self.ret.derive_ctype(typemap, iomap)
208                 for p in self.params:
209                         p.derive_ctype(typemap, iomap)
210                 for p in self.params:
211                         p.derive_csize()
212
213
214 class Enum:
215         def __init__(self, name, category, value):
216                 self.name = name
217                 self.category = category
218                 self.value = value
219
220
221 class Template:
222         def __init__(self, fn):
223                 self.mode = "functions"
224                 self.sections = []
225                 self.handcode = []
226
227                 literal = True
228                 text = ""
229                 for line in InputFile(fn):
230                         if line[0]==':':
231                                 if not literal and text:
232                                         self.add_section(text, literal)
233                                         text = ""
234                                 text += line[1:]+"\n"
235                                 literal = True
236                         elif line[0]=='!':
237                                 parts = line[1:].split()
238                                 if parts[0]=="handcode":
239                                         self.handcode.append(parts[1])
240                                 elif parts[0]=="mode":
241                                         self.mode = parts[1]
242                                 else:
243                                         sys.stderr.write("Unknown keyword '%s'\n"%parts[0])
244                         else:
245                                 if literal and text:
246                                         self.add_section(text, literal)
247                                         text = ""
248                                 text += line+"\n"
249                                 literal = False
250                 if text:
251                         self.add_section(text, literal)
252
253         def add_section(self, text, literal):
254                 if literal:
255                         self.sections.append(text)
256                 else:
257                         self.sections.append(compile(text, "-", "exec"))
258
259         def write(self, str, *args):
260                 sys.stdout.write(str%args)
261
262         def writeln(self, str, *args):
263                 sys.stdout.write(str%args+"\n")
264
265         def process_function(self, code, func):
266                 if func.name in self.handcode:
267                         return
268
269                 globals = {
270                         "w": self.write,
271                         "wl": self.writeln,
272                         "func": func,
273                         "ret": func.ret,
274                         "params": func.params
275                 }
276                 eval(code, globals)
277
278         def process_enum(self, code, enum):
279                 if enum.value is None:
280                         return
281
282                 globals = {
283                         "w": self.write,
284                         "wl": self.writeln,
285                         "enum": enum
286                 }
287                 eval(code, globals)
288
289         def process_sections(self, objects, handler):
290                 for sect in self.sections:
291                         if type(sect)==str:
292                                 print sect
293                         else:
294                                 for obj in objects:
295                                         handler(sect, obj)
296
297         def process(self, apis):
298                 if self.mode=="functions":
299                         functions = []
300                         for api in apis:
301                                 typemap = Typemap(api.typemap)
302                                 iomap = IOmap(api.iomap)
303                                 for spec in api.specs:
304                                         funcs = read_spec(spec, api.prefix)
305                                         for err in api.errata:
306                                                 read_spec(err, api.prefix, funcs)
307                                         funcs = [f for f in funcs if f.name not in api.ignore_funcs and f.category not in api.ignore_categs]
308                                         for func in funcs:
309                                                 func.finalize(typemap, iomap)
310                                         names = [f.name for f in funcs]
311                                         functions = [f for f in functions if f.name not in names]+funcs
312                         self.process_sections(functions, self.process_function)
313                 elif self.mode=="enums":
314                         enums = []
315                         for api in apis:
316                                 for spec in api.enumspecs:
317                                         ens = read_enums(spec, api.enumprefix)
318                                         enums += ens
319                         enums.sort(lambda x, y: cmp(x.value, y.value)*2+cmp(x.category, y.category))
320                         self.process_sections(enums, self.process_enum)
321
322
323 class Api:
324         def __init__(self, fn):
325                 self.typemap = None
326                 self.iomap = None
327                 self.specs = []
328                 self.errata = []
329                 self.prefix = None
330                 self.enumspecs = []
331                 self.enumprefix = None
332                 self.ignore_categs = []
333                 self.ignore_funcs = []
334
335                 path = os.path.split(fn)[0]
336
337                 for line in InputFile(fn):
338                         parts = line.split()
339                         if parts[0]=="typemap":
340                                 self.typemap = os.path.join(path, parts[1])
341                         elif parts[0]=="iomap":
342                                 self.iomap = os.path.join(path, parts[1])
343                         elif parts[0]=="spec":
344                                 self.specs.append(os.path.join(path, parts[1]))
345                         elif parts[0]=="errata":
346                                 self.errata.append(os.path.join(path, parts[1]))
347                         elif parts[0]=="prefix":
348                                 self.prefix = parts[1]
349                         elif parts[0]=="enumspec":
350                                 self.enumspecs.append(os.path.join(path, parts[1]))
351                         elif parts[0]=="enumprefix":
352                                 self.enumprefix = parts[1]
353                         elif parts[0]=="ignore":
354                                 if parts[1]=="category":
355                                         self.ignore_categs.append(parts[2])
356                                 elif parts[1]=="function":
357                                         self.ignore_funcs.append(parts[2])
358                         else:
359                                 sys.stderr.write("Unknown keyword '%s'\n", parts[0])
360
361
362 def read_spec(fn, prefix, funcs=None):
363         if funcs is None:
364                 funcs = []
365         cur_func = None
366
367         for line in InputFile(fn):
368                 if line.find(':')>=0:
369                         continue
370                 elif line[0]=='\t' and cur_func:
371                         parts = line.split()
372                         if parts[0]=="return":
373                                 cur_func.ret.set_type(parts[1], "out", "value")
374                         elif parts[0]=="param":
375                                 bracket = parts[4].find('[')
376                                 if bracket>=0:
377                                         parts.insert(5, parts[4][bracket:])
378                                         parts[4] = parts[4][:bracket]
379
380                                 param = cur_func.get_param(parts[1])
381                                 param.set_type(parts[2], parts[3], parts[4])
382                                 if len(parts)==6 or (len(parts)>6 and parts[6]!="retained"):
383                                         param.set_size(parts[5][1:-1])
384                         elif parts[0]=="category":
385                                 cur_func.set_category(parts[1])
386                         elif parts[0]=="glxvendorglx" and cur_func.category=="glx":
387                                 cur_func.set_category("glxext")
388                 else:
389                         paren = line.find('(')
390                         if paren>0:
391                                 cparen = line.rfind(')')
392                                 if cparen>paren+1:
393                                         pnames = [n.strip() for n in line[paren+1:cparen].split(",")]
394                                 else:
395                                         pnames = []
396                                 fname = prefix+line[:paren]
397                                 cur_func = None
398                                 for f in funcs:
399                                         if f.name==fname:
400                                                 cur_func = f
401                                                 break
402                                 if not cur_func:
403                                         cur_func = Function(prefix+line[:paren], pnames)
404                                         funcs.append(cur_func)
405
406         return funcs
407
408 def read_enums(fn, prefix):
409         enums = []
410         cur_categ = []
411
412         for line in InputFile(fn):
413                 if ':' in line:
414                         parts = line[:line.find(':')].split()
415                         if len(parts)==2 and parts[1]=="enum":
416                                 cur_categ = parts[0]
417                 elif cur_categ:
418                         parts = line.split()
419                         if parts[0]=="use":
420                                 enums.append(Enum(prefix+parts[2], cur_categ, None))
421                         elif parts[1]=="=":
422                                 try:
423                                         enums.append(Enum(prefix+parts[0], cur_categ, int(parts[2], 0)))
424                                 except ValueError, e:
425                                         sys.stderr.write("Syntax error in %s: %s\n"%(fn, e))
426
427         for e in enums:
428                 if e.value is None:
429                         for n in enums:
430                                 if n.name==e.name and n.value is not None:
431                                         e.value = n.value
432                         if e.value is None:
433                                 sys.stderr.write("Could not find value for enum reference %s in category %s\n"%(e.name, e.category))
434
435         return enums
436
437 parser = optparse.OptionParser()
438 parser.add_option("--depends", dest="depends", default=False)
439 (options, args) = parser.parse_args()
440
441 template = Template(args[0])
442 apis = []
443 for i in args[1:]:
444         apis.append(Api(i))
445
446 if options.depends:
447         deps = args[:]
448         if template.mode=="functions":
449                 for api in apis:
450                         deps += api.specs
451                         deps.append(api.typemap)
452                         deps.append(api.iomap)
453         elif template.mode=="enums":
454                 for api in apis:
455                         deps += api.enumspecs
456         sys.stdout.write("%s: %s\n"%(options.depends, " ".join(deps)))
457 else:
458         template.process(apis)