|
|
@@ -0,0 +1,601 @@ |
|
|
|
#!/usr/bin/python |
|
|
|
# |
|
|
|
# Copyright (C) 2009 Chia-I Wu <olv@0xlab.org> |
|
|
|
# |
|
|
|
# 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 |
|
|
|
# on the rights to use, copy, modify, merge, publish, distribute, sub |
|
|
|
# license, 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 (including the next |
|
|
|
# paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL |
|
|
|
# IBM AND/OR ITS SUPPLIERS 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. |
|
|
|
""" |
|
|
|
A parser for APIspec. |
|
|
|
""" |
|
|
|
|
|
|
|
class SpecError(Exception): |
|
|
|
"""Error in the spec file.""" |
|
|
|
|
|
|
|
|
|
|
|
class Spec(object): |
|
|
|
"""A Spec is an abstraction of the API spec.""" |
|
|
|
|
|
|
|
def __init__(self, doc): |
|
|
|
self.doc = doc |
|
|
|
|
|
|
|
self.spec_node = doc.getRootElement() |
|
|
|
self.tmpl_nodes = {} |
|
|
|
self.api_nodes = {} |
|
|
|
self.impl_node = None |
|
|
|
|
|
|
|
# parse <apispec> |
|
|
|
node = self.spec_node.children |
|
|
|
while node: |
|
|
|
if node.type == "element": |
|
|
|
if node.name == "template": |
|
|
|
self.tmpl_nodes[node.prop("name")] = node |
|
|
|
elif node.name == "api": |
|
|
|
self.api_nodes[node.prop("name")] = node |
|
|
|
else: |
|
|
|
raise SpecError("unexpected node %s in apispec" % |
|
|
|
node.name) |
|
|
|
node = node.next |
|
|
|
|
|
|
|
# find an implementation |
|
|
|
for name, node in self.api_nodes.iteritems(): |
|
|
|
if node.prop("implementation") == "true": |
|
|
|
self.impl_node = node |
|
|
|
break |
|
|
|
if not self.impl_node: |
|
|
|
raise SpecError("unable to find an implementation") |
|
|
|
|
|
|
|
def get_impl(self): |
|
|
|
"""Return the implementation.""" |
|
|
|
return API(self, self.impl_node) |
|
|
|
|
|
|
|
def get_api(self, name): |
|
|
|
"""Return an API.""" |
|
|
|
return API(self, self.api_nodes[name]) |
|
|
|
|
|
|
|
|
|
|
|
class API(object): |
|
|
|
"""An API consists of categories and functions.""" |
|
|
|
|
|
|
|
def __init__(self, spec, api_node): |
|
|
|
self.name = api_node.prop("name") |
|
|
|
self.is_impl = (api_node.prop("implementation") == "true") |
|
|
|
|
|
|
|
self.categories = [] |
|
|
|
self.functions = [] |
|
|
|
|
|
|
|
# parse <api> |
|
|
|
func_nodes = [] |
|
|
|
node = api_node.children |
|
|
|
while node: |
|
|
|
if node.type == "element": |
|
|
|
if node.name == "category": |
|
|
|
cat = node.prop("name") |
|
|
|
self.categories.append(cat) |
|
|
|
elif node.name == "function": |
|
|
|
func_nodes.append(node) |
|
|
|
else: |
|
|
|
raise SpecError("unexpected node %s in api" % node.name) |
|
|
|
node = node.next |
|
|
|
|
|
|
|
# realize functions |
|
|
|
for func_node in func_nodes: |
|
|
|
tmpl_node = spec.tmpl_nodes[func_node.prop("template")] |
|
|
|
try: |
|
|
|
func = Function(tmpl_node, func_node, self.is_impl, |
|
|
|
self.categories) |
|
|
|
except SpecError, e: |
|
|
|
func_name = func_node.prop("name") |
|
|
|
raise SpecError("failed to parse %s: %s" % (func_name, e)) |
|
|
|
self.functions.append(func) |
|
|
|
|
|
|
|
def match(self, func, conversions={}): |
|
|
|
"""Find a matching function in the API.""" |
|
|
|
match = None |
|
|
|
need_conv = False |
|
|
|
for f in self.functions: |
|
|
|
matched, conv = f.match(func, conversions) |
|
|
|
if matched: |
|
|
|
match = f |
|
|
|
need_conv = conv |
|
|
|
# exact match |
|
|
|
if not need_conv: |
|
|
|
break |
|
|
|
return (match, need_conv) |
|
|
|
|
|
|
|
|
|
|
|
class Function(object): |
|
|
|
"""Parse and realize a <template> node.""" |
|
|
|
|
|
|
|
def __init__(self, tmpl_node, func_node, force_skip_desc=False, categories=[]): |
|
|
|
self.tmpl_name = tmpl_node.prop("name") |
|
|
|
self.direction = tmpl_node.prop("direction") |
|
|
|
|
|
|
|
self.name = func_node.prop("name") |
|
|
|
self.prefix = func_node.prop("default_prefix") |
|
|
|
self.is_external = (func_node.prop("external") == "true") |
|
|
|
|
|
|
|
if force_skip_desc: |
|
|
|
self._skip_desc = True |
|
|
|
else: |
|
|
|
self._skip_desc = (self.is_external or func_node.prop("skip_desc") == "true") |
|
|
|
|
|
|
|
self._categories = categories |
|
|
|
|
|
|
|
# these attributes decide how the template is realized |
|
|
|
self._gltype = func_node.prop("gltype") |
|
|
|
if func_node.hasProp("vector_size"): |
|
|
|
self._vector_size = int(func_node.prop("vector_size")) |
|
|
|
else: |
|
|
|
self._vector_size = 0 |
|
|
|
self._expand_vector = (func_node.prop("expand_vector") == "true") |
|
|
|
|
|
|
|
self.return_type = "void" |
|
|
|
param_nodes = [] |
|
|
|
|
|
|
|
# find <proto> |
|
|
|
proto_node = tmpl_node.children |
|
|
|
while proto_node: |
|
|
|
if proto_node.type == "element" and proto_node.name == "proto": |
|
|
|
break |
|
|
|
proto_node = proto_node.next |
|
|
|
if not proto_node: |
|
|
|
raise SpecError("no proto") |
|
|
|
# and parse it |
|
|
|
node = proto_node.children |
|
|
|
while node: |
|
|
|
if node.type == "element": |
|
|
|
if node.name == "return": |
|
|
|
self.return_type = node.prop("type") |
|
|
|
elif node.name == "param" or node.name == "vector": |
|
|
|
if self.support_node(node): |
|
|
|
# make sure the node is not hidden |
|
|
|
if not (self._expand_vector and |
|
|
|
(node.prop("hide_if_expanded") == "true")): |
|
|
|
param_nodes.append(node) |
|
|
|
else: |
|
|
|
raise SpecError("unexpected node %s in proto" % node.name) |
|
|
|
node = node.next |
|
|
|
|
|
|
|
self._init_params(param_nodes) |
|
|
|
self._init_descs(tmpl_node, param_nodes) |
|
|
|
|
|
|
|
def __str__(self): |
|
|
|
return "%s %s%s(%s)" % (self.return_type, self.prefix, self.name, |
|
|
|
self.param_string(True)) |
|
|
|
|
|
|
|
def _init_params(self, param_nodes): |
|
|
|
"""Parse and initialize parameters.""" |
|
|
|
self.params = [] |
|
|
|
|
|
|
|
for param_node in param_nodes: |
|
|
|
size = self.param_node_size(param_node) |
|
|
|
# when no expansion, vector is just like param |
|
|
|
if param_node.name == "param" or not self._expand_vector: |
|
|
|
param = Parameter(param_node, self._gltype, size) |
|
|
|
self.params.append(param) |
|
|
|
continue |
|
|
|
|
|
|
|
if not size or size > param_node.lsCountNode(): |
|
|
|
raise SpecError("could not expand %s with unknown or " |
|
|
|
"mismatch sizes" % param.name) |
|
|
|
|
|
|
|
# expand the vector |
|
|
|
expanded_params = [] |
|
|
|
child = param_node.children |
|
|
|
while child: |
|
|
|
if (child.type == "element" and child.name == "param" and |
|
|
|
self.support_node(child)): |
|
|
|
expanded_params.append(Parameter(child, self._gltype)) |
|
|
|
if len(expanded_params) == size: |
|
|
|
break |
|
|
|
child = child.next |
|
|
|
# just in case that lsCountNode counts unknown nodes |
|
|
|
if len(expanded_params) < size: |
|
|
|
raise SpecError("not enough named parameters") |
|
|
|
|
|
|
|
self.params.extend(expanded_params) |
|
|
|
|
|
|
|
def _init_descs(self, tmpl_node, param_nodes): |
|
|
|
"""Parse and initialize parameter descriptions.""" |
|
|
|
self.checker = Checker() |
|
|
|
if self._skip_desc: |
|
|
|
return |
|
|
|
|
|
|
|
node = tmpl_node.children |
|
|
|
while node: |
|
|
|
if node.type == "element" and node.name == "desc": |
|
|
|
if self.support_node(node): |
|
|
|
# parse <desc> |
|
|
|
desc = Description(node, self._categories) |
|
|
|
self.checker.add_desc(desc) |
|
|
|
node = node.next |
|
|
|
|
|
|
|
self.checker.validate(self, param_nodes) |
|
|
|
|
|
|
|
def support_node(self, node): |
|
|
|
"""Return true if a node is in the supported category.""" |
|
|
|
return (not node.hasProp("category") or |
|
|
|
node.prop("category") in self._categories) |
|
|
|
|
|
|
|
def get_param(self, name): |
|
|
|
"""Return the named parameter.""" |
|
|
|
for param in self.params: |
|
|
|
if param.name == name: |
|
|
|
return param |
|
|
|
return None |
|
|
|
|
|
|
|
def param_node_size(self, param): |
|
|
|
"""Return the size of a vector.""" |
|
|
|
if param.name != "vector": |
|
|
|
return 0 |
|
|
|
|
|
|
|
size = param.prop("size") |
|
|
|
if size.isdigit(): |
|
|
|
size = int(size) |
|
|
|
else: |
|
|
|
size = 0 |
|
|
|
if not size: |
|
|
|
size = self._vector_size |
|
|
|
if not size and self._expand_vector: |
|
|
|
# return the number of named parameters |
|
|
|
size = param.lsCountNode() |
|
|
|
return size |
|
|
|
|
|
|
|
def param_string(self, declaration): |
|
|
|
"""Return the C code of the parameters.""" |
|
|
|
args = [] |
|
|
|
if declaration: |
|
|
|
for param in self.params: |
|
|
|
sep = "" if param.type.endswith("*") else " " |
|
|
|
args.append("%s%s%s" % (param.type, sep, param.name)) |
|
|
|
if not args: |
|
|
|
args.append("void") |
|
|
|
else: |
|
|
|
for param in self.params: |
|
|
|
args.append(param.name) |
|
|
|
return ", ".join(args) |
|
|
|
|
|
|
|
def match(self, other, conversions={}): |
|
|
|
"""Return true if the functions match, probably with a conversion.""" |
|
|
|
if (self.tmpl_name != other.tmpl_name or |
|
|
|
self.return_type != other.return_type or |
|
|
|
len(self.params) != len(other.params)): |
|
|
|
return (False, False) |
|
|
|
|
|
|
|
need_conv = False |
|
|
|
for i in xrange(len(self.params)): |
|
|
|
src = other.params[i] |
|
|
|
dst = self.params[i] |
|
|
|
if (src.is_vector != dst.is_vector or src.size != dst.size): |
|
|
|
return (False, False) |
|
|
|
if src.type != dst.type: |
|
|
|
if dst.base_type() in conversions.get(src.base_type(), []): |
|
|
|
need_conv = True |
|
|
|
else: |
|
|
|
# unable to convert |
|
|
|
return (False, False) |
|
|
|
|
|
|
|
return (True, need_conv) |
|
|
|
|
|
|
|
|
|
|
|
class Parameter(object): |
|
|
|
"""A parameter of a function.""" |
|
|
|
|
|
|
|
def __init__(self, param_node, gltype=None, size=0): |
|
|
|
self.is_vector = (param_node.name == "vector") |
|
|
|
|
|
|
|
self.name = param_node.prop("name") |
|
|
|
self.size = size |
|
|
|
|
|
|
|
type = param_node.prop("type") |
|
|
|
if gltype: |
|
|
|
type = type.replace("GLtype", gltype) |
|
|
|
elif type.find("GLtype") != -1: |
|
|
|
raise SpecError("parameter %s has unresolved type" % self.name) |
|
|
|
|
|
|
|
self.type = type |
|
|
|
|
|
|
|
def base_type(self): |
|
|
|
"""Return the base GL type by stripping qualifiers.""" |
|
|
|
return [t for t in self.type.split(" ") if t.startswith("GL")][0] |
|
|
|
|
|
|
|
|
|
|
|
class Checker(object): |
|
|
|
"""A checker is the collection of all descriptions on the same level. |
|
|
|
Descriptions of the same parameter are concatenated. |
|
|
|
""" |
|
|
|
|
|
|
|
def __init__(self): |
|
|
|
self.switches = {} |
|
|
|
|
|
|
|
def add_desc(self, desc): |
|
|
|
"""Add a description.""" |
|
|
|
# TODO take index into consideration |
|
|
|
if desc.name not in self.switches: |
|
|
|
self.switches[desc.name] = [] |
|
|
|
self.switches[desc.name].append(desc) |
|
|
|
|
|
|
|
def validate(self, func, param_nodes): |
|
|
|
"""Validate the checker against a function.""" |
|
|
|
tmp = Checker() |
|
|
|
|
|
|
|
for switch in self.switches.itervalues(): |
|
|
|
valid_descs = [] |
|
|
|
for desc in switch: |
|
|
|
if desc.validate(func, param_nodes): |
|
|
|
valid_descs.append(desc) |
|
|
|
# no possible values |
|
|
|
if not valid_descs: |
|
|
|
return False |
|
|
|
for desc in valid_descs: |
|
|
|
if not desc._is_noop: |
|
|
|
tmp.add_desc(desc) |
|
|
|
|
|
|
|
self.switches = tmp.switches |
|
|
|
return True |
|
|
|
|
|
|
|
def flatten(self, name=None): |
|
|
|
"""Return a flat list of all descriptions of the named parameter.""" |
|
|
|
flat_list = [] |
|
|
|
for switch in self.switches.itervalues(): |
|
|
|
for desc in switch: |
|
|
|
if not name or desc.name == name: |
|
|
|
flat_list.append(desc) |
|
|
|
flat_list.extend(desc.checker.flatten(name)) |
|
|
|
return flat_list |
|
|
|
|
|
|
|
def always_check(self, name): |
|
|
|
"""Return true if the parameter is checked in all possible pathes.""" |
|
|
|
if name in self.switches: |
|
|
|
return True |
|
|
|
|
|
|
|
# a param is always checked if any of the switch always checks it |
|
|
|
for switch in self.switches.itervalues(): |
|
|
|
# a switch always checks it if all of the descs always check it |
|
|
|
always = True |
|
|
|
for desc in switch: |
|
|
|
if not desc.checker.always_check(name): |
|
|
|
always = False |
|
|
|
break |
|
|
|
if always: |
|
|
|
return True |
|
|
|
return False |
|
|
|
|
|
|
|
def _c_switch(self, name, indent="\t"): |
|
|
|
"""Output C switch-statement for the named parameter, for debug.""" |
|
|
|
switch = self.switches.get(name, []) |
|
|
|
# make sure there are valid values |
|
|
|
need_switch = False |
|
|
|
for desc in switch: |
|
|
|
if desc.values: |
|
|
|
need_switch = True |
|
|
|
if not need_switch: |
|
|
|
return [] |
|
|
|
|
|
|
|
stmts = [] |
|
|
|
var = switch[0].name |
|
|
|
if switch[0].index >= 0: |
|
|
|
var += "[%d]" % switch[0].index |
|
|
|
stmts.append("switch (%s) { /* assume GLenum */" % var) |
|
|
|
|
|
|
|
for desc in switch: |
|
|
|
if desc.values: |
|
|
|
for val in desc.values: |
|
|
|
stmts.append("case %s:" % val) |
|
|
|
for dep_name in desc.checker.switches.iterkeys(): |
|
|
|
dep_stmts = [indent + s for s in desc.checker._c_switch(dep_name, indent)] |
|
|
|
stmts.extend(dep_stmts) |
|
|
|
stmts.append(indent + "break;") |
|
|
|
|
|
|
|
stmts.append("default:") |
|
|
|
stmts.append(indent + "ON_ERROR(%s);" % switch[0].error); |
|
|
|
stmts.append(indent + "break;") |
|
|
|
stmts.append("}") |
|
|
|
|
|
|
|
return stmts |
|
|
|
|
|
|
|
def dump(self, indent="\t"): |
|
|
|
"""Dump the descriptions in C code.""" |
|
|
|
stmts = [] |
|
|
|
for name in self.switches.iterkeys(): |
|
|
|
c_switch = self._c_switch(name) |
|
|
|
print "\n".join(c_switch) |
|
|
|
|
|
|
|
|
|
|
|
class Description(object): |
|
|
|
"""A description desribes a parameter and its relationship with other |
|
|
|
parameters. |
|
|
|
""" |
|
|
|
|
|
|
|
def __init__(self, desc_node, categories=[]): |
|
|
|
self._categories = categories |
|
|
|
self._is_noop = False |
|
|
|
|
|
|
|
self.name = desc_node.prop("name") |
|
|
|
self.index = -1 |
|
|
|
|
|
|
|
self.error = desc_node.prop("error") or "GL_INVALID_ENUM" |
|
|
|
# vector_size may be C code |
|
|
|
self.size_str = desc_node.prop("vector_size") |
|
|
|
|
|
|
|
self._has_enum = False |
|
|
|
self.values = [] |
|
|
|
dep_nodes = [] |
|
|
|
|
|
|
|
# parse <desc> |
|
|
|
valid_names = ["value", "range", "desc"] |
|
|
|
node = desc_node.children |
|
|
|
while node: |
|
|
|
if node.type == "element": |
|
|
|
if node.name in valid_names: |
|
|
|
# ignore nodes that require unsupported categories |
|
|
|
if (node.prop("category") and |
|
|
|
node.prop("category") not in self._categories): |
|
|
|
node = node.next |
|
|
|
continue |
|
|
|
else: |
|
|
|
raise SpecError("unexpected node %s in desc" % node.name) |
|
|
|
|
|
|
|
if node.name == "value": |
|
|
|
val = node.prop("name") |
|
|
|
if not self._has_enum and val.startswith("GL_"): |
|
|
|
self._has_enum = True |
|
|
|
self.values.append(val) |
|
|
|
elif node.name == "range": |
|
|
|
first = int(node.prop("from")) |
|
|
|
last = int(node.prop("to")) |
|
|
|
base = node.prop("base") or "" |
|
|
|
if not self._has_enum and base.startswith("GL_"): |
|
|
|
self._has_enum = True |
|
|
|
# expand range |
|
|
|
for i in xrange(first, last + 1): |
|
|
|
self.values.append("%s%d" % (base, i)) |
|
|
|
else: # dependent desc |
|
|
|
dep_nodes.append(node) |
|
|
|
node = node.next |
|
|
|
|
|
|
|
# default to convert if there is no enum |
|
|
|
self.convert = not self._has_enum |
|
|
|
if desc_node.hasProp("convert"): |
|
|
|
self.convert = (desc_node.prop("convert") == "true") |
|
|
|
|
|
|
|
self._init_deps(dep_nodes) |
|
|
|
|
|
|
|
def _init_deps(self, dep_nodes): |
|
|
|
"""Parse and initialize dependents.""" |
|
|
|
self.checker = Checker() |
|
|
|
|
|
|
|
for dep_node in dep_nodes: |
|
|
|
# recursion! |
|
|
|
dep = Description(dep_node, self._categories) |
|
|
|
self.checker.add_desc(dep) |
|
|
|
|
|
|
|
def _search_param_node(self, param_nodes, name=None): |
|
|
|
"""Search the template parameters for the named node.""" |
|
|
|
param_node = None |
|
|
|
param_index = -1 |
|
|
|
|
|
|
|
if not name: |
|
|
|
name = self.name |
|
|
|
for node in param_nodes: |
|
|
|
if name == node.prop("name"): |
|
|
|
param_node = node |
|
|
|
elif node.name == "vector": |
|
|
|
child = node.children |
|
|
|
idx = 0 |
|
|
|
while child: |
|
|
|
if child.type == "element" and child.name == "param": |
|
|
|
if name == child.prop("name"): |
|
|
|
param_node = node |
|
|
|
param_index = idx |
|
|
|
break |
|
|
|
idx += 1 |
|
|
|
child = child.next |
|
|
|
if param_node: |
|
|
|
break |
|
|
|
return (param_node, param_index) |
|
|
|
|
|
|
|
def _find_final(self, func, param_nodes): |
|
|
|
"""Find the final parameter.""" |
|
|
|
param = func.get_param(self.name) |
|
|
|
param_index = -1 |
|
|
|
|
|
|
|
# the described param is not in the final function |
|
|
|
if not param: |
|
|
|
# search the template parameters |
|
|
|
node, index = self._search_param_node(param_nodes) |
|
|
|
if not node: |
|
|
|
raise SpecError("invalid desc %s in %s" % |
|
|
|
(self.name, func.name)) |
|
|
|
|
|
|
|
# a named parameter of a vector |
|
|
|
if index >= 0: |
|
|
|
param = func.get_param(node.prop("name")) |
|
|
|
param_index = index |
|
|
|
elif node.name == "vector": |
|
|
|
# must be an expanded vector, check its size |
|
|
|
if self.size_str and self.size_str.isdigit(): |
|
|
|
size = int(self.size_str) |
|
|
|
expanded_size = func.param_node_size(node) |
|
|
|
if size != expanded_size: |
|
|
|
return (False, None, -1) |
|
|
|
# otherwise, it is a valid, but no-op, description |
|
|
|
|
|
|
|
return (True, param, param_index) |
|
|
|
|
|
|
|
def validate(self, func, param_nodes): |
|
|
|
"""Validate a description against certain function.""" |
|
|
|
if self.checker.switches and not self.values: |
|
|
|
raise SpecError("no valid values for %s" % self.name) |
|
|
|
|
|
|
|
valid, param, param_index = self._find_final(func, param_nodes) |
|
|
|
if not valid: |
|
|
|
return False |
|
|
|
|
|
|
|
# the description is valid, but the param is gone |
|
|
|
# mark it no-op so that it will be skipped |
|
|
|
if not param: |
|
|
|
self._is_noop = True |
|
|
|
return True |
|
|
|
|
|
|
|
if param.is_vector: |
|
|
|
# if param was known, this should have been done in __init__ |
|
|
|
if self._has_enum: |
|
|
|
self.size_str = "1" |
|
|
|
# size mismatch |
|
|
|
if (param.size and self.size_str and self.size_str.isdigit() and |
|
|
|
param.size != int(self.size_str)): |
|
|
|
return False |
|
|
|
elif self.size_str: |
|
|
|
# only vector accepts vector_size |
|
|
|
raise SpecError("vector_size is invalid for %s" % param.name) |
|
|
|
|
|
|
|
if not self.checker.validate(func, param_nodes): |
|
|
|
return False |
|
|
|
|
|
|
|
# update the description |
|
|
|
self.name = param.name |
|
|
|
self.index = param_index |
|
|
|
|
|
|
|
return True |
|
|
|
|
|
|
|
|
|
|
|
def main(): |
|
|
|
import libxml2 |
|
|
|
|
|
|
|
filename = "APIspec.xml" |
|
|
|
apinames = ["GLES1.1", "GLES2.0"] |
|
|
|
|
|
|
|
doc = libxml2.readFile(filename, None, |
|
|
|
libxml2.XML_PARSE_DTDLOAD + |
|
|
|
libxml2.XML_PARSE_DTDVALID + |
|
|
|
libxml2.XML_PARSE_NOBLANKS) |
|
|
|
|
|
|
|
spec = Spec(doc) |
|
|
|
impl = spec.get_impl() |
|
|
|
for apiname in apinames: |
|
|
|
spec.get_api(apiname) |
|
|
|
|
|
|
|
doc.freeDoc() |
|
|
|
|
|
|
|
print "%s is successfully parsed" % filename |
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
|
main() |