X-Git-Url: http://git.tdb.fi/?p=gldbg.git;a=blobdiff_plain;f=genwrap.py;h=07dd914f09d20b9a5bcda4adf6fa2000f33caf52;hp=da23cb331880292920fa98805f32b92e9c90de51;hb=9cdca19aa017ea1711436977855e885d91e78ab0;hpb=8b398bfe13b0884191b1fac56f274d395fd9d4dd diff --git a/genwrap.py b/genwrap.py index da23cb3..07dd914 100755 --- a/genwrap.py +++ b/genwrap.py @@ -4,318 +4,351 @@ import sys import os -outdir="gensrc" - -typemap = {} -for line in open("gl.tm"): - if line[0]=='#': - continue - parts = [p.strip() for p in line.split(',')] - typemap[parts[0]] = parts[3] -typemap["void"] = "void" - -def getparam(func, name): - for p in func[2]: - if p[0]==name: - return p - -funcs = [] -cur_func = None -for line in open("gl.spec"): - if line[0]=='#' or line.find(':')>=0: - continue - elif line[0]=='\t' and cur_func: - parts = line.split() - if parts[0]=="return": - cur_func[1] = typemap[parts[1]] - elif parts[0]=="param": - p = getparam(cur_func, parts[1]) - p[2] = parts[2] - p[1] = typemap[parts[2]] - if parts[4]=="array": - p[1] += " *" - if parts[3]=="in": - p[1] = "const "+p[1] - s = parts[5][1:-1] - if s.isdigit(): - p[3] = int(s) - elif s=="" or (len(parts)>=7 and parts[6]=="retained"): - p[3] = "~" - else: - p[3] = s +class InputFile: + def __init__(self, fn): + self.file = open(fn) + + def __iter__(self): + for l in self.file: + h = l.find("#") + if h==0 or (h>0 and l[h-1].isspace()): + l = l[:h] + + l = l.rstrip() + if not l: + continue + + yield l + + +def strip_name(name): + """Strips any vendor suffix and GL prefix from a name (but not GLX prefix)""" + + suffix = "" + if name.endswith(" *"): + suffix = " *" + name = name[:-2] + elif name.endswith("Pointer"): + suffix = "Pointer" + name = name[:-7] + + prefix = "" + if name.startswith("const "): + prefix = "const " + name = name[6:] + + if name.startswith("GL") and not name.startswith("GLX"): + name = name[2:] + if name.endswith(("EXT", "ARB", "SGI", "IBM", "ATI")): + return prefix+name[:-3]+suffix + elif name.endswith("SGIX"): + return prefix+name[:-4]+suffix + elif name.endswith(("NV", "HP")): + return prefix+name[:-2]+suffix else: - paren = line.find('(') - if paren>0: - cparen = line.rfind(')') - if cparen>paren+1: - args = line[paren+1:cparen].split(", ") + return prefix+name+suffix + + +class Typemap: + def __init__(self, fn): + self.map = {} + for line in InputFile(fn): + parts = [p.strip() for p in line.split(',')] + if parts[3]=="*": + parts[3] = parts[0] + elif parts[3][-1]=='*' and parts[3][-2]!=' ': + parts[3] = parts[3][:-1]+" *" + self.map[tuple(parts[0:3])] = tuple(parts[3:6]) + + def wildcard_match(self, a, b): + if a=="*" or b=="*": + return True + return a==b + + def __getitem__(self, key): + try: + return self.map[(key[0], "*", "*")] + except KeyError: + for k, v in self.map.iteritems(): + 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]): + return v + raise KeyError, key + + def update(self, other): + self.map.update(other.map) + + +class IOmap: + def __init__(self, fn): + self.map = {} + self.map["void"] = None + for line in InputFile(fn): + parts = [p.strip() for p in line.split(',')] + self.map[parts[0]] = tuple(parts[1:]) + + def __getitem__(self, key): + return self.map[strip_name(key)] + + +class Function: + class Parameter: + def __init__(self, func, name): + self.func = func + self.name = name + self.type = None + self.direction = "in" + self.kind = "value" + self.size = None + self.ctype = None + self.csize = None + self.io = None + + def set_type(self, type, dir, kind): + self.type = type + self.direction = dir + self.kind = kind + + def set_size(self, size): + if type(size)==str and size.isdigit(): + self.size = int(size) + else: + self.size = size + + def derive_ctype(self): + m = typemap[(self.type, self.direction, self.kind)] + self.ctype = m[0] + if m[1]!="*": + self.direction = m[1] + if m[2]!="*": + self.kind = m[2] + self.base_ctype = self.ctype + if self.kind=="value": + if self.base_ctype.startswith("const "): + self.base_ctype = self.base_ctype[6:] else: - args = [] - cur_func = [line[:paren], None, [[a, None, None, 0] for a in args]] - funcs.append(cur_func) - -fmtmap = {"GLenum":"%#x", - "GLboolean":"%i", - "GLbitfield":"%#x", - "GLbyte":"%i", - "GLshort":"%i", - "GLint":"%i", - "GLubyte":"%u", - "GLushort":"%u", - "GLuint":"%u", - "GLsizei":"%i", - "GLfloat":"%f", - "GLclampf":"%f", - "GLdouble":"%lf", - "GLclampd":"%lf", - "const GLubyte *":"%s", - "GLchar *":"%s", - "GLcharARB *":"%s", - "GLvoid*":"%p", - "GLsizeiptr":"%d", - "GLsizeiptrARB":"%d", - "GLintptr":"%d", - "GLintptrARB":"%d", - "GLhandleARB":"%i", - "GLhalfNV":"%#x", - "GLuint64EXT":"%lld"} - -iomap = {"GLenum":"int", - "GLboolean":"char", - "GLbitfield":"int", - "GLbyte":"char", - "GLshort":"short", - "GLint":"int", - "GLubyte":"char", - "GLushort":"short", - "GLuint":"int", - "GLsizei":"int", - "GLfloat":"float", - "GLclampf":"float", - "GLdouble":"double", - "GLclampd":"double", - "const GLubyte *":"string", - "GLchar *":"string", - "GLcharARB *":"string", - "GLvoid*":"pointer", - "GLsizeiptr":"int", - "GLsizeiptrARB":"int", - "GLintptr":"int", - "GLintptrARB":"int", - "GLhandleARB":"int", - "GLhalfNV":"short", - "GLuint64EXT":"longlong"} - -def basetype(type, is_array): - if type.startswith("const "): - type = type[6:] - if is_array and type.endswith(" *"): - type = type[:-2] - return type - -def compsize(func, size, ptype): - if not size: - return - - res = "" - have_type = False - for c in size.split('/'): - p = getparam(func, c) - if not p: + if self.direction=="in": + self.ctype = "const "+self.ctype + self.ctype = self.ctype+" *" + self.io = iomap[self.base_ctype] + + def derive_csize(self): + if self.kind=="array" and self.size is not None: + self.csize = None + if type(self.size)==int: + self.csize = "%d*sizeof(%s)"%(self.size, self.base_ctype) + elif self.size.startswith("COMPSIZE("): + self.csize = self.func.compsize(self.size[9:-1], self.base_ctype) + elif self.size=="pname": + self.csize = "paramsize(pname)*sizeof(%s)"%self.base_ctype + else: + s = self.func.get_param(self.size.split('*')[0]) + if (s.type=="SizeI" or s.type.endswith("Int32") or s.type.startswith("BufferSize")): + if s.kind=="value": + self.csize = "%s"%self.size + if self.func.name.startswith("glUniformMatrix") and self.func.name[16]!='x': + self.csize += "*%d"%(int(self.func.name[15])**2) + elif self.func.name.startswith("glUniform") and self.func.name[9].isdigit(): + self.csize += "*%s"%self.func.name[9] + if strip_name(self.base_ctype)!="void": + self.csize += "*sizeof(%s)"%self.base_ctype + elif s.kind=="array" and s.size==1: + self.csize = "*%s"%s.name + if not self.csize: + sys.stderr.write("Could not determine size for array parameter '%s[%s]' of function '%s'\n"%(self.name, self.size, self.func.name)) + elif self.kind=="reference": + self.csize = "sizeof(%s)"%self.base_ctype + + def __init__(self, name, pnames): + self.name = name + self.ret = Function.Parameter(self, "ret") + self.params = [Function.Parameter(self, n) for n in pnames] + self.category = None + + def get_param(self, pname): + for p in self.params: + if p.name==pname: + return p + raise KeyError, pname + + def set_category(self, cat): + self.category = cat + + def compsize(self, size, btype): + if not size: return - if res: - res += "*" - - cn = p[2] - if cn.endswith(("EXT", "ARB", "SGI", "IBM", "ATI")): - cn = cn[:-3] - elif cn.endswith("SGIX"): - cn = cn[:-4] - elif cn.endswith(("NV", "HP")): - cn = cn[:-2] - if cn.endswith("Type"): - res += "typesize(%s)"%p[0] - have_type = True - elif cn.endswith("Format"): - res += "formatsize(%s)"%p[0] - elif cn.endswith(("Parameter", "ParameterPName", "ParameterName")) or cn=="GetPName": - res += "paramsize(%s)"%p[0] - elif cn=="MapTarget": - res += "mapsize(%s)"%p[0] - elif (cn=="SizeI" or cn.endswith("Int32")) and p[3]==0: - res += p[0] - else: - return - if not have_type: - res += "*sizeof(%s)"%ptype - return res - -def getfmt(param): - ptype = basetype(param[1], param[3]!=0) - if param[3]: - if type(param[3])==int: - return ("{%s}"%(", ".join([fmtmap[ptype]]*param[3])), ", ".join("%s[%d]"%(param[0], i) for i in range(param[3]))) - else: - return ("%p", param[0]) - else: - return (fmtmap[ptype], param[0]) - -def getrwinfo(func, param): - ptype = basetype(param[1], param[3]!=0) - if param[3]: - if type(param[3])==int: - size = "%d*sizeof(%s)"%(param[3], ptype) - elif param[3].startswith("COMPSIZE("): - size = compsize(func, param[3][9:-1], ptype) - if not size: - print "Compsize '%s' for function '%s' failed"%(param[3][9:-1], func[0]) - return ("pointer", None, "void **") - elif param[3]=="~": - if param[2]=="charARB" or param[2]=="Char": - return ("string", None, "const unsigned char **") + res = "" + have_type = False + for c in size.replace(',', '/').split('/'): + param = self.get_param(c) + if not param: + sys.stderr.write("Compsize '%s' for function '%s' failed: No parameter '%s'\n"%(size, self.name, c)) + return + + if res: + res += "*" + + cn = strip_name(param.type) + if cn.endswith("Type"): + res += "typesize(%s)"%param.name + have_type = True + elif cn.endswith("Format"): + res += "formatsize(%s)"%param.name + elif param.name=="pname" or cn.endswith("Parameter") or (param.name=="target" and cn=="enum"): + res += "paramsize(%s)"%param.name + elif param.name=="buffer" and cn=="enum": + res += "buffersize(%s)"%param.name + elif (cn=="SizeI" or cn.endswith("Int32")) and not param.size: + res += param.name else: - return ("pointer", None, "void **") + sys.stderr.write("Compsize '%s' for function '%s' failed: Parameter '%s' has unknown type '%s'\n"%(size, self.name, param.name, param.type)) + return + if not have_type: + res += "*sizeof(%s)"%btype + return res + + def finalize(self): + self.ret.derive_ctype() + for p in self.params: + p.derive_ctype() + for p in self.params: + p.derive_csize() + + +class Template: + def __init__(self, fn): + self.sections = [] + self.handcode = [] + + literal = True + text = "" + for line in InputFile(fn): + if line[0]==':': + if not literal and text: + self.add_section(text, literal) + text = "" + text += line[1:]+"\n" + literal = True + elif line[0]=='!': + parts = line[1:].split() + if parts[0]=="handcode": + self.handcode.append(parts[1]) + else: + if literal and text: + self.add_section(text, literal) + text = "" + text += line+"\n" + literal = False + if text: + self.add_section(text, literal) + + def add_section(self, text, literal): + if literal: + self.sections.append(text) else: - s = getparam(func, param[3].split('*')[0]) - if s and (s[2]=="SizeI" or s[2].endswith("Int32") or s[2].startswith("BufferSize")) and s[3]==0: - size = "%s*sizeof(%s)"%(param[3], ptype) - if func[0].startswith("Uniform") and func[0][8]!='u' and func[0][7].isdigit(): - size += "*%s"%func[0][7] + self.sections.append(compile(text, "-", "exec")) + + def write(self, str, *args): + sys.stdout.write(str%args) + + def writeln(self, str, *args): + sys.stdout.write(str%args+"\n") + + def process(self, functions): + for sect in self.sections: + if type(sect)==str: + print sect else: - print "Could not determine size for array parameter '%s[%s]' of function '%s'"%(param[0], param[3], func[0]) - return ("pointer", None, "void **") - return ("data", size, "const void **") - else: - return (iomap[ptype], None, None) - -# Write out function enums - -out = open(os.path.join(outdir, "functions.enum"), "w"); -out.write("""enum Function -{ - FUNC_NONE, -""") -for f in funcs: - out.write("\tFUNC_%s,\n"%f[0].upper()) -out.write("};\n") -out.close() - -# Write out wrapper functions for transmitting side - -out = open(os.path.join(outdir, "glwrap.funcs"), "w") -for f in funcs: - out.write("%s APIENTRY gl%s(%s)\n{\n"%(f[1], f[0], ", ".join("%s %s"%(p[1], p[0]) for p in f[2]))) - - out.write("\tstatic %s (*orig)(%s) = NULL;\n"%(f[1], ", ".join(p[1] for p in f[2]))) - if f[1]!="void": - out.write("\t%s ret;\n"%f[1]) - out.write("\tif(!orig)\n\t\torig = glsym(\"gl%s\");\n"%f[0]) - - out.write("\t") - if f[1]!="void": - out.write("ret = ") - out.write("orig(%s);\n"%(", ".join(p[0] for p in f[2]))) - - out.write("\tbegin_packet(FUNC_%s);\n"%f[0].upper()) - if f[1]!="void": - out.write("\twrite_%s(ret);\n"%iomap[f[1]]) - for p in f[2]: - (t, s, c) = getrwinfo(f, p) - out.write("\twrite_%s(%s"%(t, p[0])) - if s: - out.write(", %s"%s) - out.write(");\n") - out.write("\tsend_packet();\n") - - if f[1]!="void": - out.write("\treturn ret;\n") - out.write("}\n\n") -out.close() - -# Write out decoder stuff - -out = open(os.path.join(outdir, "gldecoder.struct"), "w") -out.write("typedef struct sGlDecoder\n{\n") -out.write("\tvoid *user_data;\n") -out.write("\tvoid (*destroy)(void *);\n") -for f in funcs: - out.write("\tvoid (*%s)(void *"%f[0]) - if f[1]!="void": - out.write(", %s"%f[1]) - if f[2]: - out.write(", %s"%(", ".join(p[1] for p in f[2]))) - out.write(");\n") -out.write("} GlDecoder;\n") - -out = open(os.path.join(outdir, "gldecoder.funcs"), "w") -for f in funcs: - out.write("static unsigned decode_%s(GlDecoder *dec, const char *data)\n{\n"%(f[0])) - out.write("\tunsigned pos = 0;\n") - if f[1]!="void": - out.write("\t%s ret;\n"%f[1]) - for p in f[2]: - out.write("\t%s arg_%s;\n"%(p[1], p[0])) - if f[1]!="void": - out.write("\tpos += read_%s(&ret, data+pos);\n"%iomap[f[1]]) - for p in f[2]: - (t, s, c) = getrwinfo(f, p) - if c: - c="(%s)"%c + for func in functions: + if func.name in self.handcode: + continue + globals = { + "w": self.write, + "wl": self.writeln, + "func": func, + "ret": func.ret, + "params": func.params + } + eval(sect, globals) + + +class Files: + def __init__(self, fn): + self.typemap = None + self.iomap = None + self.specs = [] + self.prefix = None + self.ignore_categs = [] + self.ignore_funcs = [] + + for line in InputFile(fn): + parts = line.split() + if parts[0]=="typemap": + self.typemap = parts[1] + elif parts[0]=="iomap": + self.iomap = parts[1] + elif parts[0]=="spec": + self.specs.append(parts[1]) + elif parts[0]=="prefix": + self.prefix = parts[1] + elif parts[0]=="ignore": + if parts[1]=="category": + self.ignore_categs.append(parts[2]) + elif parts[1]=="function": + self.ignore_funcs.append(parts[2]) + else: + sys.stderr.write("Unknown keyword '%s'\n", parts[0]) + + +def read_spec(fn, prefix): + funcs = [] + cur_func = None + for line in InputFile(fn): + if line.find(':')>=0: + continue + elif line[0]=='\t' and cur_func: + parts = line.split() + if parts[0]=="return": + cur_func.ret.set_type(parts[1], "out", "value") + elif parts[0]=="param": + bracket = parts[4].find('[') + if bracket>=0: + parts.insert(5, parts[4][bracket:]) + parts[4] = parts[4][:bracket] + + param = cur_func.get_param(parts[1]) + param.set_type(parts[2], parts[3], parts[4]) + if len(parts)==6 or (len(parts)>6 and parts[6]!="retained"): + param.set_size(parts[5][1:-1]) + elif parts[0]=="category": + cur_func.set_category(parts[1]) + elif parts[0]=="glxvendorglx" and cur_func.category=="glx": + cur_func.set_category("glxext") else: - c="" - out.write("\tpos += read_%s(%s&arg_%s, data+pos);\n"%(t, c, p[0])) - out.write("\tif(dec->%s)\n"%f[0]) - out.write("\t\tdec->%s(dec->user_data"%f[0]) - if f[1]!="void": - out.write(", ret") - if f[2]: - out.write(", %s"%(", ".join("arg_"+p[0] for p in f[2]))) - out.write(");\n") - out.write("\treturn pos;\n") - out.write("}\n\n") - -out.write("""static int decode_func(GlDecoder *dec, short func, const char *data) -{ - switch(func) - { -""") -for f in funcs: - out.write("\t\tcase FUNC_%s: return decode_%s(dec, data);\n"%(f[0].upper(), f[0])) -out.write(""" } - - return -1; -} -""") -out.close() - -# Write out print stuff - -out = open(os.path.join(outdir, "glprint.funcs"), "w") -for f in funcs: - out.write("static void print_%s(void *user_data"%f[0]) - if f[1]!="void": - out.write(", %s ret"%f[1]) - if f[2]: - out.write(", %s"%(", ".join("%s %s"%(p[1], p[0]) for p in f[2]))) - out.write(")\n{\n") - out.write("\tGlPrintData *gpd = (GlPrintData *)user_data;\n") - - m = [getfmt(p) for p in f[2]] - out.write("\tsnprintf(gpd->buffer, gpd->bufsize, \"%s(%s)"%(f[0], ", ".join(p[0] for p in m))) - if f[1]!="void": - out.write(" = %s"%fmtmap[f[1]]) - out.write("\"") - if m: - out.write(", %s"%(", ".join(p[1] for p in m))) - if f[1]!="void": - out.write(", ret") - out.write(");\n") - - out.write("}\n\n") - -out.write("static void init_print(GlDecoder *dec)\n{\n") -for f in funcs: - out.write("\tdec->%s = print_%s;\n"%(f[0], f[0])) -out.write("}\n") -out.close() + paren = line.find('(') + if paren>0: + cparen = line.rfind(')') + if cparen>paren+1: + pnames = [n.strip() for n in line[paren+1:cparen].split(",")] + else: + pnames = [] + cur_func = Function(prefix+line[:paren], pnames) + funcs.append(cur_func) + return funcs + +template = Template(sys.argv[1]) +functions = [] +for i in sys.argv[2:]: + files = Files(i) + + typemap = Typemap(files.typemap) + iomap = IOmap(files.iomap) + for s in files.specs: + funcs = read_spec(s, files.prefix) + funcs = [f for f in funcs if f.name not in files.ignore_funcs and f.category not in files.ignore_categs] + for f in funcs: + f.finalize() + names = [f.name for f in funcs] + functions = [f for f in functions if f.name not in names]+funcs + +template.process(functions)