1#!/usr/bin/python 2# 3# Copyright (C) 2009 Chia-I Wu <olv@0xlab.org> 4# 5# Permission is hereby granted, free of charge, to any person obtaining a 6# copy of this software and associated documentation files (the "Software"), 7# to deal in the Software without restriction, including without limitation 8# on the rights to use, copy, modify, merge, publish, distribute, sub 9# license, and/or sell copies of the Software, and to permit persons to whom 10# the Software is furnished to do so, subject to the following conditions: 11# 12# The above copyright notice and this permission notice (including the next 13# paragraph) shall be included in all copies or substantial portions of the 14# Software. 15# 16# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 19# IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22# IN THE SOFTWARE. 23""" 24Minimal apiutil.py interface for use by es_generator.py. 25""" 26 27import sys 28import libxml2 29 30import APIspec 31 32__spec = {} 33__functions = {} 34__aliases = {} 35 36def _ParseXML(filename, apiname): 37 conversions = { 38 # from to 39 'GLfloat': [ 'GLdouble' ], 40 'GLclampf': [ 'GLclampd' ], 41 'GLubyte': [ 'GLfloat', 'GLdouble' ], 42 'GLint': [ 'GLfloat', 'GLdouble' ], 43 'GLfixed': [ 'GLfloat', 'GLdouble' ], 44 'GLclampx': [ 'GLclampf', 'GLclampd' ], 45 } 46 47 doc = libxml2.readFile(filename, None, 48 libxml2.XML_PARSE_DTDLOAD + 49 libxml2.XML_PARSE_DTDVALID + 50 libxml2.XML_PARSE_NOBLANKS) 51 spec = APIspec.Spec(doc) 52 impl = spec.get_impl() 53 api = spec.get_api(apiname) 54 doc.freeDoc() 55 56 __spec["impl"] = impl 57 __spec["api"] = api 58 59 for func in api.functions: 60 alias, need_conv = impl.match(func, conversions) 61 if not alias: 62 # external functions are manually dispatched 63 if not func.is_external: 64 print >>sys.stderr, "Error: unable to dispatch %s" % func.name 65 alias = func 66 need_conv = False 67 68 __functions[func.name] = func 69 __aliases[func.name] = (alias, need_conv) 70 71 72def AllSpecials(notused=None): 73 """Return a list of all external functions in the API.""" 74 api = __spec["api"] 75 76 specials = [] 77 for func in api.functions: 78 if func.is_external: 79 specials.append(func.name) 80 81 return specials 82 83 84def GetAllFunctions(filename, api): 85 """Return sorted list of all functions in the API.""" 86 if not __spec: 87 _ParseXML(filename, api) 88 89 api = __spec["api"] 90 names = [] 91 for func in api.functions: 92 names.append(func.name) 93 names.sort() 94 return names 95 96 97def ReturnType(funcname): 98 """Return the C return type of named function.""" 99 func = __functions[funcname] 100 return func.return_type 101 102 103def Properties(funcname): 104 """Return list of properties of the named GL function.""" 105 func = __functions[funcname] 106 return [func.direction] 107 108 109def _ValidValues(func, param): 110 """Return the valid values of a parameter.""" 111 valid_values = [] 112 switch = func.checker.switches.get(param.name, []) 113 for desc in switch: 114 # no dependent vector 115 if not desc.checker.switches: 116 for val in desc.values: 117 valid_values.append((val, None, None, [], desc.error, None)) 118 continue 119 120 items = desc.checker.switches.items() 121 if len(items) > 1: 122 print >>sys.stderr, "%s: more than one parameter depend on %s" % \ 123 (func.name, desc.name) 124 dep_name, dep_switch = items[0] 125 126 for dep_desc in dep_switch: 127 if dep_desc.index >= 0 and dep_desc.index != 0: 128 print >>sys.stderr, "%s: not first element of a vector" % func.name 129 if dep_desc.checker.switches: 130 print >>sys.stderr, "%s: deep nested dependence" % func.name 131 132 convert = None if dep_desc.convert else "noconvert" 133 for val in desc.values: 134 valid_values.append((val, dep_desc.size_str, dep_desc.name, 135 dep_desc.values, dep_desc.error, convert)) 136 return valid_values 137 138 139def _Conversion(func, src_param): 140 """Return the destination type of the conversion, or None.""" 141 alias, need_conv = __aliases[func.name] 142 if need_conv: 143 dst_param = alias.get_param(src_param.name) 144 if src_param.type == dst_param.type: 145 need_conv = False 146 if not need_conv: 147 return (None, "none") 148 149 converts = { True: 0, False: 0 } 150 151 # In Fogx, for example, pname may be GL_FOG_DENSITY/GL_FOG_START/GL_FOG_END 152 # or GL_FOG_MODE. In the former three cases, param is not checked and the 153 # default is to convert. 154 if not func.checker.always_check(src_param.name): 155 converts[True] += 1 156 157 for desc in func.checker.flatten(src_param.name): 158 converts[desc.convert] += 1 159 if converts[True] and converts[False]: 160 break 161 162 # it should be "never", "sometimes", and "always"... 163 if converts[False]: 164 if converts[True]: 165 conversion = "some" 166 else: 167 conversion = "none" 168 else: 169 conversion = "all" 170 171 return (dst_param.base_type(), conversion) 172 173 174def _MaxVecSize(func, param): 175 """Return the largest possible size of a vector.""" 176 if not param.is_vector: 177 return 0 178 if param.size: 179 return param.size 180 181 # need to look at all descriptions 182 size = 0 183 for desc in func.checker.flatten(param.name): 184 if desc.size_str and desc.size_str.isdigit(): 185 s = int(desc.size_str) 186 if s > size: 187 size = s 188 if not size: 189 need_conv = __aliases[func.name][1] 190 if need_conv: 191 print >>sys.stderr, \ 192 "Error: unable to dicide the max size of %s in %s" % \ 193 (param.name, func.name) 194 return size 195 196 197def _ParameterTuple(func, param): 198 """Return a parameter tuple. 199 200 [0] -- parameter name 201 [1] -- parameter type 202 [2] -- max vector size or 0 203 [3] -- dest type the parameter converts to, or None 204 [4] -- valid values 205 [5] -- how often does the conversion happen 206 207 """ 208 vec_size = _MaxVecSize(func, param) 209 dst_type, conversion = _Conversion(func, param) 210 valid_values = _ValidValues(func, param) 211 212 return (param.name, param.type, vec_size, dst_type, valid_values, conversion) 213 214 215def Parameters(funcname): 216 """Return list of tuples of function parameters.""" 217 func = __functions[funcname] 218 params = [] 219 for param in func.params: 220 params.append(_ParameterTuple(func, param)) 221 222 return params 223 224 225def FunctionPrefix(funcname): 226 """Return function specific prefix.""" 227 func = __functions[funcname] 228 229 return func.prefix 230 231 232def FindParamIndex(params, paramname): 233 """Find the index of a named parameter.""" 234 for i in xrange(len(params)): 235 if params[i][0] == paramname: 236 return i 237 return None 238 239 240def MakeDeclarationString(params): 241 """Return a C-style parameter declaration string.""" 242 string = [] 243 for p in params: 244 sep = "" if p[1].endswith("*") else " " 245 string.append("%s%s%s" % (p[1], sep, p[0])) 246 if not string: 247 return "void" 248 return ", ".join(string) 249 250 251def AliasPrefix(funcname): 252 """Return the prefix of the function the named function is an alias of.""" 253 alias = __aliases[funcname][0] 254 return alias.prefix 255 256 257def Alias(funcname): 258 """Return the name of the function the named function is an alias of.""" 259 alias, need_conv = __aliases[funcname] 260 return alias.name if not need_conv else None 261 262 263def ConversionFunction(funcname): 264 """Return the name of the function the named function converts to.""" 265 alias, need_conv = __aliases[funcname] 266 return alias.name if need_conv else None 267 268 269def Categories(funcname): 270 """Return all the categories of the named GL function.""" 271 api = __spec["api"] 272 return [api.name] 273