| #!/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. |
| """ |
| Minimal apiutil.py interface for use by es_generator.py. |
| """ |
| |
| import sys |
| import libxml2 |
| |
| import APIspec |
| |
| __spec = {} |
| __functions = {} |
| __aliases = {} |
| |
| def _ParseXML(filename, apiname): |
| conversions = { |
| # from to |
| 'GLfloat': [ 'GLdouble' ], |
| 'GLclampf': [ 'GLclampd' ], |
| 'GLubyte': [ 'GLfloat', 'GLdouble' ], |
| 'GLint': [ 'GLfloat', 'GLdouble' ], |
| 'GLfixed': [ 'GLfloat', 'GLdouble' ], |
| 'GLclampx': [ 'GLclampf', 'GLclampd' ], |
| } |
| |
| doc = libxml2.readFile(filename, None, |
| libxml2.XML_PARSE_DTDLOAD + |
| libxml2.XML_PARSE_DTDVALID + |
| libxml2.XML_PARSE_NOBLANKS) |
| spec = APIspec.Spec(doc) |
| impl = spec.get_impl() |
| api = spec.get_api(apiname) |
| doc.freeDoc() |
| |
| __spec["impl"] = impl |
| __spec["api"] = api |
| |
| for func in api.functions: |
| alias, need_conv = impl.match(func, conversions) |
| if not alias: |
| # external functions are manually dispatched |
| if not func.is_external: |
| print >>sys.stderr, "Error: unable to dispatch %s" % func.name |
| alias = func |
| need_conv = False |
| |
| __functions[func.name] = func |
| __aliases[func.name] = (alias, need_conv) |
| |
| |
| def AllSpecials(notused=None): |
| """Return a list of all external functions in the API.""" |
| api = __spec["api"] |
| |
| specials = [] |
| for func in api.functions: |
| if func.is_external: |
| specials.append(func.name) |
| |
| return specials |
| |
| |
| def GetAllFunctions(filename, api): |
| """Return sorted list of all functions in the API.""" |
| if not __spec: |
| _ParseXML(filename, api) |
| |
| api = __spec["api"] |
| names = [] |
| for func in api.functions: |
| names.append(func.name) |
| names.sort() |
| return names |
| |
| |
| def ReturnType(funcname): |
| """Return the C return type of named function.""" |
| func = __functions[funcname] |
| return func.return_type |
| |
| |
| def Properties(funcname): |
| """Return list of properties of the named GL function.""" |
| func = __functions[funcname] |
| return [func.direction] |
| |
| |
| def _ValidValues(func, param): |
| """Return the valid values of a parameter.""" |
| valid_values = [] |
| switch = func.checker.switches.get(param.name, []) |
| for desc in switch: |
| # no dependent vector |
| if not desc.checker.switches: |
| for val in desc.values: |
| valid_values.append((val, None, None, [], desc.error, None)) |
| continue |
| |
| items = desc.checker.switches.items() |
| if len(items) > 1: |
| print >>sys.stderr, "%s: more than one parameter depend on %s" % \ |
| (func.name, desc.name) |
| dep_name, dep_switch = items[0] |
| |
| for dep_desc in dep_switch: |
| if dep_desc.index >= 0 and dep_desc.index != 0: |
| print >>sys.stderr, "%s: not first element of a vector" % func.name |
| if dep_desc.checker.switches: |
| print >>sys.stderr, "%s: deep nested dependence" % func.name |
| |
| convert = None if dep_desc.convert else "noconvert" |
| for val in desc.values: |
| valid_values.append((val, dep_desc.size_str, dep_desc.name, |
| dep_desc.values, dep_desc.error, convert)) |
| return valid_values |
| |
| |
| def _Conversion(func, src_param): |
| """Return the destination type of the conversion, or None.""" |
| alias, need_conv = __aliases[func.name] |
| if need_conv: |
| dst_param = alias.get_param(src_param.name) |
| if src_param.type == dst_param.type: |
| need_conv = False |
| if not need_conv: |
| return (None, "none") |
| |
| converts = { True: 0, False: 0 } |
| |
| # In Fogx, for example, pname may be GL_FOG_DENSITY/GL_FOG_START/GL_FOG_END |
| # or GL_FOG_MODE. In the former three cases, param is not checked and the |
| # default is to convert. |
| if not func.checker.always_check(src_param.name): |
| converts[True] += 1 |
| |
| for desc in func.checker.flatten(src_param.name): |
| converts[desc.convert] += 1 |
| if converts[True] and converts[False]: |
| break |
| |
| # it should be "never", "sometimes", and "always"... |
| if converts[False]: |
| if converts[True]: |
| conversion = "some" |
| else: |
| conversion = "none" |
| else: |
| conversion = "all" |
| |
| return (dst_param.base_type(), conversion) |
| |
| |
| def _MaxVecSize(func, param): |
| """Return the largest possible size of a vector.""" |
| if not param.is_vector: |
| return 0 |
| if param.size: |
| return param.size |
| |
| # need to look at all descriptions |
| size = 0 |
| for desc in func.checker.flatten(param.name): |
| if desc.size_str and desc.size_str.isdigit(): |
| s = int(desc.size_str) |
| if s > size: |
| size = s |
| if not size: |
| need_conv = __aliases[func.name][1] |
| if need_conv: |
| print >>sys.stderr, \ |
| "Error: unable to dicide the max size of %s in %s" % \ |
| (param.name, func.name) |
| return size |
| |
| |
| def _ParameterTuple(func, param): |
| """Return a parameter tuple. |
| |
| [0] -- parameter name |
| [1] -- parameter type |
| [2] -- max vector size or 0 |
| [3] -- dest type the parameter converts to, or None |
| [4] -- valid values |
| [5] -- how often does the conversion happen |
| |
| """ |
| vec_size = _MaxVecSize(func, param) |
| dst_type, conversion = _Conversion(func, param) |
| valid_values = _ValidValues(func, param) |
| |
| return (param.name, param.type, vec_size, dst_type, valid_values, conversion) |
| |
| |
| def Parameters(funcname): |
| """Return list of tuples of function parameters.""" |
| func = __functions[funcname] |
| params = [] |
| for param in func.params: |
| params.append(_ParameterTuple(func, param)) |
| |
| return params |
| |
| |
| def FunctionPrefix(funcname): |
| """Return function specific prefix.""" |
| func = __functions[funcname] |
| |
| return func.prefix |
| |
| |
| def FindParamIndex(params, paramname): |
| """Find the index of a named parameter.""" |
| for i in xrange(len(params)): |
| if params[i][0] == paramname: |
| return i |
| return None |
| |
| |
| def MakeDeclarationString(params): |
| """Return a C-style parameter declaration string.""" |
| string = [] |
| for p in params: |
| sep = "" if p[1].endswith("*") else " " |
| string.append("%s%s%s" % (p[1], sep, p[0])) |
| if not string: |
| return "void" |
| return ", ".join(string) |
| |
| |
| def AliasPrefix(funcname): |
| """Return the prefix of the function the named function is an alias of.""" |
| alias = __aliases[funcname][0] |
| return alias.prefix |
| |
| |
| def Alias(funcname): |
| """Return the name of the function the named function is an alias of.""" |
| alias, need_conv = __aliases[funcname] |
| return alias.name if not need_conv else None |
| |
| |
| def ConversionFunction(funcname): |
| """Return the name of the function the named function converts to.""" |
| alias, need_conv = __aliases[funcname] |
| return alias.name if need_conv else None |
| |
| |
| def Categories(funcname): |
| """Return all the categories of the named GL function.""" |
| api = __spec["api"] |
| return [api.name] |