summaryrefslogtreecommitdiff
path: root/specs/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'specs/scripts')
-rw-r--r--specs/scripts/.gitignore7
-rw-r--r--specs/scripts/Makefile51
-rw-r--r--specs/scripts/README12
-rwxr-xr-xspecs/scripts/cdecl.py358
-rw-r--r--specs/scripts/glparams.sed2
-rwxr-xr-xspecs/scripts/glspec.py283
-rwxr-xr-xspecs/scripts/gltxt.py169
-rwxr-xr-xspecs/scripts/reference-opengl-arb.sh30
-rwxr-xr-xspecs/scripts/reference-opengl-man.sh8
-rwxr-xr-xspecs/scripts/sort.sh2
-rwxr-xr-xspecs/scripts/wglenum.sh5
11 files changed, 927 insertions, 0 deletions
diff --git a/specs/scripts/.gitignore b/specs/scripts/.gitignore
new file mode 100644
index 0000000..1dbc0cf
--- /dev/null
+++ b/specs/scripts/.gitignore
@@ -0,0 +1,7 @@
+*.spec
+*.tm
+*.txt
+*api.py
+glparams.py
+wglenum.py
+!Makefile
diff --git a/specs/scripts/Makefile b/specs/scripts/Makefile
new file mode 100644
index 0000000..2ea2066
--- /dev/null
+++ b/specs/scripts/Makefile
@@ -0,0 +1,51 @@
+
+all: \
+ download \
+ glapi.py glxapi.py wglapi.py \
+ glparams.py wglenum.py
+
+download: \
+ enum.spec \
+ enumext.spec \
+ gl.spec \
+ gl.tm \
+ glxenum.spec \
+ glxenumext.spec \
+ glx.spec \
+ glxext.spec \
+ glx.tm \
+ wglenum.spec \
+ wglenumext.spec \
+ wgl.spec \
+ wglext.spec \
+ wgl.tm
+
+%.spec:
+ wget -N http://www.opengl.org/registry/api/$@
+
+%.tm:
+ wget -N http://www.opengl.org/registry/api/$@
+
+glapi.py: glspec.py gl.tm gl.spec
+ python glspec.py gl gl.tm gl.spec > $@
+
+glxapi.py: glspec.py glx.tm glx.spec glxext.spec
+ python glspec.py glX glx.tm glx.spec glxext.spec > $@
+
+wglapi.py: glspec.py wgl.tm wgl.spec wglext.spec
+ python glspec.py wgl wgl.tm wgl.spec wglext.spec > $@
+
+glparams.py: glparams.sed enum.spec sort.sh
+ sed -n -f glparams.sed enum.spec | ./sort.sh > $@
+
+wglenum.py: wglenum.sh wglenumext.spec
+ ./wglenum.sh wglenumext.spec > $@
+
+clean:
+ rm -f \
+ glapi.py glxapi.py wglapi.py \
+ glparams.py wglenum.py
+
+.PRECIOUS: %.spec %.tm
+
+.PHONY: download clean
diff --git a/specs/scripts/README b/specs/scripts/README
new file mode 100644
index 0000000..6df2a3d
--- /dev/null
+++ b/specs/scripts/README
@@ -0,0 +1,12 @@
+This directory contains several helper scripts that facilitate the generation
+of the API descriptions from specs and/or header files.
+
+The specs/headers are not expressive enough, which is why we can't just code
+generate everything from them.
+
+For GL the typical procedure is to run
+
+ make -B
+
+and then manually crossport new functions / enums to the files in the top dir
+via a side-by-side diff tool, such as gvimdiff.
diff --git a/specs/scripts/cdecl.py b/specs/scripts/cdecl.py
new file mode 100755
index 0000000..4f36b3c
--- /dev/null
+++ b/specs/scripts/cdecl.py
@@ -0,0 +1,358 @@
+#!/usr/bin/env python
+##########################################################################
+#
+# Copyright 2011 Jose Fonseca
+# All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+##########################################################################/
+
+
+'''Script to parse C declarations and spew API definitions.
+'''
+
+
+import sys
+import re
+import optparse
+
+
+class Parser:
+
+ token_re = re.compile(r'(\w+|\s+|.)')
+
+ multi_comment_re = re.compile(r'/\*.*?\*/', flags = re.DOTALL)
+ single_comment_re = re.compile(r'//.*',)
+
+ def __init__(self):
+ self.tokens = []
+
+ def has_side_effects(self, name):
+ return True
+
+
+ def tokenize(self, s):
+ s = self.multi_comment_re.sub('', s)
+ s = self.single_comment_re.sub('', s)
+ self.tokens = self.token_re.split(s)
+ self.tokens = [token for token in self.tokens if self.filter_token(token)]
+
+ def filter_token(self, token):
+ if not token or token.isspace():
+ return False
+ if token.startswith('AVAILABLE_') or token.startswith('DEPRECATED_'):
+ return False
+ if token in ['FAR']:
+ return False
+ return True
+
+ def lookahead(self, index = 0):
+ try:
+ return self.tokens[index]
+ except KeyError:
+ return None
+
+ def match(self, *ref_tokens):
+ return self.lookahead() in ref_tokens
+
+ def consume(self, *ref_tokens):
+ if not self.tokens:
+ raise Exception('unexpected EOF')
+ token = self.tokens.pop(0)
+ if ref_tokens and token not in ref_tokens:
+ raise Exception('token mismatch', token, ref_tokens)
+ return token
+
+ def eof(self):
+ return not self.tokens
+
+
+ def parse(self, s):
+ self.tokenize(s)
+
+ while not self.eof():
+ #print self.tokens[0:10]
+ self.parse_declaration()
+
+ def parse_declaration(self):
+ self.parse_tags()
+ if self.match('enum'):
+ self.parse_enum()
+ elif self.match('interface'):
+ self.parse_interface()
+ elif self.match('mask'):
+ self.parse_value('mask', 'Flags')
+ elif self.match('struct'):
+ self.parse_struct()
+ elif self.match('value'):
+ self.parse_value('value', 'FakeEnum')
+ elif self.match('typedef'):
+ self.parse_typedef()
+ else:
+ self.parse_prototype()
+ if not self.eof() and self.match(';'):
+ self.consume(';')
+
+ def parse_typedef(self):
+ self.consume('typedef')
+ if self.lookahead(2) in (';', ','):
+ base_type = self.consume()
+ while True:
+ type = base_type
+ if self.match('*'):
+ self.consume()
+ type = 'Pointer(%s)' % type
+ name = self.consume()
+ print '%s = Alias("%s", %s)' % (name, name, type)
+ if self.match(','):
+ self.consume()
+ else:
+ break
+ else:
+ self.parse_declaration()
+ self.consume()
+
+ def parse_enum(self):
+ self.consume('enum')
+ name = self.consume()
+ self.consume('{')
+
+ print '%s = Enum("%s", [' % (name, name)
+
+ #value = 0
+ while self.lookahead() != '}':
+ name = self.consume()
+ if self.match('='):
+ self.consume('=')
+ value = self.consume()
+ if self.match(','):
+ self.consume(',')
+ tags = self.parse_tags()
+ #print ' "%s",\t# %s' % (name, value)
+ print ' "%s",' % (name,)
+ #value += 1
+ self.consume('}')
+
+ print '])'
+ print
+
+ def parse_value(self, ref_token, constructor):
+ self.consume(ref_token)
+ type = self.consume()
+ name = self.consume()
+ self.consume('{')
+
+ print '%s = %s(%s, [' % (name, constructor, type)
+
+ while self.lookahead() != '}':
+ self.consume('#')
+ self.consume('define')
+ name = self.consume()
+ value = self.consume()
+ #print ' "%s",\t# %s' % (name, value)
+ print ' "%s",' % (name,)
+ self.consume('}')
+
+ print '])'
+ print
+
+ def parse_struct(self):
+ self.consume('struct')
+ name = self.consume()
+ self.consume('{')
+
+ print '%s = Struct("%s", [' % (name, name)
+
+ value = 0
+ while self.lookahead() != '}':
+ type, name = self.parse_named_type()
+ if self.match(','):
+ self.consume(',')
+ self.consume(';')
+ print ' (%s, "%s"),' % (type, name)
+ value += 1
+ self.consume('}')
+
+ print '])'
+ print
+
+ def parse_interface(self):
+ self.consume('interface')
+ name = self.consume()
+ if self.match(';'):
+ return
+ self.consume(':')
+ base = self.consume()
+ self.consume('{')
+
+ print '%s = Interface("%s", %s)' % (name, name, base)
+ print '%s.methods += [' % (name,)
+
+ while self.lookahead() != '}':
+ self.parse_prototype('Method')
+ self.consume(';')
+ self.consume('}')
+
+ print ']'
+ print
+
+ def parse_prototype(self, creator = 'Function'):
+ if self.match('extern'):
+ self.consume()
+
+ ret = self.parse_type()
+
+ if self.match('__stdcall'):
+ self.consume()
+ creator = 'StdFunction'
+
+ name = self.consume()
+ extra = ''
+ if not self.has_side_effects(name):
+ extra += ', sideeffects=False'
+ name = name
+
+ self.consume('(')
+ args = []
+ if self.match('void') and self.tokens[1] == ')':
+ self.consume()
+ while self.lookahead() != ')':
+ arg = self.parse_arg()
+ args.append(arg)
+ if self.match(','):
+ self.consume()
+ self.consume() == ')'
+
+ print ' %s(%s, "%s", [%s]%s),' % (creator, ret, name, ', '.join(args), extra)
+
+ def parse_arg(self):
+ tags = self.parse_tags()
+
+ type, name = self.parse_named_type()
+
+ arg = '(%s, "%s")' % (type, name)
+ if 'out' in tags:
+ arg = 'Out' + arg
+ return arg
+
+ def parse_tags(self):
+ tags = []
+ if self.match('['):
+ self.consume()
+ while not self.match(']'):
+ tag = self.consume()
+ tags.append(tag)
+ self.consume(']')
+ return tags
+
+ def parse_named_type(self):
+ type = self.parse_type()
+ name = self.consume()
+ if self.match('['):
+ self.consume()
+ length = self.consume()
+ self.consume(']')
+ type = 'Array(%s, "%s")' % (type, length)
+ return type, name
+
+ int_tokens = ('unsigned', 'signed', 'int', 'long', 'short', 'char')
+
+ type_table = {
+ 'float': 'Float',
+ 'double': 'Double',
+ 'int8_t': 'Int8',
+ 'uint8_t': 'UInt8',
+ 'int16_t': 'Int16',
+ 'uint16_t': 'UInt16',
+ 'int32_t': 'Int32',
+ 'uint32_t': 'UInt32',
+ 'int64_t' : 'Int64',
+ 'uint64_t': 'UInt64',
+ }
+
+ def parse_type(self):
+ const = False
+ token = self.consume()
+ if token == 'const':
+ token = self.consume()
+ const = True
+ if token == 'void':
+ type = 'Void'
+ elif token in self.int_tokens:
+ unsigned = False
+ signed = False
+ long = 0
+ short = 0
+ char = False
+ while token in self.int_tokens:
+ if token == 'unsigned':
+ unsigned = True
+ if token == 'signed':
+ signed = True
+ if token == 'long':
+ long += 1
+ if token == 'short':
+ short += 1
+ if token == 'char':
+ char = False
+ if self.lookahead() in self.int_tokens:
+ token = self.consume()
+ else:
+ token = None
+ if char:
+ type = 'Char'
+ if signed:
+ type = 'S' + type
+ elif short:
+ type = 'Short'
+ elif long:
+ type = 'Long' * long
+ else:
+ type = 'Int'
+ if unsigned:
+ type = 'U' + type
+ else:
+ type = self.type_table.get(token, token)
+ if const:
+ type = 'Const(%s)' % type
+ while True:
+ if self.match('*'):
+ self.consume('*')
+ type = 'OpaquePointer(%s)' % type
+ elif self.match('const'):
+ self.consume('const')
+ type = 'Const(%s)' % type
+ else:
+ break
+ return type
+
+
+
+
+
+
+def main():
+ parser = Parser()
+ for arg in sys.argv[1:]:
+ parser.parse(open(arg, 'rt').read())
+
+
+if __name__ == '__main__':
+ main()
diff --git a/specs/scripts/glparams.sed b/specs/scripts/glparams.sed
new file mode 100644
index 0000000..8afde64
--- /dev/null
+++ b/specs/scripts/glparams.sed
@@ -0,0 +1,2 @@
+s/^\s\+\(\w\+\)\s*=\s*\(0x\w\+\)\s\+#\s\+\([0-9]\+\)\s\+\([IF]\)\s*\(#.*\)\?$/ ("glGet",\t\4,\t\3,\t"GL_\1"),\t# \2/p
+s/^\s\+\(\w\+\)\s*=\s*\(0x\w\+\)\s*\(#.*\)\?$/ ("",\tX,\t1,\t"GL_\1"),\t# \2/p
diff --git a/specs/scripts/glspec.py b/specs/scripts/glspec.py
new file mode 100755
index 0000000..dbd20ce
--- /dev/null
+++ b/specs/scripts/glspec.py
@@ -0,0 +1,283 @@
+#!/usr/bin/env python
+##########################################################################
+#
+# Copyright 2010 VMware, Inc.
+# All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+##########################################################################/
+
+
+import sys
+import re
+import optparse
+
+
+def stderr(x):
+ sys.stderr.write(str(x) + '\n')
+
+
+class Parser:
+
+ def __init__(self, stream):
+ pass
+
+
+class LineParser:
+ """Base class for parsers that read line-based formats."""
+
+ def __init__(self, stream):
+ self._stream = stream
+ self._line = None
+ self._eof = False
+ # read lookahead
+ self.readline()
+
+ def parse(self):
+ raise NotImplementedError
+
+ def readline(self):
+ line = self._stream.readline()
+ if not line:
+ self._line = ''
+ self._eof = True
+ self._line = line.rstrip('\r\n')
+
+ def lookahead(self):
+ assert self._line is not None
+ return self._line
+
+ def consume(self):
+ assert self._line is not None
+ line = self._line
+ self.readline()
+ return line
+
+ def eof(self):
+ assert self._line is not None
+ return self._eof
+
+ def skip_whitespace(self):
+ while not self.eof() and self.match_whitespace() or self.match_comment():
+ self.consume()
+
+ def match_whitespace(self):
+ line = self.lookahead()
+ return not line.strip()
+
+ def match_comment(self):
+ return False
+
+
+class TypemapParser(LineParser):
+
+ def parse(self):
+ typemap = {}
+ self.skip_whitespace()
+ while not self.eof():
+ line = self.consume()
+ fields = [field.strip() for field in line.split(',')]
+ src = fields[0]
+ dst = fields[3]
+ if dst != '*':
+ typemap[src] = dst
+ self.skip_whitespace()
+ return typemap
+
+ def match_comment(self):
+ line = self.lookahead()
+ return line.startswith('#')
+
+
+class SpecParser(LineParser):
+
+ property_re = re.compile(r'^\w+:')
+ prototype_re = re.compile(r'^(\w+)\((.*)\)$')
+
+ def __init__(self, stream, prefix='', typemap = None):
+ LineParser.__init__(self, stream)
+ if typemap is None:
+ self.typemap = {}
+ else:
+ self.typemap = typemap
+ self.prefix = prefix
+ self.category = None
+
+ def parse(self):
+ self.skip_whitespace()
+ while not self.eof():
+ line = self.lookahead()
+ if self.property_re.match(line):
+ self.parse_property()
+ elif self.prototype_re.match(line):
+ self.parse_prototype()
+ else:
+ self.consume()
+ self.skip_whitespace()
+
+ def parse_property(self):
+ line = self.consume()
+ name, value = line.split(':', 1)
+ if name == 'category':
+ values = value.split()
+ #self.prefix = values[0]
+
+ get_function_re = re.compile(r'^(Get|Is|Are)[A-Z]\w+')
+
+ def parse_prototype(self):
+ line = self.consume()
+ mo = self.prototype_re.match(line)
+ function_name, arg_names = mo.groups()
+ arg_names = [arg_name.strip() for arg_name in arg_names.split(',') if arg_name.strip()]
+
+ extra = ''
+ if self.get_function_re.match(function_name):
+ extra += ', sideeffects=False'
+ function_name = self.prefix + function_name
+
+ ret_type = 'Void'
+ arg_types = {}
+ category = None
+ line = self.lookahead()
+ while line.startswith('\t'):
+ fields = line.split(None, 2)
+ if fields[0] == 'return':
+ ret_type = self.parse_type(fields[1])
+ elif fields[0] == 'param':
+ arg_name, arg_type = fields[1:3]
+ arg_types[fields[1]] = self.parse_arg(function_name, arg_name, arg_type)
+ elif fields[0] == 'category':
+ category = fields[1]
+ else:
+ pass
+ self.consume()
+ line = self.lookahead()
+ self.consume()
+ args = [arg_types[arg_name] for arg_name in arg_names]
+
+ if category is not None:
+ if category == self.prefix:
+ category = self.prefix.upper()
+ else:
+ category = self.prefix.upper() + '_' + category
+ if category != self.category:
+ if self.category is not None:
+ print
+ print ' # %s' % category
+ self.category = category
+
+ if self.prefix == 'wgl':
+ constructor = 'StdFunction'
+ else:
+ constructor = 'GlFunction'
+
+ print ' %s(%s, "%s", [%s]%s),' % (constructor, ret_type, function_name, ', '.join(args), extra)
+
+ array_re = re.compile(r'^array\s+\[(.*)\]$')
+
+ string_typemap = {
+ 'GLchar': 'GLstring',
+ 'GLcharARB': 'GLstringARB',
+ }
+
+ def parse_arg(self, function_name, arg_name, arg_type):
+ orig_type, inout, kind = arg_type.split(' ', 2)
+
+ base_type = self.parse_type(orig_type)
+
+ if kind == 'value':
+ arg_type = base_type
+ elif kind == 'reference':
+ if inout == 'in':
+ base_type = 'Const(%s)' % base_type
+ arg_type = 'Pointer(%s)' % base_type
+ elif kind.startswith("array"):
+ if inout == 'in':
+ base_type = 'Const(%s)' % base_type
+
+ arg_type = 'OpaquePointer(%s)' % base_type
+
+ if base_type in ('Void', 'void', 'GLvoid'):
+ constructor = 'Blob'
+ else:
+ constructor = 'Array'
+
+ mo = self.array_re.match(kind)
+ if mo:
+ length = mo.group(1).strip()
+ if length == '':
+ try:
+ arg_type = self.string_typemap[base_type]
+ except KeyError:
+ pass
+ elif length == '1':
+ arg_type = 'Pointer(%s)' % base_type
+ elif length.find("COMPSIZE") == -1:
+ arg_type = '%s(%s, "%s")' % (constructor, base_type, length)
+ else:
+ length = length.replace("COMPSIZE", "__%s_size" % function_name)
+ length = length.replace("/", ", ")
+ arg_type = 'Opaque%s(%s, "%s")' % (constructor, base_type, length)
+ else:
+ assert False
+
+ arg = '(%s, "%s")' % (arg_type, arg_name)
+ if inout == 'out':
+ arg = 'Out' + arg
+ return arg
+
+ semantic_typemap = {
+ 'String': 'CString',
+ 'Texture': 'GLtexture',
+ }
+
+ post_typemap = {
+ 'void': 'Void',
+ 'int': 'Int',
+ 'float': 'Float',
+ }
+
+ def parse_type(self, type):
+ try:
+ return self.semantic_typemap[type]
+ except KeyError:
+ pass
+ type = self.typemap.get(type, type)
+ type = self.post_typemap.get(type, type)
+ return type
+
+ def match_comment(self):
+ line = self.lookahead()
+ return line.startswith('#')
+
+
+def main():
+ prefix = sys.argv[1]
+
+ parser = TypemapParser(open(sys.argv[2], 'rt'))
+ typemap = parser.parse()
+
+ for arg in sys.argv[3:]:
+ parser = SpecParser(open(arg, 'rt'), prefix=prefix, typemap=typemap)
+ parser.parse()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/specs/scripts/gltxt.py b/specs/scripts/gltxt.py
new file mode 100755
index 0000000..c6be7c1
--- /dev/null
+++ b/specs/scripts/gltxt.py
@@ -0,0 +1,169 @@
+#!/usr/bin/env python
+##########################################################################
+#
+# Copyright 2010 VMware, Inc.
+# All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+##########################################################################/
+
+
+import sys
+import re
+import optparse
+
+
+def stderr(x):
+ sys.stderr.write(str(x) + '\n')
+
+
+class Parser:
+
+ def __init__(self, stream):
+ pass
+
+
+class LineParser:
+ """Base class for parsers that read line-based formats."""
+
+ def __init__(self, stream):
+ self._stream = stream
+ self._line = None
+ self._eof = False
+ # read lookahead
+ self.readline()
+
+ def parse(self):
+ raise NotImplementedError
+
+ def readline(self):
+ line = self._stream.readline()
+ if not line:
+ self._line = ''
+ self._eof = True
+ self._line = line.rstrip('\r\n')
+
+ def lookahead(self):
+ assert self._line is not None
+ return self._line
+
+ def consume(self):
+ assert self._line is not None
+ line = self._line
+ self.readline()
+ return line
+
+ def eof(self):
+ assert self._line is not None
+ return self._eof
+
+ def skip_whitespace(self):
+ while not self.eof() and self.match_whitespace() or self.match_comment():
+ self.consume()
+
+ def match_whitespace(self):
+ line = self.lookahead()
+ return not line.strip()
+
+ def match_comment(self):
+ return False
+
+
+class TxtParser(LineParser):
+
+ property_re = re.compile(r'^\w+:')
+ prototype_re = re.compile(r'^(\w+)\((.*)\)$')
+
+ def __init__(self, stream, prefix=''):
+ LineParser.__init__(self, stream)
+ self.prefix = prefix
+
+ def parse(self):
+ line = self.consume()
+ while not line.startswith("New Procedures and Functions"):
+ line = self.consume()
+ self.parse_procs()
+
+ def parse_procs(self):
+ lines = []
+ while True:
+ line = self.consume()
+ if not line.strip():
+ continue
+ if not line.startswith(' '):
+ break
+ lines.append(line.strip())
+ if line.endswith(';'):
+ self.parse_proc(' '.join(lines))
+ lines = []
+
+ token_re = re.compile(r'(\w+|\s+|.)')
+ get_function_re = re.compile(r'^Get[A-Z]\w+')
+
+ def parse_proc(self, prototype):
+ #print prototype
+ tokens = self.token_re.split(prototype)
+ self.tokens = [token for token in tokens if token.strip()]
+ #print self.tokens
+
+ ret = self.parse_type()
+
+ name = self.tokens.pop(0)
+ extra = ''
+ if self.get_function_re.match(name):
+ extra += ', sideeffects=False'
+ name = self.prefix + name
+
+ assert self.tokens.pop(0) == '('
+ args = []
+ while self.tokens[0] != ')':
+ arg = self.parse_arg()
+ args.append(arg)
+ if self.tokens[0] == ',':
+ self.tokens.pop(0)
+ print ' GlFunction(%s, "%s", [%s]%s),' % (ret, name, ', '.join(args), extra)
+
+ def parse_arg(self):
+ type = self.parse_type()
+ name = self.tokens.pop(0)
+ return '(%s, "%s")' % (type, name)
+
+ def parse_type(self):
+ token = self.tokens.pop(0)
+ if token == 'const':
+ return 'Const(%s)' % self.parse_type()
+ if token == 'void':
+ type = 'Void'
+ else:
+ type = 'GL' + token
+ while self.tokens[0] == '*':
+ type = 'OpaquePointer(%s)' % type
+ self.tokens.pop(0)
+ return type
+
+
+def main():
+ for arg in sys.argv[1:]:
+ parser = TxtParser(open(arg, 'rt'), prefix='gl')
+ parser.parse()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/specs/scripts/reference-opengl-arb.sh b/specs/scripts/reference-opengl-arb.sh
new file mode 100755
index 0000000..670ba17
--- /dev/null
+++ b/specs/scripts/reference-opengl-arb.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+# Script to extract reference URLs for functions documented in OpenGL ARB specs
+
+extract_urls () {
+ for URL
+ do
+ lynx -dump "$URL" | sed -n -e '/^References$/,$s/^ *[0-9]\+\. \+//p' | sed -e 's/ /%20/g'
+ done
+}
+
+extract_functions () {
+ sed -n -e '/^New Procedures and Functions$/,/^\w/ s/.* \(\w\+\)(.*$/\1/p' "$@" \
+ | sed -e '/^[A-Z]/s/^/gl/'
+}
+
+extract_urls http://www.opengl.org/registry/ \
+| grep '^http://www\.opengl\.org/registry/specs/ARB/.*\.txt$' \
+| sort -u \
+| while read URL
+do
+ wget --quiet -O - $URL \
+ | extract_functions \
+ | while read FUNCTION
+ do
+ echo "$FUNCTION $URL"
+ done
+done
+
+
+
diff --git a/specs/scripts/reference-opengl-man.sh b/specs/scripts/reference-opengl-man.sh
new file mode 100755
index 0000000..20bdaa6
--- /dev/null
+++ b/specs/scripts/reference-opengl-man.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+# Script to extract reference URLS for functions documented in OpenGL man pages
+
+wget -N -r -np http://www.opengl.org/sdk/docs/{man,man2,man3,man4}/
+
+find www.opengl.org -type f -name '*.xml' \
+| xargs grep -o '<b class="fsfunc">[^<]*</b>' \
+| sed -e 's/<[^>]*>//g' -e 's@^\(.*\):\(.*\)$@\2\thttp://\1@'
diff --git a/specs/scripts/sort.sh b/specs/scripts/sort.sh
new file mode 100755
index 0000000..5cdc6a4
--- /dev/null
+++ b/specs/scripts/sort.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+sed -e 's/\(^.*#\) \(0x\w\+\)$/\2 \1/' "$@" | sort | sed -e 's/\(0x\w\+\) \(.*#\)$/\2 \1/'
diff --git a/specs/scripts/wglenum.sh b/specs/scripts/wglenum.sh
new file mode 100755
index 0000000..97f969d
--- /dev/null
+++ b/specs/scripts/wglenum.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+sed -n -e 's/^\s\+\(WGL_\S\+\)\s*=\s*\(0x2\w\w\w\)\s*$/\2 \1/p' "$@" \
+| sort -u \
+| sed -e 's/\(\S\+\)\s\+\(\S\+\)/ "\2",\t\t# \1/'