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=="":
- 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:]
+ self.io = iomap[self.base_ctype]
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":"%p",
- "GLsizeiptrARB":"%p",
- "GLintptr":"%p",
- "GLintptrARB":"%p",
- "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+" *"
+
+ 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=="" and (self.type=="charARB" or self.type=="Char"):
+ self.csize = "strlen"
+ else:
+ s = self.func.get_param(self.size.split('*')[0])
+ if (s.type=="SizeI" or s.type.endswith("Int32") or s.type.startswith("BufferSize")) and s.kind=="value":
+ self.csize = "%s*sizeof(%s)"%(self.size, self.base_ctype)
+ if self.func.name.startswith("Uniform") and self.func.name[7].isdigit():
+ self.csize += "*%s"%func.name[7]
+ 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 getwrite(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)
- elif param[3]=="~" and (param[2]=="charARB" or param[2]=="Char"):
- return ("string", None)
- else:
- s = getparam(func, param[3].split('*')[0])
- if s and (s[2]=="SizeI" or s[2].endswith("Int32")) 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]
+ 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 cn.endswith(("Parameter", "ParameterPName", "ParameterName")) or cn=="GetPName":
+ res += "paramsize(%s)"%param.name
+ elif cn=="MapTarget":
+ res += "mapsize(%s)"%param.name
+ elif (cn=="SizeI" or cn.endswith("Int32")) and not param.size:
+ res += param.name
else:
- print "Could not determine size for array parameter '%s[%s]' of function '%s'"%(param[0], param[3], func[0])
- return ("pointer", None)
- return ("data", size)
- else:
- return (iomap[ptype], None)
+ 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)"%param.ctype
+ 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 = []
+
+ 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
+ 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:
+ self.sections.append(compile(text, "-", "exec"))
-def getread(func, param):
- ptype = basetype(param[1], param[3]!=0)
- if param[3]:
- return ("data", "(const void **)")
- else:
- return (iomap[ptype], "")
-
-# 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 GLAPIENTRY 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) = getwrite(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, unsigned len)\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, len);\n"%iomap[f[1]])
- for p in f[2]:
- (t, c) = getread(f, p)
- out.write("\tpos += read_%s(%s&arg_%s, data+pos, len-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("""unsigned gldecoder_decode(GlDecoder *dec, const char *data, unsigned len)
-{
- unsigned pos = 0;
- short func;
-
- pos += read_short(&func, data, len);
- switch(func)
- {
-""")
-for f in funcs:
- out.write("\t\tcase FUNC_%s: pos += decode_%s(dec, data+pos, len); break;\n"%(f[0].upper(), f[0]))
-out.write(""" }
-
- return pos;
-}
-""")
-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()
+ 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:
+ for func in functions:
+ 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:
+ 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)