1#!/usr/bin/python -u 2# 3# generate python wrappers from the XML API description 4# 5 6functions = {} 7enums = {} # { enumType: { enumConstant: enumValue } } 8 9import os 10import sys 11import string 12 13if __name__ == "__main__": 14 # launched as a script 15 srcPref = os.path.dirname(sys.argv[0]) 16else: 17 # imported 18 srcPref = os.path.dirname(__file__) 19 20####################################################################### 21# 22# That part if purely the API acquisition phase from the 23# XML API description 24# 25####################################################################### 26import os 27import xml.sax 28 29debug = 0 30 31def getparser(): 32 # Attach parser to an unmarshalling object. return both objects. 33 target = docParser() 34 parser = xml.sax.make_parser() 35 parser.setContentHandler(target) 36 return parser, target 37 38class docParser(xml.sax.handler.ContentHandler): 39 def __init__(self): 40 self._methodname = None 41 self._data = [] 42 self.in_function = 0 43 44 self.startElement = self.start 45 self.endElement = self.end 46 self.characters = self.data 47 48 def close(self): 49 if debug: 50 print "close" 51 52 def getmethodname(self): 53 return self._methodname 54 55 def data(self, text): 56 if debug: 57 print "data %s" % text 58 self._data.append(text) 59 60 def start(self, tag, attrs): 61 if debug: 62 print "start %s, %s" % (tag, attrs) 63 if tag == 'function': 64 self._data = [] 65 self.in_function = 1 66 self.function = None 67 self.function_cond = None 68 self.function_args = [] 69 self.function_descr = None 70 self.function_return = None 71 self.function_file = None 72 if attrs.has_key('name'): 73 self.function = attrs['name'] 74 if attrs.has_key('file'): 75 self.function_file = attrs['file'] 76 elif tag == 'cond': 77 self._data = [] 78 elif tag == 'info': 79 self._data = [] 80 elif tag == 'arg': 81 if self.in_function == 1: 82 self.function_arg_name = None 83 self.function_arg_type = None 84 self.function_arg_info = None 85 if attrs.has_key('name'): 86 self.function_arg_name = attrs['name'] 87 if attrs.has_key('type'): 88 self.function_arg_type = attrs['type'] 89 if attrs.has_key('info'): 90 self.function_arg_info = attrs['info'] 91 elif tag == 'return': 92 if self.in_function == 1: 93 self.function_return_type = None 94 self.function_return_info = None 95 self.function_return_field = None 96 if attrs.has_key('type'): 97 self.function_return_type = attrs['type'] 98 if attrs.has_key('info'): 99 self.function_return_info = attrs['info'] 100 if attrs.has_key('field'): 101 self.function_return_field = attrs['field'] 102 elif tag == 'enum': 103 enum(attrs['type'],attrs['name'],attrs['value']) 104 105 def end(self, tag): 106 if debug: 107 print "end %s" % tag 108 if tag == 'function': 109 if self.function != None: 110 function(self.function, self.function_descr, 111 self.function_return, self.function_args, 112 self.function_file, self.function_cond) 113 self.in_function = 0 114 elif tag == 'arg': 115 if self.in_function == 1: 116 self.function_args.append([self.function_arg_name, 117 self.function_arg_type, 118 self.function_arg_info]) 119 elif tag == 'return': 120 if self.in_function == 1: 121 self.function_return = [self.function_return_type, 122 self.function_return_info, 123 self.function_return_field] 124 elif tag == 'info': 125 str = '' 126 for c in self._data: 127 str = str + c 128 if self.in_function == 1: 129 self.function_descr = str 130 elif tag == 'cond': 131 str = '' 132 for c in self._data: 133 str = str + c 134 if self.in_function == 1: 135 self.function_cond = str 136 137 138def function(name, desc, ret, args, file, cond): 139 functions[name] = (desc, ret, args, file, cond) 140 141def enum(type, name, value): 142 if not enums.has_key(type): 143 enums[type] = {} 144 enums[type][name] = value 145 146####################################################################### 147# 148# Some filtering rukes to drop functions/types which should not 149# be exposed as-is on the Python interface 150# 151####################################################################### 152 153skipped_modules = { 154 'xmlmemory': None, 155 'DOCBparser': None, 156 'SAX': None, 157 'hash': None, 158 'list': None, 159 'threads': None, 160# 'xpointer': None, 161} 162skipped_types = { 163 'int *': "usually a return type", 164 'xmlSAXHandlerPtr': "not the proper interface for SAX", 165 'htmlSAXHandlerPtr': "not the proper interface for SAX", 166 'xmlRMutexPtr': "thread specific, skipped", 167 'xmlMutexPtr': "thread specific, skipped", 168 'xmlGlobalStatePtr': "thread specific, skipped", 169 'xmlListPtr': "internal representation not suitable for python", 170 'xmlBufferPtr': "internal representation not suitable for python", 171 'FILE *': None, 172} 173 174####################################################################### 175# 176# Table of remapping to/from the python type or class to the C 177# counterpart. 178# 179####################################################################### 180 181py_types = { 182 'void': (None, None, None, None), 183 'int': ('i', None, "int", "int"), 184 'long': ('l', None, "long", "long"), 185 'double': ('d', None, "double", "double"), 186 'unsigned int': ('i', None, "int", "int"), 187 'xmlChar': ('c', None, "int", "int"), 188 'unsigned char *': ('z', None, "charPtr", "char *"), 189 'char *': ('z', None, "charPtr", "char *"), 190 'const char *': ('z', None, "charPtrConst", "const char *"), 191 'xmlChar *': ('z', None, "xmlCharPtr", "xmlChar *"), 192 'const xmlChar *': ('z', None, "xmlCharPtrConst", "const xmlChar *"), 193 'xmlNodePtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 194 'const xmlNodePtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 195 'xmlNode *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 196 'const xmlNode *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 197 'xmlDtdPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 198 'const xmlDtdPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 199 'xmlDtd *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 200 'const xmlDtd *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 201 'xmlAttrPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 202 'const xmlAttrPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 203 'xmlAttr *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 204 'const xmlAttr *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 205 'xmlEntityPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 206 'const xmlEntityPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 207 'xmlEntity *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 208 'const xmlEntity *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 209 'xmlElementPtr': ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr"), 210 'const xmlElementPtr': ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr"), 211 'xmlElement *': ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr"), 212 'const xmlElement *': ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr"), 213 'xmlAttributePtr': ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr"), 214 'const xmlAttributePtr': ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr"), 215 'xmlAttribute *': ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr"), 216 'const xmlAttribute *': ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr"), 217 'xmlNsPtr': ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr"), 218 'const xmlNsPtr': ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr"), 219 'xmlNs *': ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr"), 220 'const xmlNs *': ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr"), 221 'xmlDocPtr': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"), 222 'const xmlDocPtr': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"), 223 'xmlDoc *': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"), 224 'const xmlDoc *': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"), 225 'htmlDocPtr': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"), 226 'const htmlDocPtr': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"), 227 'htmlDoc *': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"), 228 'const htmlDoc *': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"), 229 'htmlNodePtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 230 'const htmlNodePtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 231 'htmlNode *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 232 'const htmlNode *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"), 233 'xmlXPathContextPtr': ('O', "xmlXPathContext", "xmlXPathContextPtr", "xmlXPathContextPtr"), 234 'xmlXPathContext *': ('O', "xpathContext", "xmlXPathContextPtr", "xmlXPathContextPtr"), 235 'xmlXPathParserContextPtr': ('O', "xmlXPathParserContext", "xmlXPathParserContextPtr", "xmlXPathParserContextPtr"), 236 'xmlParserCtxtPtr': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr"), 237 'xmlParserCtxt *': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr"), 238 'htmlParserCtxtPtr': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr"), 239 'htmlParserCtxt *': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr"), 240 'xmlValidCtxtPtr': ('O', "ValidCtxt", "xmlValidCtxtPtr", "xmlValidCtxtPtr"), 241 'xmlCatalogPtr': ('O', "catalog", "xmlCatalogPtr", "xmlCatalogPtr"), 242 'FILE *': ('O', "File", "FILEPtr", "FILE *"), 243 'xmlURIPtr': ('O', "URI", "xmlURIPtr", "xmlURIPtr"), 244 'xmlErrorPtr': ('O', "Error", "xmlErrorPtr", "xmlErrorPtr"), 245 'xmlOutputBufferPtr': ('O', "outputBuffer", "xmlOutputBufferPtr", "xmlOutputBufferPtr"), 246 'xmlParserInputBufferPtr': ('O', "inputBuffer", "xmlParserInputBufferPtr", "xmlParserInputBufferPtr"), 247 'xmlRegexpPtr': ('O', "xmlReg", "xmlRegexpPtr", "xmlRegexpPtr"), 248 'xmlTextReaderLocatorPtr': ('O', "xmlTextReaderLocator", "xmlTextReaderLocatorPtr", "xmlTextReaderLocatorPtr"), 249 'xmlTextReaderPtr': ('O', "xmlTextReader", "xmlTextReaderPtr", "xmlTextReaderPtr"), 250 'xmlRelaxNGPtr': ('O', "relaxNgSchema", "xmlRelaxNGPtr", "xmlRelaxNGPtr"), 251 'xmlRelaxNGParserCtxtPtr': ('O', "relaxNgParserCtxt", "xmlRelaxNGParserCtxtPtr", "xmlRelaxNGParserCtxtPtr"), 252 'xmlRelaxNGValidCtxtPtr': ('O', "relaxNgValidCtxt", "xmlRelaxNGValidCtxtPtr", "xmlRelaxNGValidCtxtPtr"), 253 'xmlSchemaPtr': ('O', "Schema", "xmlSchemaPtr", "xmlSchemaPtr"), 254 'xmlSchemaParserCtxtPtr': ('O', "SchemaParserCtxt", "xmlSchemaParserCtxtPtr", "xmlSchemaParserCtxtPtr"), 255 'xmlSchemaValidCtxtPtr': ('O', "SchemaValidCtxt", "xmlSchemaValidCtxtPtr", "xmlSchemaValidCtxtPtr"), 256} 257 258py_return_types = { 259 'xmlXPathObjectPtr': ('O', "foo", "xmlXPathObjectPtr", "xmlXPathObjectPtr"), 260} 261 262unknown_types = {} 263 264foreign_encoding_args = ( 265 'htmlCreateMemoryParserCtxt', 266 'htmlCtxtReadMemory', 267 'htmlParseChunk', 268 'htmlReadMemory', 269 'xmlCreateMemoryParserCtxt', 270 'xmlCtxtReadMemory', 271 'xmlCtxtResetPush', 272 'xmlParseChunk', 273 'xmlParseMemory', 274 'xmlReadMemory', 275 'xmlRecoverMemory', 276) 277 278####################################################################### 279# 280# This part writes the C <-> Python stubs libxml2-py.[ch] and 281# the table libxml2-export.c to add when registrering the Python module 282# 283####################################################################### 284 285# Class methods which are written by hand in libxml.c but the Python-level 286# code is still automatically generated (so they are not in skip_function()). 287skip_impl = ( 288 'xmlSaveFileTo', 289 'xmlSaveFormatFileTo', 290) 291 292def skip_function(name): 293 if name[0:12] == "xmlXPathWrap": 294 return 1 295 if name == "xmlFreeParserCtxt": 296 return 1 297 if name == "xmlCleanupParser": 298 return 1 299 if name == "xmlFreeTextReader": 300 return 1 301# if name[0:11] == "xmlXPathNew": 302# return 1 303 # the next function is defined in libxml.c 304 if name == "xmlRelaxNGFreeValidCtxt": 305 return 1 306 if name == "xmlFreeValidCtxt": 307 return 1 308 if name == "xmlSchemaFreeValidCtxt": 309 return 1 310 311# 312# Those are skipped because the Const version is used of the bindings 313# instead. 314# 315 if name == "xmlTextReaderBaseUri": 316 return 1 317 if name == "xmlTextReaderLocalName": 318 return 1 319 if name == "xmlTextReaderName": 320 return 1 321 if name == "xmlTextReaderNamespaceUri": 322 return 1 323 if name == "xmlTextReaderPrefix": 324 return 1 325 if name == "xmlTextReaderXmlLang": 326 return 1 327 if name == "xmlTextReaderValue": 328 return 1 329 if name == "xmlOutputBufferClose": # handled by by the superclass 330 return 1 331 if name == "xmlOutputBufferFlush": # handled by by the superclass 332 return 1 333 if name == "xmlErrMemory": 334 return 1 335 336 if name == "xmlValidBuildContentModel": 337 return 1 338 if name == "xmlValidateElementDecl": 339 return 1 340 if name == "xmlValidateAttributeDecl": 341 return 1 342 343 return 0 344 345def print_function_wrapper(name, output, export, include): 346 global py_types 347 global unknown_types 348 global functions 349 global skipped_modules 350 351 try: 352 (desc, ret, args, file, cond) = functions[name] 353 except: 354 print "failed to get function %s infos" 355 return 356 357 if skipped_modules.has_key(file): 358 return 0 359 if skip_function(name) == 1: 360 return 0 361 if name in skip_impl: 362 # Don't delete the function entry in the caller. 363 return 1 364 365 c_call = "" 366 format="" 367 format_args="" 368 c_args="" 369 c_return="" 370 c_convert="" 371 num_bufs=0 372 for arg in args: 373 # This should be correct 374 if arg[1][0:6] == "const ": 375 arg[1] = arg[1][6:] 376 c_args = c_args + " %s %s;\n" % (arg[1], arg[0]) 377 if py_types.has_key(arg[1]): 378 (f, t, n, c) = py_types[arg[1]] 379 if (f == 'z') and (name in foreign_encoding_args) and (num_bufs == 0): 380 f = 't#' 381 if f != None: 382 format = format + f 383 if t != None: 384 format_args = format_args + ", &pyobj_%s" % (arg[0]) 385 c_args = c_args + " PyObject *pyobj_%s;\n" % (arg[0]) 386 c_convert = c_convert + \ 387 " %s = (%s) Py%s_Get(pyobj_%s);\n" % (arg[0], 388 arg[1], t, arg[0]) 389 else: 390 format_args = format_args + ", &%s" % (arg[0]) 391 if f == 't#': 392 format_args = format_args + ", &py_buffsize%d" % num_bufs 393 c_args = c_args + " int py_buffsize%d;\n" % num_bufs 394 num_bufs = num_bufs + 1 395 if c_call != "": 396 c_call = c_call + ", " 397 c_call = c_call + "%s" % (arg[0]) 398 else: 399 if skipped_types.has_key(arg[1]): 400 return 0 401 if unknown_types.has_key(arg[1]): 402 lst = unknown_types[arg[1]] 403 lst.append(name) 404 else: 405 unknown_types[arg[1]] = [name] 406 return -1 407 if format != "": 408 format = format + ":%s" % (name) 409 410 if ret[0] == 'void': 411 if file == "python_accessor": 412 if args[1][1] == "char *" or args[1][1] == "xmlChar *": 413 c_call = "\n if (%s->%s != NULL) xmlFree(%s->%s);\n" % ( 414 args[0][0], args[1][0], args[0][0], args[1][0]) 415 c_call = c_call + " %s->%s = (%s)xmlStrdup((const xmlChar *)%s);\n" % (args[0][0], 416 args[1][0], args[1][1], args[1][0]) 417 else: 418 c_call = "\n %s->%s = %s;\n" % (args[0][0], args[1][0], 419 args[1][0]) 420 else: 421 c_call = "\n %s(%s);\n" % (name, c_call) 422 ret_convert = " Py_INCREF(Py_None);\n return(Py_None);\n" 423 elif py_types.has_key(ret[0]): 424 (f, t, n, c) = py_types[ret[0]] 425 c_return = " %s c_retval;\n" % (ret[0]) 426 if file == "python_accessor" and ret[2] != None: 427 c_call = "\n c_retval = %s->%s;\n" % (args[0][0], ret[2]) 428 else: 429 c_call = "\n c_retval = %s(%s);\n" % (name, c_call) 430 ret_convert = " py_retval = libxml_%sWrap((%s) c_retval);\n" % (n,c) 431 ret_convert = ret_convert + " return(py_retval);\n" 432 elif py_return_types.has_key(ret[0]): 433 (f, t, n, c) = py_return_types[ret[0]] 434 c_return = " %s c_retval;\n" % (ret[0]) 435 c_call = "\n c_retval = %s(%s);\n" % (name, c_call) 436 ret_convert = " py_retval = libxml_%sWrap((%s) c_retval);\n" % (n,c) 437 ret_convert = ret_convert + " return(py_retval);\n" 438 else: 439 if skipped_types.has_key(ret[0]): 440 return 0 441 if unknown_types.has_key(ret[0]): 442 lst = unknown_types[ret[0]] 443 lst.append(name) 444 else: 445 unknown_types[ret[0]] = [name] 446 return -1 447 448 if cond != None and cond != "": 449 include.write("#if %s\n" % cond) 450 export.write("#if %s\n" % cond) 451 output.write("#if %s\n" % cond) 452 453 include.write("PyObject * ") 454 include.write("libxml_%s(PyObject *self, PyObject *args);\n" % (name)) 455 456 export.write(" { (char *)\"%s\", libxml_%s, METH_VARARGS, NULL },\n" % 457 (name, name)) 458 459 if file == "python": 460 # Those have been manually generated 461 if cond != None and cond != "": 462 include.write("#endif\n") 463 export.write("#endif\n") 464 output.write("#endif\n") 465 return 1 466 if file == "python_accessor" and ret[0] != "void" and ret[2] is None: 467 # Those have been manually generated 468 if cond != None and cond != "": 469 include.write("#endif\n") 470 export.write("#endif\n") 471 output.write("#endif\n") 472 return 1 473 474 output.write("PyObject *\n") 475 output.write("libxml_%s(PyObject *self ATTRIBUTE_UNUSED," % (name)) 476 output.write(" PyObject *args") 477 if format == "": 478 output.write(" ATTRIBUTE_UNUSED") 479 output.write(") {\n") 480 if ret[0] != 'void': 481 output.write(" PyObject *py_retval;\n") 482 if c_return != "": 483 output.write(c_return) 484 if c_args != "": 485 output.write(c_args) 486 if format != "": 487 output.write("\n if (!PyArg_ParseTuple(args, (char *)\"%s\"%s))\n" % 488 (format, format_args)) 489 output.write(" return(NULL);\n") 490 if c_convert != "": 491 output.write(c_convert) 492 493 output.write(c_call) 494 output.write(ret_convert) 495 output.write("}\n\n") 496 if cond != None and cond != "": 497 include.write("#endif /* %s */\n" % cond) 498 export.write("#endif /* %s */\n" % cond) 499 output.write("#endif /* %s */\n" % cond) 500 return 1 501 502def buildStubs(): 503 global py_types 504 global py_return_types 505 global unknown_types 506 507 try: 508 f = open(os.path.join(srcPref,"libxml2-api.xml")) 509 data = f.read() 510 (parser, target) = getparser() 511 parser.feed(data) 512 parser.close() 513 except IOError, msg: 514 try: 515 f = open(os.path.join(srcPref,"..","doc","libxml2-api.xml")) 516 data = f.read() 517 (parser, target) = getparser() 518 parser.feed(data) 519 parser.close() 520 except IOError, msg: 521 print file, ":", msg 522 sys.exit(1) 523 524 n = len(functions.keys()) 525 print "Found %d functions in libxml2-api.xml" % (n) 526 527 py_types['pythonObject'] = ('O', "pythonObject", "pythonObject", "pythonObject") 528 try: 529 f = open(os.path.join(srcPref,"libxml2-python-api.xml")) 530 data = f.read() 531 (parser, target) = getparser() 532 parser.feed(data) 533 parser.close() 534 except IOError, msg: 535 print file, ":", msg 536 537 538 print "Found %d functions in libxml2-python-api.xml" % ( 539 len(functions.keys()) - n) 540 nb_wrap = 0 541 failed = 0 542 skipped = 0 543 544 include = open("libxml2-py.h", "w") 545 include.write("/* Generated */\n\n") 546 export = open("libxml2-export.c", "w") 547 export.write("/* Generated */\n\n") 548 wrapper = open("libxml2-py.c", "w") 549 wrapper.write("/* Generated */\n\n") 550 wrapper.write("#include <Python.h>\n") 551 wrapper.write("#include <libxml/xmlversion.h>\n") 552 wrapper.write("#include <libxml/tree.h>\n") 553 wrapper.write("#include <libxml/xmlschemastypes.h>\n") 554 wrapper.write("#include \"libxml_wrap.h\"\n") 555 wrapper.write("#include \"libxml2-py.h\"\n\n") 556 for function in functions.keys(): 557 ret = print_function_wrapper(function, wrapper, export, include) 558 if ret < 0: 559 failed = failed + 1 560 del functions[function] 561 if ret == 0: 562 skipped = skipped + 1 563 del functions[function] 564 if ret == 1: 565 nb_wrap = nb_wrap + 1 566 include.close() 567 export.close() 568 wrapper.close() 569 570 print "Generated %d wrapper functions, %d failed, %d skipped\n" % (nb_wrap, 571 failed, skipped) 572 print "Missing type converters: " 573 for type in unknown_types.keys(): 574 print "%s:%d " % (type, len(unknown_types[type])), 575 print 576 577####################################################################### 578# 579# This part writes part of the Python front-end classes based on 580# mapping rules between types and classes and also based on function 581# renaming to get consistent function names at the Python level 582# 583####################################################################### 584 585# 586# The type automatically remapped to generated classes 587# 588classes_type = { 589 "xmlNodePtr": ("._o", "xmlNode(_obj=%s)", "xmlNode"), 590 "xmlNode *": ("._o", "xmlNode(_obj=%s)", "xmlNode"), 591 "xmlDocPtr": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"), 592 "xmlDocPtr *": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"), 593 "htmlDocPtr": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"), 594 "htmlxmlDocPtr *": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"), 595 "xmlAttrPtr": ("._o", "xmlAttr(_obj=%s)", "xmlAttr"), 596 "xmlAttr *": ("._o", "xmlAttr(_obj=%s)", "xmlAttr"), 597 "xmlNsPtr": ("._o", "xmlNs(_obj=%s)", "xmlNs"), 598 "xmlNs *": ("._o", "xmlNs(_obj=%s)", "xmlNs"), 599 "xmlDtdPtr": ("._o", "xmlDtd(_obj=%s)", "xmlDtd"), 600 "xmlDtd *": ("._o", "xmlDtd(_obj=%s)", "xmlDtd"), 601 "xmlEntityPtr": ("._o", "xmlEntity(_obj=%s)", "xmlEntity"), 602 "xmlEntity *": ("._o", "xmlEntity(_obj=%s)", "xmlEntity"), 603 "xmlElementPtr": ("._o", "xmlElement(_obj=%s)", "xmlElement"), 604 "xmlElement *": ("._o", "xmlElement(_obj=%s)", "xmlElement"), 605 "xmlAttributePtr": ("._o", "xmlAttribute(_obj=%s)", "xmlAttribute"), 606 "xmlAttribute *": ("._o", "xmlAttribute(_obj=%s)", "xmlAttribute"), 607 "xmlXPathContextPtr": ("._o", "xpathContext(_obj=%s)", "xpathContext"), 608 "xmlXPathContext *": ("._o", "xpathContext(_obj=%s)", "xpathContext"), 609 "xmlXPathParserContext *": ("._o", "xpathParserContext(_obj=%s)", "xpathParserContext"), 610 "xmlXPathParserContextPtr": ("._o", "xpathParserContext(_obj=%s)", "xpathParserContext"), 611 "xmlParserCtxtPtr": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"), 612 "xmlParserCtxt *": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"), 613 "htmlParserCtxtPtr": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"), 614 "htmlParserCtxt *": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"), 615 "xmlValidCtxtPtr": ("._o", "ValidCtxt(_obj=%s)", "ValidCtxt"), 616 "xmlCatalogPtr": ("._o", "catalog(_obj=%s)", "catalog"), 617 "xmlURIPtr": ("._o", "URI(_obj=%s)", "URI"), 618 "xmlErrorPtr": ("._o", "Error(_obj=%s)", "Error"), 619 "xmlOutputBufferPtr": ("._o", "outputBuffer(_obj=%s)", "outputBuffer"), 620 "xmlParserInputBufferPtr": ("._o", "inputBuffer(_obj=%s)", "inputBuffer"), 621 "xmlRegexpPtr": ("._o", "xmlReg(_obj=%s)", "xmlReg"), 622 "xmlTextReaderLocatorPtr": ("._o", "xmlTextReaderLocator(_obj=%s)", "xmlTextReaderLocator"), 623 "xmlTextReaderPtr": ("._o", "xmlTextReader(_obj=%s)", "xmlTextReader"), 624 'xmlRelaxNGPtr': ('._o', "relaxNgSchema(_obj=%s)", "relaxNgSchema"), 625 'xmlRelaxNGParserCtxtPtr': ('._o', "relaxNgParserCtxt(_obj=%s)", "relaxNgParserCtxt"), 626 'xmlRelaxNGValidCtxtPtr': ('._o', "relaxNgValidCtxt(_obj=%s)", "relaxNgValidCtxt"), 627 'xmlSchemaPtr': ("._o", "Schema(_obj=%s)", "Schema"), 628 'xmlSchemaParserCtxtPtr': ("._o", "SchemaParserCtxt(_obj=%s)", "SchemaParserCtxt"), 629 'xmlSchemaValidCtxtPtr': ("._o", "SchemaValidCtxt(_obj=%s)", "SchemaValidCtxt"), 630} 631 632converter_type = { 633 "xmlXPathObjectPtr": "xpathObjectRet(%s)", 634} 635 636primary_classes = ["xmlNode", "xmlDoc"] 637 638classes_ancestor = { 639 "xmlNode" : "xmlCore", 640 "xmlDtd" : "xmlNode", 641 "xmlDoc" : "xmlNode", 642 "xmlAttr" : "xmlNode", 643 "xmlNs" : "xmlNode", 644 "xmlEntity" : "xmlNode", 645 "xmlElement" : "xmlNode", 646 "xmlAttribute" : "xmlNode", 647 "outputBuffer": "ioWriteWrapper", 648 "inputBuffer": "ioReadWrapper", 649 "parserCtxt": "parserCtxtCore", 650 "xmlTextReader": "xmlTextReaderCore", 651 "ValidCtxt": "ValidCtxtCore", 652 "SchemaValidCtxt": "SchemaValidCtxtCore", 653 "relaxNgValidCtxt": "relaxNgValidCtxtCore", 654} 655classes_destructors = { 656 "parserCtxt": "xmlFreeParserCtxt", 657 "catalog": "xmlFreeCatalog", 658 "URI": "xmlFreeURI", 659# "outputBuffer": "xmlOutputBufferClose", 660 "inputBuffer": "xmlFreeParserInputBuffer", 661 "xmlReg": "xmlRegFreeRegexp", 662 "xmlTextReader": "xmlFreeTextReader", 663 "relaxNgSchema": "xmlRelaxNGFree", 664 "relaxNgParserCtxt": "xmlRelaxNGFreeParserCtxt", 665 "relaxNgValidCtxt": "xmlRelaxNGFreeValidCtxt", 666 "Schema": "xmlSchemaFree", 667 "SchemaParserCtxt": "xmlSchemaFreeParserCtxt", 668 "SchemaValidCtxt": "xmlSchemaFreeValidCtxt", 669 "ValidCtxt": "xmlFreeValidCtxt", 670} 671 672functions_noexcept = { 673 "xmlHasProp": 1, 674 "xmlHasNsProp": 1, 675 "xmlDocSetRootElement": 1, 676 "xmlNodeGetNs": 1, 677 "xmlNodeGetNsDefs": 1, 678 "xmlNextElementSibling": 1, 679 "xmlPreviousElementSibling": 1, 680 "xmlFirstElementChild": 1, 681 "xmlLastElementChild": 1, 682} 683 684reference_keepers = { 685 "xmlTextReader": [('inputBuffer', 'input')], 686 "relaxNgValidCtxt": [('relaxNgSchema', 'schema')], 687 "SchemaValidCtxt": [('Schema', 'schema')], 688} 689 690function_classes = {} 691 692function_classes["None"] = [] 693 694def nameFixup(name, classe, type, file): 695 listname = classe + "List" 696 ll = len(listname) 697 l = len(classe) 698 if name[0:l] == listname: 699 func = name[l:] 700 func = string.lower(func[0:1]) + func[1:] 701 elif name[0:12] == "xmlParserGet" and file == "python_accessor": 702 func = name[12:] 703 func = string.lower(func[0:1]) + func[1:] 704 elif name[0:12] == "xmlParserSet" and file == "python_accessor": 705 func = name[12:] 706 func = string.lower(func[0:1]) + func[1:] 707 elif name[0:10] == "xmlNodeGet" and file == "python_accessor": 708 func = name[10:] 709 func = string.lower(func[0:1]) + func[1:] 710 elif name[0:9] == "xmlURIGet" and file == "python_accessor": 711 func = name[9:] 712 func = string.lower(func[0:1]) + func[1:] 713 elif name[0:9] == "xmlURISet" and file == "python_accessor": 714 func = name[6:] 715 func = string.lower(func[0:1]) + func[1:] 716 elif name[0:11] == "xmlErrorGet" and file == "python_accessor": 717 func = name[11:] 718 func = string.lower(func[0:1]) + func[1:] 719 elif name[0:17] == "xmlXPathParserGet" and file == "python_accessor": 720 func = name[17:] 721 func = string.lower(func[0:1]) + func[1:] 722 elif name[0:11] == "xmlXPathGet" and file == "python_accessor": 723 func = name[11:] 724 func = string.lower(func[0:1]) + func[1:] 725 elif name[0:11] == "xmlXPathSet" and file == "python_accessor": 726 func = name[8:] 727 func = string.lower(func[0:1]) + func[1:] 728 elif name[0:15] == "xmlOutputBuffer" and file != "python": 729 func = name[15:] 730 func = string.lower(func[0:1]) + func[1:] 731 elif name[0:20] == "xmlParserInputBuffer" and file != "python": 732 func = name[20:] 733 func = string.lower(func[0:1]) + func[1:] 734 elif name[0:9] == "xmlRegexp" and file == "xmlregexp": 735 func = "regexp" + name[9:] 736 elif name[0:6] == "xmlReg" and file == "xmlregexp": 737 func = "regexp" + name[6:] 738 elif name[0:20] == "xmlTextReaderLocator" and file == "xmlreader": 739 func = name[20:] 740 elif name[0:18] == "xmlTextReaderConst" and file == "xmlreader": 741 func = name[18:] 742 elif name[0:13] == "xmlTextReader" and file == "xmlreader": 743 func = name[13:] 744 elif name[0:12] == "xmlReaderNew" and file == "xmlreader": 745 func = name[9:] 746 elif name[0:11] == "xmlACatalog": 747 func = name[11:] 748 func = string.lower(func[0:1]) + func[1:] 749 elif name[0:l] == classe: 750 func = name[l:] 751 func = string.lower(func[0:1]) + func[1:] 752 elif name[0:7] == "libxml_": 753 func = name[7:] 754 func = string.lower(func[0:1]) + func[1:] 755 elif name[0:6] == "xmlGet": 756 func = name[6:] 757 func = string.lower(func[0:1]) + func[1:] 758 elif name[0:3] == "xml": 759 func = name[3:] 760 func = string.lower(func[0:1]) + func[1:] 761 else: 762 func = name 763 if func[0:5] == "xPath": 764 func = "xpath" + func[5:] 765 elif func[0:4] == "xPtr": 766 func = "xpointer" + func[4:] 767 elif func[0:8] == "xInclude": 768 func = "xinclude" + func[8:] 769 elif func[0:2] == "iD": 770 func = "ID" + func[2:] 771 elif func[0:3] == "uRI": 772 func = "URI" + func[3:] 773 elif func[0:4] == "uTF8": 774 func = "UTF8" + func[4:] 775 elif func[0:3] == 'sAX': 776 func = "SAX" + func[3:] 777 return func 778 779 780def functionCompare(info1, info2): 781 (index1, func1, name1, ret1, args1, file1) = info1 782 (index2, func2, name2, ret2, args2, file2) = info2 783 if file1 == file2: 784 if func1 < func2: 785 return -1 786 if func1 > func2: 787 return 1 788 if file1 == "python_accessor": 789 return -1 790 if file2 == "python_accessor": 791 return 1 792 if file1 < file2: 793 return -1 794 if file1 > file2: 795 return 1 796 return 0 797 798def writeDoc(name, args, indent, output): 799 if functions[name][0] is None or functions[name][0] == "": 800 return 801 val = functions[name][0] 802 val = string.replace(val, "NULL", "None") 803 output.write(indent) 804 output.write('"""') 805 while len(val) > 60: 806 if val[0] == " ": 807 val = val[1:] 808 continue 809 str = val[0:60] 810 i = string.rfind(str, " ") 811 if i < 0: 812 i = 60 813 str = val[0:i] 814 val = val[i:] 815 output.write(str) 816 output.write('\n ') 817 output.write(indent) 818 output.write(val) 819 output.write(' """\n') 820 821def buildWrappers(): 822 global ctypes 823 global py_types 824 global py_return_types 825 global unknown_types 826 global functions 827 global function_classes 828 global classes_type 829 global classes_list 830 global converter_type 831 global primary_classes 832 global converter_type 833 global classes_ancestor 834 global converter_type 835 global primary_classes 836 global classes_ancestor 837 global classes_destructors 838 global functions_noexcept 839 840 for type in classes_type.keys(): 841 function_classes[classes_type[type][2]] = [] 842 843 # 844 # Build the list of C types to look for ordered to start 845 # with primary classes 846 # 847 ctypes = [] 848 classes_list = [] 849 ctypes_processed = {} 850 classes_processed = {} 851 for classe in primary_classes: 852 classes_list.append(classe) 853 classes_processed[classe] = () 854 for type in classes_type.keys(): 855 tinfo = classes_type[type] 856 if tinfo[2] == classe: 857 ctypes.append(type) 858 ctypes_processed[type] = () 859 for type in classes_type.keys(): 860 if ctypes_processed.has_key(type): 861 continue 862 tinfo = classes_type[type] 863 if not classes_processed.has_key(tinfo[2]): 864 classes_list.append(tinfo[2]) 865 classes_processed[tinfo[2]] = () 866 867 ctypes.append(type) 868 ctypes_processed[type] = () 869 870 for name in functions.keys(): 871 found = 0 872 (desc, ret, args, file, cond) = functions[name] 873 for type in ctypes: 874 classe = classes_type[type][2] 875 876 if name[0:3] == "xml" and len(args) >= 1 and args[0][1] == type: 877 found = 1 878 func = nameFixup(name, classe, type, file) 879 info = (0, func, name, ret, args, file) 880 function_classes[classe].append(info) 881 elif name[0:3] == "xml" and len(args) >= 2 and args[1][1] == type \ 882 and file != "python_accessor": 883 found = 1 884 func = nameFixup(name, classe, type, file) 885 info = (1, func, name, ret, args, file) 886 function_classes[classe].append(info) 887 elif name[0:4] == "html" and len(args) >= 1 and args[0][1] == type: 888 found = 1 889 func = nameFixup(name, classe, type, file) 890 info = (0, func, name, ret, args, file) 891 function_classes[classe].append(info) 892 elif name[0:4] == "html" and len(args) >= 2 and args[1][1] == type \ 893 and file != "python_accessor": 894 found = 1 895 func = nameFixup(name, classe, type, file) 896 info = (1, func, name, ret, args, file) 897 function_classes[classe].append(info) 898 if found == 1: 899 continue 900 if name[0:8] == "xmlXPath": 901 continue 902 if name[0:6] == "xmlStr": 903 continue 904 if name[0:10] == "xmlCharStr": 905 continue 906 func = nameFixup(name, "None", file, file) 907 info = (0, func, name, ret, args, file) 908 function_classes['None'].append(info) 909 910 classes = open("libxml2class.py", "w") 911 txt = open("libxml2class.txt", "w") 912 txt.write(" Generated Classes for libxml2-python\n\n") 913 914 txt.write("#\n# Global functions of the module\n#\n\n") 915 if function_classes.has_key("None"): 916 flist = function_classes["None"] 917 flist.sort(functionCompare) 918 oldfile = "" 919 for info in flist: 920 (index, func, name, ret, args, file) = info 921 if file != oldfile: 922 classes.write("#\n# Functions from module %s\n#\n\n" % file) 923 txt.write("\n# functions from module %s\n" % file) 924 oldfile = file 925 classes.write("def %s(" % func) 926 txt.write("%s()\n" % func) 927 n = 0 928 for arg in args: 929 if n != 0: 930 classes.write(", ") 931 classes.write("%s" % arg[0]) 932 n = n + 1 933 classes.write("):\n") 934 writeDoc(name, args, ' ', classes) 935 936 for arg in args: 937 if classes_type.has_key(arg[1]): 938 classes.write(" if %s is None: %s__o = None\n" % 939 (arg[0], arg[0])) 940 classes.write(" else: %s__o = %s%s\n" % 941 (arg[0], arg[0], classes_type[arg[1]][0])) 942 if ret[0] != "void": 943 classes.write(" ret = ") 944 else: 945 classes.write(" ") 946 classes.write("libxml2mod.%s(" % name) 947 n = 0 948 for arg in args: 949 if n != 0: 950 classes.write(", ") 951 classes.write("%s" % arg[0]) 952 if classes_type.has_key(arg[1]): 953 classes.write("__o") 954 n = n + 1 955 classes.write(")\n") 956 if ret[0] != "void": 957 if classes_type.has_key(ret[0]): 958 # 959 # Raise an exception 960 # 961 if functions_noexcept.has_key(name): 962 classes.write(" if ret is None:return None\n") 963 elif string.find(name, "URI") >= 0: 964 classes.write( 965 " if ret is None:raise uriError('%s() failed')\n" 966 % (name)) 967 elif string.find(name, "XPath") >= 0: 968 classes.write( 969 " if ret is None:raise xpathError('%s() failed')\n" 970 % (name)) 971 elif string.find(name, "Parse") >= 0: 972 classes.write( 973 " if ret is None:raise parserError('%s() failed')\n" 974 % (name)) 975 else: 976 classes.write( 977 " if ret is None:raise treeError('%s() failed')\n" 978 % (name)) 979 classes.write(" return ") 980 classes.write(classes_type[ret[0]][1] % ("ret")) 981 classes.write("\n") 982 else: 983 classes.write(" return ret\n") 984 classes.write("\n") 985 986 txt.write("\n\n#\n# Set of classes of the module\n#\n\n") 987 for classname in classes_list: 988 if classname == "None": 989 pass 990 else: 991 if classes_ancestor.has_key(classname): 992 txt.write("\n\nClass %s(%s)\n" % (classname, 993 classes_ancestor[classname])) 994 classes.write("class %s(%s):\n" % (classname, 995 classes_ancestor[classname])) 996 classes.write(" def __init__(self, _obj=None):\n") 997 if classes_ancestor[classname] == "xmlCore" or \ 998 classes_ancestor[classname] == "xmlNode": 999 classes.write(" if type(_obj).__name__ != ") 1000 classes.write("'PyCObject':\n") 1001 classes.write(" raise TypeError, ") 1002 classes.write("'%s needs a PyCObject argument'\n" % \ 1003 classname) 1004 if reference_keepers.has_key(classname): 1005 rlist = reference_keepers[classname] 1006 for ref in rlist: 1007 classes.write(" self.%s = None\n" % ref[1]) 1008 classes.write(" self._o = _obj\n") 1009 classes.write(" %s.__init__(self, _obj=_obj)\n\n" % ( 1010 classes_ancestor[classname])) 1011 if classes_ancestor[classname] == "xmlCore" or \ 1012 classes_ancestor[classname] == "xmlNode": 1013 classes.write(" def __repr__(self):\n") 1014 format = "<%s (%%s) object at 0x%%x>" % (classname) 1015 classes.write(" return \"%s\" %% (self.name, long(pos_id (self)))\n\n" % ( 1016 format)) 1017 else: 1018 txt.write("Class %s()\n" % (classname)) 1019 classes.write("class %s:\n" % (classname)) 1020 classes.write(" def __init__(self, _obj=None):\n") 1021 if reference_keepers.has_key(classname): 1022 list = reference_keepers[classname] 1023 for ref in list: 1024 classes.write(" self.%s = None\n" % ref[1]) 1025 classes.write(" if _obj != None:self._o = _obj;return\n") 1026 classes.write(" self._o = None\n\n") 1027 destruct=None 1028 if classes_destructors.has_key(classname): 1029 classes.write(" def __del__(self):\n") 1030 classes.write(" if self._o != None:\n") 1031 classes.write(" libxml2mod.%s(self._o)\n" % 1032 classes_destructors[classname]) 1033 classes.write(" self._o = None\n\n") 1034 destruct=classes_destructors[classname] 1035 flist = function_classes[classname] 1036 flist.sort(functionCompare) 1037 oldfile = "" 1038 for info in flist: 1039 (index, func, name, ret, args, file) = info 1040 # 1041 # Do not provide as method the destructors for the class 1042 # to avoid double free 1043 # 1044 if name == destruct: 1045 continue 1046 if file != oldfile: 1047 if file == "python_accessor": 1048 classes.write(" # accessors for %s\n" % (classname)) 1049 txt.write(" # accessors\n") 1050 else: 1051 classes.write(" #\n") 1052 classes.write(" # %s functions from module %s\n" % ( 1053 classname, file)) 1054 txt.write("\n # functions from module %s\n" % file) 1055 classes.write(" #\n\n") 1056 oldfile = file 1057 classes.write(" def %s(self" % func) 1058 txt.write(" %s()\n" % func) 1059 n = 0 1060 for arg in args: 1061 if n != index: 1062 classes.write(", %s" % arg[0]) 1063 n = n + 1 1064 classes.write("):\n") 1065 writeDoc(name, args, ' ', classes) 1066 n = 0 1067 for arg in args: 1068 if classes_type.has_key(arg[1]): 1069 if n != index: 1070 classes.write(" if %s is None: %s__o = None\n" % 1071 (arg[0], arg[0])) 1072 classes.write(" else: %s__o = %s%s\n" % 1073 (arg[0], arg[0], classes_type[arg[1]][0])) 1074 n = n + 1 1075 if ret[0] != "void": 1076 classes.write(" ret = ") 1077 else: 1078 classes.write(" ") 1079 classes.write("libxml2mod.%s(" % name) 1080 n = 0 1081 for arg in args: 1082 if n != 0: 1083 classes.write(", ") 1084 if n != index: 1085 classes.write("%s" % arg[0]) 1086 if classes_type.has_key(arg[1]): 1087 classes.write("__o") 1088 else: 1089 classes.write("self") 1090 if classes_type.has_key(arg[1]): 1091 classes.write(classes_type[arg[1]][0]) 1092 n = n + 1 1093 classes.write(")\n") 1094 if ret[0] != "void": 1095 if classes_type.has_key(ret[0]): 1096 # 1097 # Raise an exception 1098 # 1099 if functions_noexcept.has_key(name): 1100 classes.write( 1101 " if ret is None:return None\n") 1102 elif string.find(name, "URI") >= 0: 1103 classes.write( 1104 " if ret is None:raise uriError('%s() failed')\n" 1105 % (name)) 1106 elif string.find(name, "XPath") >= 0: 1107 classes.write( 1108 " if ret is None:raise xpathError('%s() failed')\n" 1109 % (name)) 1110 elif string.find(name, "Parse") >= 0: 1111 classes.write( 1112 " if ret is None:raise parserError('%s() failed')\n" 1113 % (name)) 1114 else: 1115 classes.write( 1116 " if ret is None:raise treeError('%s() failed')\n" 1117 % (name)) 1118 1119 # 1120 # generate the returned class wrapper for the object 1121 # 1122 classes.write(" __tmp = ") 1123 classes.write(classes_type[ret[0]][1] % ("ret")) 1124 classes.write("\n") 1125 1126 # 1127 # Sometime one need to keep references of the source 1128 # class in the returned class object. 1129 # See reference_keepers for the list 1130 # 1131 tclass = classes_type[ret[0]][2] 1132 if reference_keepers.has_key(tclass): 1133 list = reference_keepers[tclass] 1134 for pref in list: 1135 if pref[0] == classname: 1136 classes.write(" __tmp.%s = self\n" % 1137 pref[1]) 1138 # 1139 # return the class 1140 # 1141 classes.write(" return __tmp\n") 1142 elif converter_type.has_key(ret[0]): 1143 # 1144 # Raise an exception 1145 # 1146 if functions_noexcept.has_key(name): 1147 classes.write( 1148 " if ret is None:return None") 1149 elif string.find(name, "URI") >= 0: 1150 classes.write( 1151 " if ret is None:raise uriError('%s() failed')\n" 1152 % (name)) 1153 elif string.find(name, "XPath") >= 0: 1154 classes.write( 1155 " if ret is None:raise xpathError('%s() failed')\n" 1156 % (name)) 1157 elif string.find(name, "Parse") >= 0: 1158 classes.write( 1159 " if ret is None:raise parserError('%s() failed')\n" 1160 % (name)) 1161 else: 1162 classes.write( 1163 " if ret is None:raise treeError('%s() failed')\n" 1164 % (name)) 1165 classes.write(" return ") 1166 classes.write(converter_type[ret[0]] % ("ret")) 1167 classes.write("\n") 1168 else: 1169 classes.write(" return ret\n") 1170 classes.write("\n") 1171 1172 # 1173 # Generate enum constants 1174 # 1175 for type,enum in enums.items(): 1176 classes.write("# %s\n" % type) 1177 items = enum.items() 1178 items.sort(lambda i1,i2: cmp(long(i1[1]),long(i2[1]))) 1179 for name,value in items: 1180 classes.write("%s = %s\n" % (name,value)) 1181 classes.write("\n") 1182 1183 txt.close() 1184 classes.close() 1185 1186buildStubs() 1187buildWrappers() 1188