Initial revision
[TestXSLT.git] / libxml2 / python / libxml.c
1 /*
2  * libxml.c: this modules implements the main part of the glue of the
3  *           libxml2 library and the Python interpreter. It provides the
4  *           entry points where an automatically generated stub is either
5  *           unpractical or would not match cleanly the Python model.
6  *
7  * If compiled with MERGED_MODULES, the entry point will be used to
8  * initialize both the libxml2 and the libxslt wrappers
9  *
10  * See Copyright for the status of this software.
11  *
12  * daniel@veillard.com
13  */
14 #include <Python.h>
15 #include <fileobject.h>
16 /* #include "config.h" */
17 #include <libxml/xmlmemory.h>
18 #include <libxml/parser.h>
19 #include <libxml/tree.h>
20 #include <libxml/xpath.h>
21 #include <libxml/xmlerror.h>
22 #include <libxml/xpathInternals.h>
23 #include <libxml/xmlmemory.h>
24 #include <libxml/xmlIO.h>
25 #include "libxml_wrap.h"
26 #include "libxml2-py.h"
27
28 #if (defined(_MSC_VER) || defined(__MINGW32__)) && !defined(vsnprintf)
29 #define vsnprintf(b,c,f,a) _vsnprintf(b,c,f,a)
30 #endif
31
32 /* #define DEBUG */
33 /* #define DEBUG_SAX */
34 /* #define DEBUG_XPATH */
35 /* #define DEBUG_ERROR */
36 /* #define DEBUG_MEMORY */
37 /* #define DEBUG_FILES */
38 /* #define DEBUG_LOADER */
39
40 void initlibxml2mod(void);
41
42 /**
43  * TODO:
44  *
45  * macro to flag unimplemented blocks
46  */
47 #define TODO                                                            \
48     xmlGenericError(xmlGenericErrorContext,                             \
49             "Unimplemented block at %s:%d\n",                           \
50             __FILE__, __LINE__);
51
52 /************************************************************************
53  *                                                                      *
54  *              Memory debug interface                                  *
55  *                                                                      *
56  ************************************************************************/
57
58 extern void xmlMemFree(void *ptr);
59 extern void *xmlMemMalloc(size_t size);
60 extern void *xmlMemRealloc(void *ptr, size_t size);
61 extern char *xmlMemoryStrdup(const char *str);
62
63 static int libxmlMemoryDebugActivated = 0;
64 static long libxmlMemoryAllocatedBase = 0;
65
66 static int libxmlMemoryDebug = 0;
67 static xmlFreeFunc freeFunc = NULL;
68 static xmlMallocFunc mallocFunc = NULL;
69 static xmlReallocFunc reallocFunc = NULL;
70 static xmlStrdupFunc strdupFunc = NULL;
71
72 PyObject *
73 libxml_xmlDebugMemory(ATTRIBUTE_UNUSED PyObject * self, PyObject * args)
74 {
75     int activate;
76     PyObject *py_retval;
77     long ret;
78
79     if (!PyArg_ParseTuple(args, (char *) "i:xmlDebugMemory", &activate))
80         return (NULL);
81
82 #ifdef DEBUG_MEMORY
83     printf("libxml_xmlDebugMemory(%d) called\n", activate);
84 #endif
85
86     if (activate != 0) {
87         if (libxmlMemoryDebug == 0) {
88             /*
89              * First initialize the library and grab the old memory handlers
90              * and switch the library to memory debugging
91              */
92             xmlMemGet((xmlFreeFunc *) & freeFunc,
93                       (xmlMallocFunc *) & mallocFunc,
94                       (xmlReallocFunc *) & reallocFunc,
95                       (xmlStrdupFunc *) & strdupFunc);
96             if ((freeFunc == xmlMemFree) && (mallocFunc == xmlMemMalloc) &&
97                 (reallocFunc == xmlMemRealloc) &&
98                 (strdupFunc == xmlMemoryStrdup)) {
99                 libxmlMemoryAllocatedBase = xmlMemUsed();
100             } else {
101                 ret = (long) xmlMemSetup(xmlMemFree, xmlMemMalloc,
102                                          xmlMemRealloc, xmlMemoryStrdup);
103                 if (ret < 0)
104                     goto error;
105                 libxmlMemoryAllocatedBase = xmlMemUsed();
106             }
107             xmlInitParser();
108             ret = 0;
109         } else if (libxmlMemoryDebugActivated == 0) {
110             libxmlMemoryAllocatedBase = xmlMemUsed();
111             ret = 0;
112         } else {
113             ret = xmlMemUsed() - libxmlMemoryAllocatedBase;
114         }
115         libxmlMemoryDebug = 1;
116         libxmlMemoryDebugActivated = 1;
117     } else {
118         if (libxmlMemoryDebugActivated == 1)
119             ret = xmlMemUsed() - libxmlMemoryAllocatedBase;
120         else
121             ret = 0;
122         libxmlMemoryDebugActivated = 0;
123     }
124   error:
125     py_retval = libxml_longWrap(ret);
126     return (py_retval);
127 }
128
129 PyObject *
130 libxml_xmlDumpMemory(ATTRIBUTE_UNUSED PyObject * self,
131                      ATTRIBUTE_UNUSED PyObject * args)
132 {
133
134     if (libxmlMemoryDebug != 0)
135         xmlMemoryDump();
136     Py_INCREF(Py_None);
137     return (Py_None);
138 }
139
140 /************************************************************************
141  *                                                                      *
142  *              Handling Python FILE I/O at the C level                 *
143  *      The raw I/O attack diectly the File objects, while the          *
144  *      other routines address the ioWrapper instance instead           *
145  *                                                                      *
146  ************************************************************************/
147
148 /**
149  * xmlPythonFileCloseUnref:
150  * @context:  the I/O context
151  *
152  * Close an I/O channel
153  */
154 static int
155 xmlPythonFileCloseRaw (void * context) {
156     PyObject *file, *ret;
157
158 #ifdef DEBUG_FILES
159     printf("xmlPythonFileCloseUnref\n");
160 #endif
161     file = (PyObject *) context;
162     if (file == NULL) return(-1);
163     ret = PyEval_CallMethod(file, (char *) "close", (char *) "()");
164     if (ret != NULL) {
165         Py_DECREF(ret);
166     }
167     Py_DECREF(file);
168     return(0);
169 }
170
171 /**
172  * xmlPythonFileReadRaw:
173  * @context:  the I/O context
174  * @buffer:  where to drop data
175  * @len:  number of bytes to write
176  *
177  * Read @len bytes to @buffer from the Python file in the I/O channel
178  *
179  * Returns the number of bytes read
180  */
181 static int
182 xmlPythonFileReadRaw (void * context, char * buffer, int len) {
183     PyObject *file;
184     PyObject *ret;
185     int lenread = -1;
186     char *data;
187
188 #ifdef DEBUG_FILES
189     printf("xmlPythonFileReadRaw: %d\n", len);
190 #endif
191     file = (PyObject *) context;
192     if (file == NULL) return(-1);
193     ret = PyEval_CallMethod(file, (char *) "read", (char *) "(i)", len);
194     if (ret == NULL) {
195         printf("xmlPythonFileReadRaw: result is NULL\n");
196         return(-1);
197     } else if (PyString_Check(ret)) {
198         lenread = PyString_Size(ret);
199         data = PyString_AsString(ret);
200         if (lenread > len)
201             memcpy(buffer, data, len);
202         else
203             memcpy(buffer, data, lenread);
204         Py_DECREF(ret);
205     } else {
206         printf("xmlPythonFileReadRaw: result is not a String\n");
207         Py_DECREF(ret);
208     }
209     return(lenread);
210 }
211
212 /**
213  * xmlPythonFileRead:
214  * @context:  the I/O context
215  * @buffer:  where to drop data
216  * @len:  number of bytes to write
217  *
218  * Read @len bytes to @buffer from the I/O channel.
219  *
220  * Returns the number of bytes read
221  */
222 static int
223 xmlPythonFileRead (void * context, char * buffer, int len) {
224     PyObject *file;
225     PyObject *ret;
226     int lenread = -1;
227     char *data;
228
229 #ifdef DEBUG_FILES
230     printf("xmlPythonFileRead: %d\n", len);
231 #endif
232     file = (PyObject *) context;
233     if (file == NULL) return(-1);
234     ret = PyEval_CallMethod(file, (char *) "io_read", (char *) "(i)", len);
235     if (ret == NULL) {
236         printf("xmlPythonFileRead: result is NULL\n");
237         return(-1);
238     } else if (PyString_Check(ret)) {
239         lenread = PyString_Size(ret);
240         data = PyString_AsString(ret);
241         if (lenread > len)
242             memcpy(buffer, data, len);
243         else
244             memcpy(buffer, data, lenread);
245         Py_DECREF(ret);
246     } else {
247         printf("xmlPythonFileRead: result is not a String\n");
248         Py_DECREF(ret);
249     }
250     return(lenread);
251 }
252
253 /**
254  * xmlFileWrite:
255  * @context:  the I/O context
256  * @buffer:  where to drop data
257  * @len:  number of bytes to write
258  *
259  * Write @len bytes from @buffer to the I/O channel.
260  *
261  * Returns the number of bytes written
262  */
263 static int
264 xmlPythonFileWrite (void * context, const char * buffer, int len) {
265     PyObject *file;
266     PyObject *string;
267     PyObject *ret;
268     int written = -1;
269
270 #ifdef DEBUG_FILES
271     printf("xmlPythonFileWrite: %d\n", len);
272 #endif
273     file = (PyObject *) context;
274     if (file == NULL) return(-1);
275     string = PyString_FromStringAndSize(buffer, len);
276     if (string == NULL) return(-1);
277     ret = PyEval_CallMethod(file, (char *) "io_write", (char *) "(O)", string);
278     Py_DECREF(string);
279     if (ret == NULL) {
280         printf("xmlPythonFileWrite: result is NULL\n");
281         return(-1);
282     } else if (PyInt_Check(ret)) {
283         written = (int) PyInt_AsLong(ret);
284         Py_DECREF(ret);
285     } else if (ret == Py_None) {
286         written = len;
287         Py_DECREF(ret);
288     } else {
289         printf("xmlPythonFileWrite: result is not an Int nor None\n");
290         Py_DECREF(ret);
291     }
292     return(written);
293 }
294
295 /**
296  * xmlPythonFileClose:
297  * @context:  the I/O context
298  *
299  * Close an I/O channel
300  */
301 static int
302 xmlPythonFileClose (void * context) {
303     PyObject *file, *ret;
304
305 #ifdef DEBUG_FILES
306     printf("xmlPythonFileClose\n");
307 #endif
308     file = (PyObject *) context;
309     if (file == NULL) return(-1);
310     ret = PyEval_CallMethod(file, (char *) "io_close", (char *) "()");
311     if (ret != NULL) {
312         Py_DECREF(ret);
313     }
314     return(0);
315 }
316
317 /**
318  * xmlOutputBufferCreatePythonFile:
319  * @file:  a PyFile_Type
320  * @encoder:  the encoding converter or NULL
321  *
322  * Create a buffered output for the progressive saving to a PyFile_Type
323  * buffered C I/O
324  *
325  * Returns the new parser output or NULL
326  */
327 static xmlOutputBufferPtr
328 xmlOutputBufferCreatePythonFile(PyObject *file, 
329                                 xmlCharEncodingHandlerPtr encoder) {
330     xmlOutputBufferPtr ret;
331
332     if (file == NULL) return(NULL);
333
334     ret = xmlAllocOutputBuffer(encoder);
335     if (ret != NULL) {
336         ret->context = file;
337         /* Py_INCREF(file); */
338         ret->writecallback = xmlPythonFileWrite;
339         ret->closecallback = xmlPythonFileClose;
340     }
341
342     return(ret);
343 }
344
345 PyObject *
346 libxml_xmlCreateOutputBuffer(ATTRIBUTE_UNUSED PyObject *self, PyObject *args) {
347     PyObject *py_retval;
348     PyObject *file;
349     xmlChar  *encoding;
350     xmlCharEncodingHandlerPtr handler = NULL;
351     xmlOutputBufferPtr buffer;
352
353
354     if (!PyArg_ParseTuple(args, (char *)"Oz:xmlOutputBufferCreate",
355                 &file, &encoding))
356         return(NULL);
357     if ((encoding != NULL) && (encoding[0] != 0)) {
358         handler = xmlFindCharEncodingHandler((const char *) encoding);
359     }
360     buffer = xmlOutputBufferCreatePythonFile(file, handler);
361     if (buffer == NULL)
362         printf("libxml_xmlCreateOutputBuffer: buffer == NULL\n");
363     py_retval = libxml_xmlOutputBufferPtrWrap(buffer);
364     return(py_retval);
365 }
366
367
368 /**
369  * xmlParserInputBufferCreatePythonFile:
370  * @file:  a PyFile_Type
371  * @encoder:  the encoding converter or NULL
372  *
373  * Create a buffered output for the progressive saving to a PyFile_Type
374  * buffered C I/O
375  *
376  * Returns the new parser output or NULL
377  */
378 static xmlParserInputBufferPtr
379 xmlParserInputBufferCreatePythonFile(PyObject *file, 
380                                 xmlCharEncoding encoding) {
381     xmlParserInputBufferPtr ret;
382
383     if (file == NULL) return(NULL);
384
385     ret = xmlAllocParserInputBuffer(encoding);
386     if (ret != NULL) {
387         ret->context = file;
388         /* Py_INCREF(file); */
389         ret->readcallback = xmlPythonFileRead;
390         ret->closecallback = xmlPythonFileClose;
391     }
392
393     return(ret);
394 }
395
396 PyObject *
397 libxml_xmlCreateInputBuffer(ATTRIBUTE_UNUSED PyObject *self, PyObject *args) {
398     PyObject *py_retval;
399     PyObject *file;
400     xmlChar  *encoding;
401     xmlCharEncoding enc = XML_CHAR_ENCODING_NONE;
402     xmlParserInputBufferPtr buffer;
403
404
405     if (!PyArg_ParseTuple(args, (char *)"Oz:xmlParserInputBufferCreate",
406                 &file, &encoding))
407         return(NULL);
408     if ((encoding != NULL) && (encoding[0] != 0)) {
409         enc = xmlParseCharEncoding((const char *) encoding);
410     }
411     buffer = xmlParserInputBufferCreatePythonFile(file, enc);
412     if (buffer == NULL)
413         printf("libxml_xmlParserInputBufferCreate: buffer == NULL\n");
414     py_retval = libxml_xmlParserInputBufferPtrWrap(buffer);
415     return(py_retval);
416 }
417
418 /************************************************************************
419  *                                                                      *
420  *              Providing the resolver at the Python level              *
421  *                                                                      *
422  ************************************************************************/
423
424 static xmlExternalEntityLoader defaultExternalEntityLoader = NULL;
425 static PyObject *pythonExternalEntityLoaderObjext;
426
427 static xmlParserInputPtr
428 pythonExternalEntityLoader(const char *URL, const char *ID,
429                            xmlParserCtxtPtr ctxt) {
430     xmlParserInputPtr result = NULL;
431     if (pythonExternalEntityLoaderObjext != NULL) {
432         PyObject *ret;
433         PyObject *ctxtobj;
434
435         ctxtobj = libxml_xmlParserCtxtPtrWrap(ctxt);
436 #ifdef DEBUG_LOADER
437         printf("pythonExternalEntityLoader: ready to call\n");
438 #endif
439
440         ret = PyObject_CallFunction(pythonExternalEntityLoaderObjext,
441                       (char *) "(ssO)", URL, ID, ctxtobj);
442         Py_XDECREF(ctxtobj);
443 #ifdef DEBUG_LOADER
444         printf("pythonExternalEntityLoader: result ");
445         PyObject_Print(ret, stdout, 0);
446         printf("\n");
447 #endif
448
449         if (ret != NULL) {
450             if (PyObject_HasAttrString(ret, (char *) "read")) {
451                 xmlParserInputBufferPtr buf;
452
453                 buf = xmlAllocParserInputBuffer(XML_CHAR_ENCODING_NONE);
454                 if (buf != NULL) {
455                     buf->context = ret;
456                     buf->readcallback = xmlPythonFileReadRaw;
457                     buf->closecallback = xmlPythonFileCloseRaw;
458                     result = xmlNewIOInputStream(ctxt, buf,
459                                                  XML_CHAR_ENCODING_NONE);
460                 }
461             } else {
462                 printf("pythonExternalEntityLoader: can't read\n");
463             }
464             if (result == NULL) {
465                 Py_DECREF(ret);
466             } else if (URL != NULL) {
467                 result->filename = xmlStrdup(URL);
468                 result->directory = xmlParserGetDirectory((const char *) URL);
469             }
470         }
471     }
472     if ((result == NULL) && (defaultExternalEntityLoader != NULL)) {
473         result = defaultExternalEntityLoader(URL, ID, ctxt);
474     }
475     return(result);
476 }
477
478 PyObject *
479 libxml_xmlSetEntityLoader(ATTRIBUTE_UNUSED PyObject *self, PyObject *args) {
480     PyObject *py_retval;
481     PyObject *loader;
482
483     if (!PyArg_ParseTuple(args, (char *)"O:libxml_xmlSetEntityLoader",
484                 &loader))
485         return(NULL);
486
487 #ifdef DEBUG_LOADER
488     printf("libxml_xmlSetEntityLoader\n");
489 #endif
490     if (defaultExternalEntityLoader == NULL) 
491         defaultExternalEntityLoader = xmlGetExternalEntityLoader();
492
493     pythonExternalEntityLoaderObjext = loader;
494     xmlSetExternalEntityLoader(pythonExternalEntityLoader);
495
496     py_retval = PyInt_FromLong(0);
497     return(py_retval);
498 }
499
500
501 /************************************************************************
502  *                                                                      *
503  *              Handling SAX/xmllib/sgmlop callback interfaces          *
504  *                                                                      *
505  ************************************************************************/
506
507 static void
508 pythonStartElement(void *user_data, const xmlChar * name,
509                    const xmlChar ** attrs)
510 {
511     int i;
512     PyObject *handler;
513     PyObject *dict;
514     PyObject *attrname;
515     PyObject *attrvalue;
516     PyObject *result = NULL;
517     int type = 0;
518
519 #ifdef DEBUG_SAX
520     printf("pythonStartElement(%s) called\n", name);
521 #endif
522     handler = (PyObject *) user_data;
523     if (PyObject_HasAttrString(handler, (char *) "startElement"))
524         type = 1;
525     else if (PyObject_HasAttrString(handler, (char *) "start"))
526         type = 2;
527     if (type != 0) {
528         /*
529          * the xmllib interface always generate a dictionnary,
530          * possibly empty
531          */
532         if ((attrs == NULL) && (type == 1)) {
533             Py_XINCREF(Py_None);
534             dict = Py_None;
535         } else if (attrs == NULL) {
536             dict = PyDict_New();
537         } else {
538             dict = PyDict_New();
539             for (i = 0; attrs[i] != NULL; i++) {
540                 attrname = PyString_FromString((char *) attrs[i]);
541                 i++;
542                 if (attrs[i] != NULL) {
543                     attrvalue = PyString_FromString((char *) attrs[i]);
544                 } else {
545                     Py_XINCREF(Py_None);
546                     attrvalue = Py_None;
547                 }
548                 PyDict_SetItem(dict, attrname, attrvalue);
549             }
550         }
551
552         if (type == 1)
553             result = PyObject_CallMethod(handler, (char *) "startElement",
554                                          (char *) "sO", name, dict);
555         else if (type == 2)
556             result = PyObject_CallMethod(handler, (char *) "start",
557                                          (char *) "sO", name, dict);
558         if (PyErr_Occurred())
559             PyErr_Print();
560         Py_XDECREF(dict);
561         Py_XDECREF(result);
562     }
563 }
564
565 static void
566 pythonStartDocument(void *user_data)
567 {
568     PyObject *handler;
569     PyObject *result;
570
571 #ifdef DEBUG_SAX
572     printf("pythonStartDocument() called\n");
573 #endif
574     handler = (PyObject *) user_data;
575     if (PyObject_HasAttrString(handler, (char *) "startDocument")) {
576         result =
577             PyObject_CallMethod(handler, (char *) "startDocument", NULL);
578         if (PyErr_Occurred())
579             PyErr_Print();
580         Py_XDECREF(result);
581     }
582 }
583
584 static void
585 pythonEndDocument(void *user_data)
586 {
587     PyObject *handler;
588     PyObject *result;
589
590 #ifdef DEBUG_SAX
591     printf("pythonEndDocument() called\n");
592 #endif
593     handler = (PyObject *) user_data;
594     if (PyObject_HasAttrString(handler, (char *) "endDocument")) {
595         result =
596             PyObject_CallMethod(handler, (char *) "endDocument", NULL);
597         if (PyErr_Occurred())
598             PyErr_Print();
599         Py_XDECREF(result);
600     }
601     /*
602      * The reference to the handler is released there
603      */
604     Py_XDECREF(handler);
605 }
606
607 static void
608 pythonEndElement(void *user_data, const xmlChar * name)
609 {
610     PyObject *handler;
611     PyObject *result;
612
613 #ifdef DEBUG_SAX
614     printf("pythonEndElement(%s) called\n", name);
615 #endif
616     handler = (PyObject *) user_data;
617     if (PyObject_HasAttrString(handler, (char *) "endElement")) {
618         result = PyObject_CallMethod(handler, (char *) "endElement",
619                                      (char *) "s", name);
620         if (PyErr_Occurred())
621             PyErr_Print();
622         Py_XDECREF(result);
623     } else if (PyObject_HasAttrString(handler, (char *) "end")) {
624         result = PyObject_CallMethod(handler, (char *) "end",
625                                      (char *) "s", name);
626         if (PyErr_Occurred())
627             PyErr_Print();
628         Py_XDECREF(result);
629     }
630 }
631
632 static void
633 pythonReference(void *user_data, const xmlChar * name)
634 {
635     PyObject *handler;
636     PyObject *result;
637
638 #ifdef DEBUG_SAX
639     printf("pythonReference(%s) called\n", name);
640 #endif
641     handler = (PyObject *) user_data;
642     if (PyObject_HasAttrString(handler, (char *) "reference")) {
643         result = PyObject_CallMethod(handler, (char *) "reference",
644                                      (char *) "s", name);
645         if (PyErr_Occurred())
646             PyErr_Print();
647         Py_XDECREF(result);
648     }
649 }
650
651 static void
652 pythonCharacters(void *user_data, const xmlChar * ch, int len)
653 {
654     PyObject *handler;
655     PyObject *result = NULL;
656     int type = 0;
657
658 #ifdef DEBUG_SAX
659     printf("pythonCharacters(%s, %d) called\n", ch, len);
660 #endif
661     handler = (PyObject *) user_data;
662     if (PyObject_HasAttrString(handler, (char *) "characters"))
663         type = 1;
664     else if (PyObject_HasAttrString(handler, (char *) "data"))
665         type = 2;
666     if (type != 0) {
667         if (type == 1)
668             result = PyObject_CallMethod(handler, (char *) "characters",
669                                          (char *) "s#", ch, len);
670         else if (type == 2)
671             result = PyObject_CallMethod(handler, (char *) "data",
672                                          (char *) "s#", ch, len);
673         if (PyErr_Occurred())
674             PyErr_Print();
675         Py_XDECREF(result);
676     }
677 }
678
679 static void
680 pythonIgnorableWhitespace(void *user_data, const xmlChar * ch, int len)
681 {
682     PyObject *handler;
683     PyObject *result = NULL;
684     int type = 0;
685
686 #ifdef DEBUG_SAX
687     printf("pythonIgnorableWhitespace(%s, %d) called\n", ch, len);
688 #endif
689     handler = (PyObject *) user_data;
690     if (PyObject_HasAttrString(handler, (char *) "ignorableWhitespace"))
691         type = 1;
692     else if (PyObject_HasAttrString(handler, (char *) "data"))
693         type = 2;
694     if (type != 0) {
695         if (type == 1)
696             result =
697                 PyObject_CallMethod(handler,
698                                     (char *) "ignorableWhitespace",
699                                     (char *) "s#", ch, len);
700         else if (type == 2)
701             result =
702                 PyObject_CallMethod(handler, (char *) "data",
703                                     (char *) "s#", ch, len);
704         Py_XDECREF(result);
705     }
706 }
707
708 static void
709 pythonProcessingInstruction(void *user_data,
710                             const xmlChar * target, const xmlChar * data)
711 {
712     PyObject *handler;
713     PyObject *result;
714
715 #ifdef DEBUG_SAX
716     printf("pythonProcessingInstruction(%s, %s) called\n", target, data);
717 #endif
718     handler = (PyObject *) user_data;
719     if (PyObject_HasAttrString(handler, (char *) "processingInstruction")) {
720         result = PyObject_CallMethod(handler, (char *)
721                                      "processingInstruction",
722                                      (char *) "ss", target, data);
723         Py_XDECREF(result);
724     }
725 }
726
727 static void
728 pythonComment(void *user_data, const xmlChar * value)
729 {
730     PyObject *handler;
731     PyObject *result;
732
733 #ifdef DEBUG_SAX
734     printf("pythonComment(%s) called\n", value);
735 #endif
736     handler = (PyObject *) user_data;
737     if (PyObject_HasAttrString(handler, (char *) "comment")) {
738         result =
739             PyObject_CallMethod(handler, (char *) "comment", (char *) "s",
740                                 value);
741         if (PyErr_Occurred())
742             PyErr_Print();
743         Py_XDECREF(result);
744     }
745 }
746
747 static void
748 pythonWarning(void *user_data, const char *msg, ...)
749 {
750     PyObject *handler;
751     PyObject *result;
752     va_list args;
753     char buf[1024];
754
755 #ifdef DEBUG_SAX
756     printf("pythonWarning(%s) called\n", msg);
757 #endif
758     handler = (PyObject *) user_data;
759     if (PyObject_HasAttrString(handler, (char *) "warning")) {
760         va_start(args, msg);
761         vsnprintf(buf, 1023, msg, args);
762         va_end(args);
763         buf[1023] = 0;
764         result =
765             PyObject_CallMethod(handler, (char *) "warning", (char *) "s",
766                                 buf);
767         if (PyErr_Occurred())
768             PyErr_Print();
769         Py_XDECREF(result);
770     }
771 }
772
773 static void
774 pythonError(void *user_data, const char *msg, ...)
775 {
776     PyObject *handler;
777     PyObject *result;
778     va_list args;
779     char buf[1024];
780
781 #ifdef DEBUG_SAX
782     printf("pythonError(%s) called\n", msg);
783 #endif
784     handler = (PyObject *) user_data;
785     if (PyObject_HasAttrString(handler, (char *) "error")) {
786         va_start(args, msg);
787         vsnprintf(buf, 1023, msg, args);
788         va_end(args);
789         buf[1023] = 0;
790         result =
791             PyObject_CallMethod(handler, (char *) "error", (char *) "s",
792                                 buf);
793         if (PyErr_Occurred())
794             PyErr_Print();
795         Py_XDECREF(result);
796     }
797 }
798
799 static void
800 pythonFatalError(void *user_data, const char *msg, ...)
801 {
802     PyObject *handler;
803     PyObject *result;
804     va_list args;
805     char buf[1024];
806
807 #ifdef DEBUG_SAX
808     printf("pythonFatalError(%s) called\n", msg);
809 #endif
810     handler = (PyObject *) user_data;
811     if (PyObject_HasAttrString(handler, (char *) "fatalError")) {
812         va_start(args, msg);
813         vsnprintf(buf, 1023, msg, args);
814         va_end(args);
815         buf[1023] = 0;
816         result =
817             PyObject_CallMethod(handler, (char *) "fatalError",
818                                 (char *) "s", buf);
819         if (PyErr_Occurred())
820             PyErr_Print();
821         Py_XDECREF(result);
822     }
823 }
824
825 static void
826 pythonCdataBlock(void *user_data, const xmlChar * ch, int len)
827 {
828     PyObject *handler;
829     PyObject *result = NULL;
830     int type = 0;
831
832 #ifdef DEBUG_SAX
833     printf("pythonCdataBlock(%s, %d) called\n", ch, len);
834 #endif
835     handler = (PyObject *) user_data;
836     if (PyObject_HasAttrString(handler, (char *) "cdataBlock"))
837         type = 1;
838     else if (PyObject_HasAttrString(handler, (char *) "cdata"))
839         type = 2;
840     if (type != 0) {
841         if (type == 1)
842             result =
843                 PyObject_CallMethod(handler, (char *) "cdataBlock",
844                                     (char *) "s#", ch, len);
845         else if (type == 2)
846             result =
847                 PyObject_CallMethod(handler, (char *) "cdata",
848                                     (char *) "s#", ch, len);
849         if (PyErr_Occurred())
850             PyErr_Print();
851         Py_XDECREF(result);
852     }
853 }
854
855 static void
856 pythonExternalSubset(void *user_data,
857                      const xmlChar * name,
858                      const xmlChar * externalID, const xmlChar * systemID)
859 {
860     PyObject *handler;
861     PyObject *result;
862
863 #ifdef DEBUG_SAX
864     printf("pythonExternalSubset(%s, %s, %s) called\n",
865            name, externalID, systemID);
866 #endif
867     handler = (PyObject *) user_data;
868     if (PyObject_HasAttrString(handler, (char *) "externalSubset")) {
869         result =
870             PyObject_CallMethod(handler, (char *) "externalSubset",
871                                 (char *) "sss", name, externalID,
872                                 systemID);
873         Py_XDECREF(result);
874     }
875 }
876
877 static void
878 pythonEntityDecl(void *user_data,
879                  const xmlChar * name,
880                  int type,
881                  const xmlChar * publicId,
882                  const xmlChar * systemId, xmlChar * content)
883 {
884     PyObject *handler;
885     PyObject *result;
886
887     handler = (PyObject *) user_data;
888     if (PyObject_HasAttrString(handler, (char *) "entityDecl")) {
889         result = PyObject_CallMethod(handler, (char *) "entityDecl",
890                                      (char *) "sisss", name, type,
891                                      publicId, systemId, content);
892         if (PyErr_Occurred())
893             PyErr_Print();
894         Py_XDECREF(result);
895     }
896 }
897
898
899
900 static void
901
902 pythonNotationDecl(void *user_data,
903                    const xmlChar * name,
904                    const xmlChar * publicId, const xmlChar * systemId)
905 {
906     PyObject *handler;
907     PyObject *result;
908
909     handler = (PyObject *) user_data;
910     if (PyObject_HasAttrString(handler, (char *) "notationDecl")) {
911         result = PyObject_CallMethod(handler, (char *) "notationDecl",
912                                      (char *) "sss", name, publicId,
913                                      systemId);
914         if (PyErr_Occurred())
915             PyErr_Print();
916         Py_XDECREF(result);
917     }
918 }
919
920 static void
921 pythonAttributeDecl(void *user_data,
922                     const xmlChar * elem,
923                     const xmlChar * name,
924                     int type,
925                     int def,
926                     const xmlChar * defaultValue, xmlEnumerationPtr tree)
927 {
928     PyObject *handler;
929     PyObject *nameList;
930     PyObject *newName;
931     xmlEnumerationPtr node;
932     PyObject *result;
933     int count;
934
935     handler = (PyObject *) user_data;
936     if (PyObject_HasAttrString(handler, (char *) "attributeDecl")) {
937         count = 0;
938         for (node = tree; node != NULL; node = node->next) {
939             count++;
940         }
941         nameList = PyList_New(count);
942         count = 0;
943         for (node = tree; node != NULL; node = node->next) {
944             newName = PyString_FromString((char *) node->name);
945             PyList_SetItem(nameList, count, newName);
946             count++;
947         }
948         result = PyObject_CallMethod(handler, (char *) "attributeDecl",
949                                      (char *) "ssiisO", elem, name, type,
950                                      def, defaultValue, nameList);
951         if (PyErr_Occurred())
952             PyErr_Print();
953         Py_XDECREF(nameList);
954         Py_XDECREF(result);
955     }
956 }
957
958 static void
959 pythonElementDecl(void *user_data,
960                   const xmlChar * name,
961                   int type, ATTRIBUTE_UNUSED xmlElementContentPtr content)
962 {
963     PyObject *handler;
964     PyObject *obj;
965     PyObject *result;
966
967     handler = (PyObject *) user_data;
968     if (PyObject_HasAttrString(handler, (char *) "elementDecl")) {
969         /* TODO: wrap in an elementContent object */
970         printf
971             ("pythonElementDecl: xmlElementContentPtr wrapper missing !\n");
972         obj = Py_None;
973         /* Py_XINCREF(Py_None); isn't the reference just borrowed ??? */
974         result = PyObject_CallMethod(handler, (char *) "elementDecl",
975                                      (char *) "siO", name, type, obj);
976         if (PyErr_Occurred())
977             PyErr_Print();
978         Py_XDECREF(result);
979     }
980 }
981
982 static void
983 pythonUnparsedEntityDecl(void *user_data,
984                          const xmlChar * name,
985                          const xmlChar * publicId,
986                          const xmlChar * systemId,
987                          const xmlChar * notationName)
988 {
989     PyObject *handler;
990     PyObject *result;
991
992     handler = (PyObject *) user_data;
993     if (PyObject_HasAttrString(handler, (char *) "unparsedEntityDecl")) {
994         result =
995             PyObject_CallMethod(handler, (char *) "unparsedEntityDecl",
996                                 (char *) "ssss", name, publicId, systemId,
997                                 notationName);
998         if (PyErr_Occurred())
999             PyErr_Print();
1000         Py_XDECREF(result);
1001     }
1002 }
1003
1004 static void
1005 pythonInternalSubset(void *user_data, const xmlChar * name,
1006                      const xmlChar * ExternalID, const xmlChar * SystemID)
1007 {
1008     PyObject *handler;
1009     PyObject *result;
1010
1011 #ifdef DEBUG_SAX
1012     printf("pythonInternalSubset(%s, %s, %s) called\n",
1013            name, ExternalID, SystemID);
1014 #endif
1015     handler = (PyObject *) user_data;
1016     if (PyObject_HasAttrString(handler, (char *) "internalSubset")) {
1017         result = PyObject_CallMethod(handler, (char *) "internalSubset",
1018                                      (char *) "sss", name, ExternalID,
1019                                      SystemID);
1020         if (PyErr_Occurred())
1021             PyErr_Print();
1022         Py_XDECREF(result);
1023     }
1024 }
1025
1026 static xmlSAXHandler pythonSaxHandler = {
1027     pythonInternalSubset,
1028     NULL,                       /* TODO pythonIsStandalone, */
1029     NULL,                       /* TODO pythonHasInternalSubset, */
1030     NULL,                       /* TODO pythonHasExternalSubset, */
1031     NULL,                       /* TODO pythonResolveEntity, */
1032     NULL,                       /* TODO pythonGetEntity, */
1033     pythonEntityDecl,
1034     pythonNotationDecl,
1035     pythonAttributeDecl,
1036     pythonElementDecl,
1037     pythonUnparsedEntityDecl,
1038     NULL,                       /* OBSOLETED pythonSetDocumentLocator, */
1039     pythonStartDocument,
1040     pythonEndDocument,
1041     pythonStartElement,
1042     pythonEndElement,
1043     pythonReference,
1044     pythonCharacters,
1045     pythonIgnorableWhitespace,
1046     pythonProcessingInstruction,
1047     pythonComment,
1048     pythonWarning,
1049     pythonError,
1050     pythonFatalError,
1051     NULL,                       /* TODO pythonGetParameterEntity, */
1052     pythonCdataBlock,
1053     pythonExternalSubset,
1054     1
1055 };
1056
1057 /************************************************************************
1058  *                                                                      *
1059  *              Handling of specific parser context                     *
1060  *                                                                      *
1061  ************************************************************************/
1062
1063 PyObject *
1064 libxml_xmlCreatePushParser(ATTRIBUTE_UNUSED PyObject * self,
1065                            PyObject * args)
1066 {
1067     const char *chunk;
1068     int size;
1069     const char *URI;
1070     PyObject *pyobj_SAX = NULL;
1071     xmlSAXHandlerPtr SAX = NULL;
1072     xmlParserCtxtPtr ret;
1073     PyObject *pyret;
1074
1075     if (!PyArg_ParseTuple
1076         (args, (char *) "Oziz:xmlCreatePushParser", &pyobj_SAX, &chunk,
1077          &size, &URI))
1078         return (NULL);
1079
1080 #ifdef DEBUG
1081     printf("libxml_xmlCreatePushParser(%p, %s, %d, %s) called\n",
1082            pyobj_SAX, chunk, size, URI);
1083 #endif
1084     if (pyobj_SAX != Py_None) {
1085         SAX = &pythonSaxHandler;
1086         Py_INCREF(pyobj_SAX);
1087         /* The reference is released in pythonEndDocument() */
1088     }
1089     ret = xmlCreatePushParserCtxt(SAX, pyobj_SAX, chunk, size, URI);
1090     pyret = libxml_xmlParserCtxtPtrWrap(ret);
1091     return (pyret);
1092 }
1093
1094 PyObject *
1095 libxml_htmlCreatePushParser(ATTRIBUTE_UNUSED PyObject * self,
1096                             PyObject * args)
1097 {
1098     const char *chunk;
1099     int size;
1100     const char *URI;
1101     PyObject *pyobj_SAX = NULL;
1102     xmlSAXHandlerPtr SAX = NULL;
1103     xmlParserCtxtPtr ret;
1104     PyObject *pyret;
1105
1106     if (!PyArg_ParseTuple
1107         (args, (char *) "Oziz:htmlCreatePushParser", &pyobj_SAX, &chunk,
1108          &size, &URI))
1109         return (NULL);
1110
1111 #ifdef DEBUG
1112     printf("libxml_htmlCreatePushParser(%p, %s, %d, %s) called\n",
1113            pyobj_SAX, chunk, size, URI);
1114 #endif
1115     if (pyobj_SAX != Py_None) {
1116         SAX = &pythonSaxHandler;
1117         Py_INCREF(pyobj_SAX);
1118         /* The reference is released in pythonEndDocument() */
1119     }
1120     ret = htmlCreatePushParserCtxt(SAX, pyobj_SAX, chunk, size, URI,
1121                                    XML_CHAR_ENCODING_NONE);
1122     pyret = libxml_xmlParserCtxtPtrWrap(ret);
1123     return (pyret);
1124 }
1125
1126 PyObject *
1127 libxml_xmlSAXParseFile(ATTRIBUTE_UNUSED PyObject * self, PyObject * args)
1128 {
1129     int recover;
1130     const char *URI;
1131     PyObject *pyobj_SAX = NULL;
1132     xmlSAXHandlerPtr SAX = NULL;
1133
1134     if (!PyArg_ParseTuple(args, (char *) "Osi:xmlSAXParseFile", &pyobj_SAX,
1135                           &URI, &recover))
1136         return (NULL);
1137
1138 #ifdef DEBUG
1139     printf("libxml_xmlSAXParseFile(%p, %s, %d) called\n",
1140            pyobj_SAX, URI, recover);
1141 #endif
1142     if (pyobj_SAX == Py_None) {
1143         Py_INCREF(Py_None);
1144         return (Py_None);
1145     }
1146     SAX = &pythonSaxHandler;
1147     Py_INCREF(pyobj_SAX);
1148     /* The reference is released in pythonEndDocument() */
1149     xmlSAXParseFileWithData(SAX, URI, recover, pyobj_SAX);
1150     Py_INCREF(Py_None);
1151     return (Py_None);
1152 }
1153
1154 PyObject *
1155 libxml_htmlSAXParseFile(ATTRIBUTE_UNUSED PyObject * self, PyObject * args)
1156 {
1157     const char *URI;
1158     const char *encoding;
1159     PyObject *pyobj_SAX = NULL;
1160     xmlSAXHandlerPtr SAX = NULL;
1161
1162     if (!PyArg_ParseTuple
1163         (args, (char *) "Osz:htmlSAXParseFile", &pyobj_SAX, &URI,
1164          &encoding))
1165         return (NULL);
1166
1167 #ifdef DEBUG
1168     printf("libxml_htmlSAXParseFile(%p, %s, %s) called\n",
1169            pyobj_SAX, URI, encoding);
1170 #endif
1171     if (pyobj_SAX == Py_None) {
1172         Py_INCREF(Py_None);
1173         return (Py_None);
1174     }
1175     SAX = &pythonSaxHandler;
1176     Py_INCREF(pyobj_SAX);
1177     /* The reference is released in pythonEndDocument() */
1178     htmlSAXParseFile(URI, encoding, SAX, pyobj_SAX);
1179     Py_INCREF(Py_None);
1180     return (Py_None);
1181 }
1182
1183 /************************************************************************
1184  *                                                                      *
1185  *                      Error message callback                          *
1186  *                                                                      *
1187  ************************************************************************/
1188
1189 static PyObject *libxml_xmlPythonErrorFuncHandler = NULL;
1190 static PyObject *libxml_xmlPythonErrorFuncCtxt = NULL;
1191
1192 /* helper to build a xmlMalloc'ed string from a format and va_list */
1193 static char *
1194 libxml_buildMessage(const char *msg, va_list ap)
1195 {
1196     int size;
1197     int chars;
1198     char *larger;
1199     char *str;
1200
1201     str = (char *) xmlMalloc(150);
1202     if (str == NULL)
1203         return NULL;
1204
1205     size = 150;
1206
1207     while (1) {
1208         chars = vsnprintf(str, size, msg, ap);
1209         if ((chars > -1) && (chars < size))
1210             break;
1211         if (chars > -1)
1212             size += chars + 1;
1213         else
1214             size += 100;
1215         if ((larger = (char *) xmlRealloc(str, size)) == NULL) {
1216             xmlFree(str);
1217             return NULL;
1218         }
1219         str = larger;
1220     }
1221
1222     return str;
1223 }
1224
1225 static void
1226 libxml_xmlErrorFuncHandler(ATTRIBUTE_UNUSED void *ctx, const char *msg,
1227                            ...)
1228 {
1229     va_list ap;
1230     char *str;
1231     PyObject *list;
1232     PyObject *message;
1233     PyObject *result;
1234
1235 #ifdef DEBUG_ERROR
1236     printf("libxml_xmlErrorFuncHandler(%p, %s, ...) called\n", ctx, msg);
1237 #endif
1238
1239
1240     if (libxml_xmlPythonErrorFuncHandler == NULL) {
1241         va_start(ap, msg);
1242         vfprintf(stdout, msg, ap);
1243         va_end(ap);
1244     } else {
1245         va_start(ap, msg);
1246         str = libxml_buildMessage(msg,ap);
1247         va_end(ap);
1248
1249         list = PyTuple_New(2);
1250         PyTuple_SetItem(list, 0, libxml_xmlPythonErrorFuncCtxt);
1251         Py_XINCREF(libxml_xmlPythonErrorFuncCtxt);
1252         message = libxml_charPtrWrap(str);
1253         PyTuple_SetItem(list, 1, message);
1254         result = PyEval_CallObject(libxml_xmlPythonErrorFuncHandler, list);
1255         Py_XDECREF(list);
1256         Py_XDECREF(result);
1257     }
1258 }
1259
1260 static void
1261 libxml_xmlErrorInitialize(void)
1262 {
1263 #ifdef DEBUG_ERROR
1264     printf("libxml_xmlErrorInitialize() called\n");
1265 #endif
1266     xmlSetGenericErrorFunc(NULL, libxml_xmlErrorFuncHandler);
1267 }
1268
1269 PyObject *
1270 libxml_xmlRegisterErrorHandler(ATTRIBUTE_UNUSED PyObject * self,
1271                                PyObject * args)
1272 {
1273     PyObject *py_retval;
1274     PyObject *pyobj_f;
1275     PyObject *pyobj_ctx;
1276
1277     if (!PyArg_ParseTuple
1278         (args, (char *) "OO:xmlRegisterErrorHandler", &pyobj_f,
1279          &pyobj_ctx))
1280         return (NULL);
1281
1282 #ifdef DEBUG_ERROR
1283     printf("libxml_registerXPathFunction(%p, %p) called\n", pyobj_ctx,
1284            pyobj_f);
1285 #endif
1286
1287     if (libxml_xmlPythonErrorFuncHandler != NULL) {
1288         Py_XDECREF(libxml_xmlPythonErrorFuncHandler);
1289     }
1290     if (libxml_xmlPythonErrorFuncCtxt != NULL) {
1291         Py_XDECREF(libxml_xmlPythonErrorFuncCtxt);
1292     }
1293
1294     Py_XINCREF(pyobj_ctx);
1295     Py_XINCREF(pyobj_f);
1296
1297     /* TODO: check f is a function ! */
1298     libxml_xmlPythonErrorFuncHandler = pyobj_f;
1299     libxml_xmlPythonErrorFuncCtxt = pyobj_ctx;
1300
1301     py_retval = libxml_intWrap(1);
1302     return (py_retval);
1303 }
1304
1305
1306 /************************************************************************
1307  *                                                                      *
1308  *                      Per parserCtxt error handler                    *
1309  *                                                                      *
1310  ************************************************************************/
1311
1312 typedef struct 
1313 {
1314     PyObject *f;
1315     PyObject *arg;
1316 } xmlParserCtxtPyCtxt;
1317 typedef xmlParserCtxtPyCtxt *xmlParserCtxtPyCtxtPtr;
1318
1319 static void
1320 libxml_xmlParserCtxtGenericErrorFuncHandler(void *ctx, int severity, char *str) 
1321 {
1322     PyObject *list;
1323     PyObject *result;
1324     xmlParserCtxtPtr ctxt;
1325     xmlParserCtxtPyCtxtPtr pyCtxt;
1326     
1327 #ifdef DEBUG_ERROR
1328     printf("libxml_xmlParserCtxtGenericErrorFuncHandler(%p, %s, ...) called\n", ctx, msg);
1329 #endif
1330
1331     ctxt = (xmlParserCtxtPtr)ctx;
1332     pyCtxt = (xmlParserCtxtPyCtxtPtr)ctxt->_private;
1333
1334     list = PyTuple_New(4);
1335     PyTuple_SetItem(list, 0, pyCtxt->arg);
1336     Py_XINCREF(pyCtxt->arg);
1337     PyTuple_SetItem(list, 1, libxml_charPtrWrap(str));
1338     PyTuple_SetItem(list, 2, libxml_intWrap(severity));
1339     PyTuple_SetItem(list, 3, Py_None);
1340     Py_INCREF(Py_None);
1341     result = PyEval_CallObject(pyCtxt->f, list);
1342     if (result == NULL) 
1343     {
1344         /* TODO: manage for the exception to be propagated... */
1345         PyErr_Print();
1346     }
1347     Py_XDECREF(list);
1348     Py_XDECREF(result);
1349 }
1350
1351 static void 
1352 libxml_xmlParserCtxtErrorFuncHandler(void *ctx, const char *msg, ...) 
1353 {
1354     va_list ap;
1355
1356     va_start(ap, msg);
1357     libxml_xmlParserCtxtGenericErrorFuncHandler(ctx,XML_PARSER_SEVERITY_ERROR,libxml_buildMessage(msg,ap));
1358     va_end(ap);
1359 }
1360
1361 static void 
1362 libxml_xmlParserCtxtWarningFuncHandler(void *ctx, const char *msg, ...) 
1363 {
1364     va_list ap;
1365
1366     va_start(ap, msg);
1367     libxml_xmlParserCtxtGenericErrorFuncHandler(ctx,XML_PARSER_SEVERITY_WARNING,libxml_buildMessage(msg,ap));
1368     va_end(ap);
1369 }
1370
1371 static void 
1372 libxml_xmlParserCtxtValidityErrorFuncHandler(void *ctx, const char *msg, ...) 
1373 {
1374     va_list ap;
1375
1376     va_start(ap, msg);
1377     libxml_xmlParserCtxtGenericErrorFuncHandler(ctx,XML_PARSER_SEVERITY_VALIDITY_ERROR,libxml_buildMessage(msg,ap));
1378     va_end(ap);
1379 }
1380
1381 static void 
1382 libxml_xmlParserCtxtValidityWarningFuncHandler(void *ctx, const char *msg, ...) 
1383 {
1384     va_list ap;
1385
1386     va_start(ap, msg);
1387     libxml_xmlParserCtxtGenericErrorFuncHandler(ctx,XML_PARSER_SEVERITY_VALIDITY_WARNING,libxml_buildMessage(msg,ap));
1388     va_end(ap);
1389 }
1390
1391 PyObject *
1392 libxml_xmlParserCtxtSetErrorHandler(ATTRIBUTE_UNUSED PyObject *self, PyObject *args) 
1393 {
1394     PyObject *py_retval;
1395     xmlParserCtxtPtr ctxt;
1396     xmlParserCtxtPyCtxtPtr pyCtxt;
1397     PyObject *pyobj_ctxt;
1398     PyObject *pyobj_f;
1399     PyObject *pyobj_arg;
1400
1401     if (!PyArg_ParseTuple(args, (char *)"OOO:xmlParserCtxtSetErrorHandler",
1402                           &pyobj_ctxt, &pyobj_f, &pyobj_arg))
1403         return(NULL);
1404     ctxt = (xmlParserCtxtPtr) PyparserCtxt_Get(pyobj_ctxt);
1405     if (ctxt->_private == NULL) {
1406         pyCtxt = xmlMalloc(sizeof(xmlParserCtxtPyCtxt));
1407         if (pyCtxt == NULL) {
1408             py_retval = libxml_intWrap(-1);
1409             return(py_retval);
1410         }
1411         memset(pyCtxt,0,sizeof(xmlParserCtxtPyCtxt));
1412         ctxt->_private = pyCtxt;
1413     }
1414     else {
1415         pyCtxt = (xmlParserCtxtPyCtxtPtr)ctxt->_private;
1416     }
1417     /* TODO: check f is a function ! */
1418     Py_XDECREF(pyCtxt->f);
1419     Py_XINCREF(pyobj_f);
1420     pyCtxt->f = pyobj_f;
1421     Py_XDECREF(pyCtxt->arg);
1422     Py_XINCREF(pyobj_arg);
1423     pyCtxt->arg = pyobj_arg;
1424
1425     if (pyobj_f != Py_None) {
1426         ctxt->sax->error = libxml_xmlParserCtxtErrorFuncHandler;
1427         ctxt->sax->warning = libxml_xmlParserCtxtWarningFuncHandler;
1428         ctxt->vctxt.error = libxml_xmlParserCtxtValidityErrorFuncHandler;
1429         ctxt->vctxt.warning = libxml_xmlParserCtxtValidityWarningFuncHandler;
1430     }
1431     else {
1432         ctxt->sax->error = xmlParserError;
1433         ctxt->vctxt.error = xmlParserValidityError;
1434         ctxt->sax->warning = xmlParserWarning;
1435         ctxt->vctxt.warning = xmlParserValidityWarning;
1436     }
1437
1438     py_retval = libxml_intWrap(1);
1439     return(py_retval);
1440 }
1441
1442 PyObject *
1443 libxml_xmlParserCtxtGetErrorHandler(ATTRIBUTE_UNUSED PyObject *self, PyObject *args) 
1444 {
1445     PyObject *py_retval;
1446     xmlParserCtxtPtr ctxt;
1447     xmlParserCtxtPyCtxtPtr pyCtxt;
1448     PyObject *pyobj_ctxt;
1449
1450     if (!PyArg_ParseTuple(args, (char *)"O:xmlParserCtxtGetErrorHandler",
1451                           &pyobj_ctxt))
1452         return(NULL);
1453     ctxt = (xmlParserCtxtPtr) PyparserCtxt_Get(pyobj_ctxt);
1454     py_retval = PyTuple_New(2);
1455     if (ctxt->_private != NULL) {
1456         pyCtxt = (xmlParserCtxtPyCtxtPtr)ctxt->_private;
1457
1458         PyTuple_SetItem(py_retval, 0, pyCtxt->f);
1459         Py_XINCREF(pyCtxt->f);
1460         PyTuple_SetItem(py_retval, 1, pyCtxt->arg);
1461         Py_XINCREF(pyCtxt->arg);
1462     }
1463     else {
1464         /* no python error handler registered */
1465         PyTuple_SetItem(py_retval, 0, Py_None);
1466         Py_XINCREF(Py_None);
1467         PyTuple_SetItem(py_retval, 1, Py_None);
1468         Py_XINCREF(Py_None);
1469     }
1470     return(py_retval);
1471 }
1472
1473 PyObject *
1474 libxml_xmlFreeParserCtxt(ATTRIBUTE_UNUSED PyObject *self, PyObject *args) {
1475     xmlParserCtxtPtr ctxt;
1476     PyObject *pyobj_ctxt;
1477     xmlParserCtxtPyCtxtPtr pyCtxt;
1478
1479     if (!PyArg_ParseTuple(args, (char *)"O:xmlFreeParserCtxt", &pyobj_ctxt))
1480         return(NULL);
1481     ctxt = (xmlParserCtxtPtr) PyparserCtxt_Get(pyobj_ctxt);
1482
1483     if (ctxt != NULL) {
1484         pyCtxt = (xmlParserCtxtPyCtxtPtr)((xmlParserCtxtPtr)ctxt)->_private;
1485         if (pyCtxt) {
1486             Py_XDECREF(pyCtxt->f);
1487             Py_XDECREF(pyCtxt->arg);
1488             xmlFree(pyCtxt);
1489         }
1490         xmlFreeParserCtxt(ctxt);
1491     }
1492
1493     Py_INCREF(Py_None);
1494     return(Py_None);
1495 }
1496
1497 /************************************************************************
1498  *                                                                      *
1499  *                      Per xmlTextReader error handler                 *
1500  *                                                                      *
1501  ************************************************************************/
1502
1503 typedef struct 
1504 {
1505     PyObject *f;
1506     PyObject *arg;
1507 } xmlTextReaderPyCtxt;
1508 typedef xmlTextReaderPyCtxt *xmlTextReaderPyCtxtPtr;
1509
1510 static void 
1511 libxml_xmlTextReaderErrorCallback(void *arg, 
1512                                   const char *msg,
1513                                   int severity,
1514                                   xmlTextReaderLocatorPtr locator)
1515 {
1516     xmlTextReaderPyCtxt *pyCtxt = (xmlTextReaderPyCtxt *)arg;
1517     PyObject *list;
1518     PyObject *result;
1519     
1520     list = PyTuple_New(4);
1521     PyTuple_SetItem(list, 0, pyCtxt->arg);
1522     Py_XINCREF(pyCtxt->arg);
1523     PyTuple_SetItem(list, 1, libxml_charPtrConstWrap(msg));
1524     PyTuple_SetItem(list, 2, libxml_intWrap(severity));
1525     PyTuple_SetItem(list, 3, libxml_xmlTextReaderLocatorPtrWrap(locator));
1526     result = PyEval_CallObject(pyCtxt->f, list);
1527     if (result == NULL)
1528     {
1529         /* TODO: manage for the exception to be propagated... */
1530         PyErr_Print();
1531     }
1532     Py_XDECREF(list);
1533     Py_XDECREF(result);
1534 }
1535
1536 PyObject *
1537 libxml_xmlTextReaderSetErrorHandler(ATTRIBUTE_UNUSED PyObject *self, PyObject *args)
1538 {
1539     xmlTextReaderPtr reader;
1540     xmlTextReaderPyCtxtPtr pyCtxt;
1541     xmlTextReaderErrorFunc f;
1542     void *arg;
1543     PyObject *pyobj_reader;
1544     PyObject *pyobj_f;
1545     PyObject *pyobj_arg;
1546     PyObject *py_retval;
1547
1548     if (!PyArg_ParseTuple(args, (char *)"OOO:xmlTextReaderSetErrorHandler", &pyobj_reader, &pyobj_f, &pyobj_arg))
1549         return(NULL);
1550     reader = (xmlTextReaderPtr) PyxmlTextReader_Get(pyobj_reader);
1551     /* clear previous error handler */
1552     xmlTextReaderGetErrorHandler(reader,&f,&arg);
1553     if (arg != NULL) {
1554         if (f == libxml_xmlTextReaderErrorCallback) {
1555             /* ok, it's our error handler! */
1556             pyCtxt = (xmlTextReaderPyCtxtPtr)arg;
1557             Py_XDECREF(pyCtxt->f);
1558             Py_XDECREF(pyCtxt->arg);
1559             xmlFree(pyCtxt);
1560         }
1561         else {
1562             /* 
1563              * there already an arg, and it's not ours,
1564              * there is definitely something wrong going on here...
1565              * we don't know how to free it, so we bail out... 
1566              */
1567             py_retval = libxml_intWrap(-1);
1568             return(py_retval);
1569         }
1570     }
1571     xmlTextReaderSetErrorHandler(reader,NULL,NULL);
1572     /* set new error handler */
1573     if (pyobj_f != Py_None)
1574     {
1575         pyCtxt = (xmlTextReaderPyCtxtPtr)xmlMalloc(sizeof(xmlTextReaderPyCtxt));
1576         if (pyCtxt == NULL) {
1577             py_retval = libxml_intWrap(-1);
1578             return(py_retval);
1579         }
1580         Py_XINCREF(pyobj_f);
1581         pyCtxt->f = pyobj_f;
1582         Py_XINCREF(pyobj_arg);
1583         pyCtxt->arg = pyobj_arg;
1584         xmlTextReaderSetErrorHandler(reader,libxml_xmlTextReaderErrorCallback,pyCtxt);
1585     }
1586
1587     py_retval = libxml_intWrap(1);
1588     return(py_retval);
1589 }
1590
1591 PyObject *
1592 libxml_xmlTextReaderGetErrorHandler(ATTRIBUTE_UNUSED PyObject *self, PyObject *args)
1593 {
1594     xmlTextReaderPtr reader;
1595     xmlTextReaderPyCtxtPtr pyCtxt;
1596     xmlTextReaderErrorFunc f;
1597     void *arg;
1598     PyObject *pyobj_reader;
1599     PyObject *py_retval;
1600
1601     if (!PyArg_ParseTuple(args, (char *)"O:xmlTextReaderSetErrorHandler", &pyobj_reader))
1602         return(NULL);
1603     reader = (xmlTextReaderPtr) PyxmlTextReader_Get(pyobj_reader);
1604     xmlTextReaderGetErrorHandler(reader,&f,&arg);
1605     py_retval = PyTuple_New(2);
1606     if (f == libxml_xmlTextReaderErrorCallback) {
1607         /* ok, it's our error handler! */
1608         pyCtxt = (xmlTextReaderPyCtxtPtr)arg;
1609         PyTuple_SetItem(py_retval, 0, pyCtxt->f);
1610         Py_XINCREF(pyCtxt->f);
1611         PyTuple_SetItem(py_retval, 1, pyCtxt->arg);
1612         Py_XINCREF(pyCtxt->arg);
1613     }
1614     else
1615     {
1616         /* f is null or it's not our error handler */
1617         PyTuple_SetItem(py_retval, 0, Py_None);
1618         Py_XINCREF(Py_None);
1619         PyTuple_SetItem(py_retval, 1, Py_None);
1620         Py_XINCREF(Py_None);
1621     }
1622     return(py_retval);
1623 }
1624
1625 PyObject *
1626 libxml_xmlFreeTextReader(ATTRIBUTE_UNUSED PyObject *self, PyObject *args) {
1627     xmlTextReaderPtr reader;
1628     PyObject *pyobj_reader;
1629     xmlTextReaderPyCtxtPtr pyCtxt;
1630     xmlTextReaderErrorFunc f;
1631     void *arg;
1632
1633     if (!PyArg_ParseTuple(args, (char *)"O:xmlFreeTextReader", &pyobj_reader))
1634         return(NULL);
1635     reader = (xmlTextReaderPtr) PyxmlTextReader_Get(pyobj_reader);
1636
1637     xmlTextReaderGetErrorHandler(reader,&f,&arg);
1638     if (arg != NULL) {
1639         if (f == libxml_xmlTextReaderErrorCallback) {
1640             /* ok, it's our error handler! */
1641             pyCtxt = (xmlTextReaderPyCtxtPtr)arg;
1642             Py_XDECREF(pyCtxt->f);
1643             Py_XDECREF(pyCtxt->arg);
1644             xmlFree(pyCtxt);
1645         }
1646         /* 
1647          * else, something wrong happened, because the error handler is
1648          * not owned by the python bindings...
1649          */
1650     }
1651
1652     xmlFreeTextReader(reader);
1653     Py_INCREF(Py_None);
1654     return(Py_None);
1655 }
1656
1657 /************************************************************************
1658  *                                                                      *
1659  *                      XPath extensions                                *
1660  *                                                                      *
1661  ************************************************************************/
1662
1663 static int libxml_xpathCallbacksInitialized = 0;
1664
1665 typedef struct libxml_xpathCallback {
1666     xmlXPathContextPtr ctx;
1667     xmlChar *name;
1668     xmlChar *ns_uri;
1669     PyObject *function;
1670 } libxml_xpathCallback, *libxml_xpathCallbackPtr;
1671 static libxml_xpathCallback libxml_xpathCallbacks[10];
1672 static int libxml_xpathCallbacksNb = 0;
1673 static int libxml_xpathCallbacksMax = 10;
1674
1675 static void
1676 libxml_xmlXPathFuncCallback(xmlXPathParserContextPtr ctxt, int nargs)
1677 {
1678     PyObject *list, *cur, *result;
1679     xmlXPathObjectPtr obj;
1680     xmlXPathContextPtr rctxt;
1681     PyObject *current_function = NULL;
1682     const xmlChar *name;
1683     const xmlChar *ns_uri;
1684     int i;
1685
1686     if (ctxt == NULL)
1687         return;
1688     rctxt = ctxt->context;
1689     if (rctxt == NULL)
1690         return;
1691     name = rctxt->function;
1692     ns_uri = rctxt->functionURI;
1693 #ifdef DEBUG_XPATH
1694     printf("libxml_xmlXPathFuncCallback called name %s URI %s\n", name,
1695            ns_uri);
1696 #endif
1697
1698     /*
1699      * Find the function, it should be there it was there at lookup
1700      */
1701     for (i = 0; i < libxml_xpathCallbacksNb; i++) {
1702         if (                    /* TODO (ctxt == libxml_xpathCallbacks[i].ctx) && */
1703                (xmlStrEqual(name, libxml_xpathCallbacks[i].name)) &&
1704                (xmlStrEqual(ns_uri, libxml_xpathCallbacks[i].ns_uri))) {
1705             current_function = libxml_xpathCallbacks[i].function;
1706         }
1707     }
1708     if (current_function == NULL) {
1709         printf
1710             ("libxml_xmlXPathFuncCallback: internal error %s not found !\n",
1711              name);
1712         return;
1713     }
1714
1715     list = PyTuple_New(nargs + 1);
1716     PyTuple_SetItem(list, 0, libxml_xmlXPathParserContextPtrWrap(ctxt));
1717     for (i = 0; i < nargs; i++) {
1718         obj = valuePop(ctxt);
1719         cur = libxml_xmlXPathObjectPtrWrap(obj);
1720         PyTuple_SetItem(list, i + 1, cur);
1721     }
1722     result = PyEval_CallObject(current_function, list);
1723     Py_DECREF(list);
1724
1725     obj = libxml_xmlXPathObjectPtrConvert(result);
1726     valuePush(ctxt, obj);
1727 }
1728
1729 static xmlXPathFunction
1730 libxml_xmlXPathFuncLookupFunc(void *ctxt, const xmlChar * name,
1731                               const xmlChar * ns_uri)
1732 {
1733     int i;
1734
1735 #ifdef DEBUG_XPATH
1736     printf("libxml_xmlXPathFuncLookupFunc(%p, %s, %s) called\n",
1737            ctxt, name, ns_uri);
1738 #endif
1739     /*
1740      * This is called once only. The address is then stored in the
1741      * XPath expression evaluation, the proper object to call can
1742      * then still be found using the execution context function
1743      * and functionURI fields.
1744      */
1745     for (i = 0; i < libxml_xpathCallbacksNb; i++) {
1746         if ((ctxt == libxml_xpathCallbacks[i].ctx) &&
1747             (xmlStrEqual(name, libxml_xpathCallbacks[i].name)) &&
1748             (xmlStrEqual(ns_uri, libxml_xpathCallbacks[i].ns_uri))) {
1749             return (libxml_xmlXPathFuncCallback);
1750         }
1751     }
1752     return (NULL);
1753 }
1754
1755 static void
1756 libxml_xpathCallbacksInitialize(void)
1757 {
1758     int i;
1759
1760     if (libxml_xpathCallbacksInitialized != 0)
1761         return;
1762
1763 #ifdef DEBUG_XPATH
1764     printf("libxml_xpathCallbacksInitialized called\n");
1765 #endif
1766
1767     for (i = 0; i < 10; i++) {
1768         libxml_xpathCallbacks[i].ctx = NULL;
1769         libxml_xpathCallbacks[i].name = NULL;
1770         libxml_xpathCallbacks[i].ns_uri = NULL;
1771         libxml_xpathCallbacks[i].function = NULL;
1772     }
1773     libxml_xpathCallbacksInitialized = 1;
1774 }
1775
1776 PyObject *
1777 libxml_xmlRegisterXPathFunction(ATTRIBUTE_UNUSED PyObject * self,
1778                                 PyObject * args)
1779 {
1780     PyObject *py_retval;
1781     int c_retval = 0;
1782     xmlChar *name;
1783     xmlChar *ns_uri;
1784     xmlXPathContextPtr ctx;
1785     PyObject *pyobj_ctx;
1786     PyObject *pyobj_f;
1787     int i;
1788
1789     if (!PyArg_ParseTuple
1790         (args, (char *) "OszO:registerXPathFunction", &pyobj_ctx, &name,
1791          &ns_uri, &pyobj_f))
1792         return (NULL);
1793
1794     ctx = (xmlXPathContextPtr) PyxmlXPathContext_Get(pyobj_ctx);
1795     if (libxml_xpathCallbacksInitialized == 0)
1796         libxml_xpathCallbacksInitialize();
1797     xmlXPathRegisterFuncLookup(ctx, libxml_xmlXPathFuncLookupFunc, ctx);
1798
1799     if ((pyobj_ctx == NULL) || (name == NULL) || (pyobj_f == NULL)) {
1800         py_retval = libxml_intWrap(-1);
1801         return (py_retval);
1802     }
1803 #ifdef DEBUG_XPATH
1804     printf("libxml_registerXPathFunction(%p, %s, %s) called\n",
1805            ctx, name, ns_uri);
1806 #endif
1807     for (i = 0; i < libxml_xpathCallbacksNb; i++) {
1808         if ((ctx == libxml_xpathCallbacks[i].ctx) &&
1809             (xmlStrEqual(name, libxml_xpathCallbacks[i].name)) &&
1810             (xmlStrEqual(ns_uri, libxml_xpathCallbacks[i].ns_uri))) {
1811             Py_XINCREF(pyobj_f);
1812             Py_XDECREF(libxml_xpathCallbacks[i].function);
1813             libxml_xpathCallbacks[i].function = pyobj_f;
1814             c_retval = 1;
1815             goto done;
1816         }
1817     }
1818     if (libxml_xpathCallbacksNb >= libxml_xpathCallbacksMax) {
1819         printf("libxml_registerXPathFunction() table full\n");
1820     } else {
1821         i = libxml_xpathCallbacksNb++;
1822         Py_XINCREF(pyobj_f);
1823         libxml_xpathCallbacks[i].ctx = ctx;
1824         libxml_xpathCallbacks[i].name = xmlStrdup(name);
1825         libxml_xpathCallbacks[i].ns_uri = xmlStrdup(ns_uri);
1826         libxml_xpathCallbacks[i].function = pyobj_f;
1827         c_retval = 1;
1828     }
1829   done:
1830     py_retval = libxml_intWrap((int) c_retval);
1831     return (py_retval);
1832 }
1833
1834 /************************************************************************
1835  *                                                                      *
1836  *                      Global properties access                        *
1837  *                                                                      *
1838  ************************************************************************/
1839 static PyObject *
1840 libxml_name(ATTRIBUTE_UNUSED PyObject * self, PyObject * args)
1841 {
1842     PyObject *resultobj, *obj;
1843     xmlNodePtr cur;
1844     const xmlChar *res;
1845
1846     if (!PyArg_ParseTuple(args, (char *) "O:name", &obj))
1847         return NULL;
1848     cur = PyxmlNode_Get(obj);
1849
1850 #ifdef DEBUG
1851     printf("libxml_name: cur = %p type %d\n", cur, cur->type);
1852 #endif
1853
1854     switch (cur->type) {
1855         case XML_DOCUMENT_NODE:
1856 #ifdef LIBXML_DOCB_ENABLED
1857         case XML_DOCB_DOCUMENT_NODE:
1858 #endif
1859         case XML_HTML_DOCUMENT_NODE:{
1860                 xmlDocPtr doc = (xmlDocPtr) cur;
1861
1862                 res = doc->URL;
1863                 break;
1864             }
1865         case XML_ATTRIBUTE_NODE:{
1866                 xmlAttrPtr attr = (xmlAttrPtr) cur;
1867
1868                 res = attr->name;
1869                 break;
1870             }
1871         case XML_NAMESPACE_DECL:{
1872                 xmlNsPtr ns = (xmlNsPtr) cur;
1873
1874                 res = ns->prefix;
1875                 break;
1876             }
1877         default:
1878             res = cur->name;
1879             break;
1880     }
1881     resultobj = libxml_constxmlCharPtrWrap(res);
1882
1883     return resultobj;
1884 }
1885
1886 static PyObject *
1887 libxml_doc(ATTRIBUTE_UNUSED PyObject * self, PyObject * args)
1888 {
1889     PyObject *resultobj, *obj;
1890     xmlNodePtr cur;
1891     xmlDocPtr res;
1892
1893     if (!PyArg_ParseTuple(args, (char *) "O:doc", &obj))
1894         return NULL;
1895     cur = PyxmlNode_Get(obj);
1896
1897 #ifdef DEBUG
1898     printf("libxml_doc: cur = %p\n", cur);
1899 #endif
1900
1901     switch (cur->type) {
1902         case XML_DOCUMENT_NODE:
1903 #ifdef LIBXML_DOCB_ENABLED
1904         case XML_DOCB_DOCUMENT_NODE:
1905 #endif
1906         case XML_HTML_DOCUMENT_NODE:
1907             res = NULL;
1908             break;
1909         case XML_ATTRIBUTE_NODE:{
1910                 xmlAttrPtr attr = (xmlAttrPtr) cur;
1911
1912                 res = attr->doc;
1913                 break;
1914             }
1915         case XML_NAMESPACE_DECL:
1916             res = NULL;
1917             break;
1918         default:
1919             res = cur->doc;
1920             break;
1921     }
1922     resultobj = libxml_xmlDocPtrWrap(res);
1923     return resultobj;
1924 }
1925
1926 static PyObject *
1927 libxml_properties(ATTRIBUTE_UNUSED PyObject * self, PyObject * args)
1928 {
1929     PyObject *resultobj, *obj;
1930     xmlNodePtr cur = NULL;
1931     xmlAttrPtr res;
1932
1933     if (!PyArg_ParseTuple(args, (char *) "O:properties", &obj))
1934         return NULL;
1935     cur = PyxmlNode_Get(obj);
1936     if (cur->type == XML_ELEMENT_NODE)
1937         res = cur->properties;
1938     else
1939         res = NULL;
1940     resultobj = libxml_xmlAttrPtrWrap(res);
1941     return resultobj;
1942 }
1943
1944 static PyObject *
1945 libxml_next(ATTRIBUTE_UNUSED PyObject * self, PyObject * args)
1946 {
1947     PyObject *resultobj, *obj;
1948     xmlNodePtr cur;
1949     xmlNodePtr res;
1950
1951     if (!PyArg_ParseTuple(args, (char *) "O:next", &obj))
1952         return NULL;
1953     cur = PyxmlNode_Get(obj);
1954
1955 #ifdef DEBUG
1956     printf("libxml_next: cur = %p\n", cur);
1957 #endif
1958
1959     switch (cur->type) {
1960         case XML_DOCUMENT_NODE:
1961 #ifdef LIBXML_DOCB_ENABLED
1962         case XML_DOCB_DOCUMENT_NODE:
1963 #endif
1964         case XML_HTML_DOCUMENT_NODE:
1965             res = NULL;
1966             break;
1967         case XML_ATTRIBUTE_NODE:{
1968                 xmlAttrPtr attr = (xmlAttrPtr) cur;
1969
1970                 res = (xmlNodePtr) attr->next;
1971                 break;
1972             }
1973         case XML_NAMESPACE_DECL:{
1974                 xmlNsPtr ns = (xmlNsPtr) cur;
1975
1976                 res = (xmlNodePtr) ns->next;
1977                 break;
1978             }
1979         default:
1980             res = cur->next;
1981             break;
1982
1983     }
1984     resultobj = libxml_xmlNodePtrWrap(res);
1985     return resultobj;
1986 }
1987
1988 static PyObject *
1989 libxml_prev(ATTRIBUTE_UNUSED PyObject * self, PyObject * args)
1990 {
1991     PyObject *resultobj, *obj;
1992     xmlNodePtr cur;
1993     xmlNodePtr res;
1994
1995     if (!PyArg_ParseTuple(args, (char *) "O:prev", &obj))
1996         return NULL;
1997     cur = PyxmlNode_Get(obj);
1998
1999 #ifdef DEBUG
2000     printf("libxml_prev: cur = %p\n", cur);
2001 #endif
2002
2003     switch (cur->type) {
2004         case XML_DOCUMENT_NODE:
2005 #ifdef LIBXML_DOCB_ENABLED
2006         case XML_DOCB_DOCUMENT_NODE:
2007 #endif
2008         case XML_HTML_DOCUMENT_NODE:
2009             res = NULL;
2010             break;
2011         case XML_ATTRIBUTE_NODE:{
2012                 xmlAttrPtr attr = (xmlAttrPtr) cur;
2013
2014                 res = (xmlNodePtr) attr->prev;
2015             }
2016         case XML_NAMESPACE_DECL:
2017             res = NULL;
2018             break;
2019         default:
2020             res = cur->prev;
2021             break;
2022     }
2023     resultobj = libxml_xmlNodePtrWrap(res);
2024     return resultobj;
2025 }
2026
2027 static PyObject *
2028 libxml_children(ATTRIBUTE_UNUSED PyObject * self, PyObject * args)
2029 {
2030     PyObject *resultobj, *obj;
2031     xmlNodePtr cur;
2032     xmlNodePtr res;
2033
2034     if (!PyArg_ParseTuple(args, (char *) "O:children", &obj))
2035         return NULL;
2036     cur = PyxmlNode_Get(obj);
2037
2038 #ifdef DEBUG
2039     printf("libxml_children: cur = %p\n", cur);
2040 #endif
2041
2042     switch (cur->type) {
2043         case XML_ELEMENT_NODE:
2044         case XML_ENTITY_REF_NODE:
2045         case XML_ENTITY_NODE:
2046         case XML_PI_NODE:
2047         case XML_COMMENT_NODE:
2048         case XML_DOCUMENT_NODE:
2049 #ifdef LIBXML_DOCB_ENABLED
2050         case XML_DOCB_DOCUMENT_NODE:
2051 #endif
2052         case XML_HTML_DOCUMENT_NODE:
2053         case XML_DTD_NODE:
2054             res = cur->children;
2055             break;
2056         case XML_ATTRIBUTE_NODE:{
2057                 xmlAttrPtr attr = (xmlAttrPtr) cur;
2058
2059                 res = attr->children;
2060                 break;
2061             }
2062         default:
2063             res = NULL;
2064             break;
2065     }
2066     resultobj = libxml_xmlNodePtrWrap(res);
2067     return resultobj;
2068 }
2069
2070 static PyObject *
2071 libxml_last(ATTRIBUTE_UNUSED PyObject * self, PyObject * args)
2072 {
2073     PyObject *resultobj, *obj;
2074     xmlNodePtr cur;
2075     xmlNodePtr res;
2076
2077     if (!PyArg_ParseTuple(args, (char *) "O:last", &obj))
2078         return NULL;
2079     cur = PyxmlNode_Get(obj);
2080
2081 #ifdef DEBUG
2082     printf("libxml_last: cur = %p\n", cur);
2083 #endif
2084
2085     switch (cur->type) {
2086         case XML_ELEMENT_NODE:
2087         case XML_ENTITY_REF_NODE:
2088         case XML_ENTITY_NODE:
2089         case XML_PI_NODE:
2090         case XML_COMMENT_NODE:
2091         case XML_DOCUMENT_NODE:
2092 #ifdef LIBXML_DOCB_ENABLED
2093         case XML_DOCB_DOCUMENT_NODE:
2094 #endif
2095         case XML_HTML_DOCUMENT_NODE:
2096         case XML_DTD_NODE:
2097             res = cur->last;
2098             break;
2099         case XML_ATTRIBUTE_NODE:{
2100                 xmlAttrPtr attr = (xmlAttrPtr) cur;
2101
2102                 res = attr->last;
2103             }
2104         default:
2105             res = NULL;
2106             break;
2107     }
2108     resultobj = libxml_xmlNodePtrWrap(res);
2109     return resultobj;
2110 }
2111
2112 static PyObject *
2113 libxml_parent(ATTRIBUTE_UNUSED PyObject * self, PyObject * args)
2114 {
2115     PyObject *resultobj, *obj;
2116     xmlNodePtr cur;
2117     xmlNodePtr res;
2118
2119     if (!PyArg_ParseTuple(args, (char *) "O:parent", &obj))
2120         return NULL;
2121     cur = PyxmlNode_Get(obj);
2122
2123 #ifdef DEBUG
2124     printf("libxml_parent: cur = %p\n", cur);
2125 #endif
2126
2127     switch (cur->type) {
2128         case XML_DOCUMENT_NODE:
2129         case XML_HTML_DOCUMENT_NODE:
2130 #ifdef LIBXML_DOCB_ENABLED
2131         case XML_DOCB_DOCUMENT_NODE:
2132 #endif
2133             res = NULL;
2134             break;
2135         case XML_ATTRIBUTE_NODE:{
2136                 xmlAttrPtr attr = (xmlAttrPtr) cur;
2137
2138                 res = attr->parent;
2139             }
2140         case XML_ENTITY_DECL:
2141         case XML_NAMESPACE_DECL:
2142         case XML_XINCLUDE_START:
2143         case XML_XINCLUDE_END:
2144             res = NULL;
2145             break;
2146         default:
2147             res = cur->parent;
2148             break;
2149     }
2150     resultobj = libxml_xmlNodePtrWrap(res);
2151     return resultobj;
2152 }
2153
2154 static PyObject *
2155 libxml_type(ATTRIBUTE_UNUSED PyObject * self, PyObject * args)
2156 {
2157     PyObject *resultobj, *obj;
2158     xmlNodePtr cur;
2159     const xmlChar *res = NULL;
2160
2161     if (!PyArg_ParseTuple(args, (char *) "O:last", &obj))
2162         return NULL;
2163     cur = PyxmlNode_Get(obj);
2164
2165 #ifdef DEBUG
2166     printf("libxml_type: cur = %p\n", cur);
2167 #endif
2168
2169     switch (cur->type) {
2170         case XML_ELEMENT_NODE:
2171             res = (const xmlChar *) "element";
2172             break;
2173         case XML_ATTRIBUTE_NODE:
2174             res = (const xmlChar *) "attribute";
2175             break;
2176         case XML_TEXT_NODE:
2177             res = (const xmlChar *) "text";
2178             break;
2179         case XML_CDATA_SECTION_NODE:
2180             res = (const xmlChar *) "cdata";
2181             break;
2182         case XML_ENTITY_REF_NODE:
2183             res = (const xmlChar *) "entity_ref";
2184             break;
2185         case XML_ENTITY_NODE:
2186             res = (const xmlChar *) "entity";
2187             break;
2188         case XML_PI_NODE:
2189             res = (const xmlChar *) "pi";
2190             break;
2191         case XML_COMMENT_NODE:
2192             res = (const xmlChar *) "comment";
2193             break;
2194         case XML_DOCUMENT_NODE:
2195             res = (const xmlChar *) "document_xml";
2196             break;
2197         case XML_DOCUMENT_TYPE_NODE:
2198             res = (const xmlChar *) "doctype";
2199             break;
2200         case XML_DOCUMENT_FRAG_NODE:
2201             res = (const xmlChar *) "fragment";
2202             break;
2203         case XML_NOTATION_NODE:
2204             res = (const xmlChar *) "notation";
2205             break;
2206         case XML_HTML_DOCUMENT_NODE:
2207             res = (const xmlChar *) "document_html";
2208             break;
2209         case XML_DTD_NODE:
2210             res = (const xmlChar *) "dtd";
2211             break;
2212         case XML_ELEMENT_DECL:
2213             res = (const xmlChar *) "elem_decl";
2214             break;
2215         case XML_ATTRIBUTE_DECL:
2216             res = (const xmlChar *) "attribute_decl";
2217             break;
2218         case XML_ENTITY_DECL:
2219             res = (const xmlChar *) "entity_decl";
2220             break;
2221         case XML_NAMESPACE_DECL:
2222             res = (const xmlChar *) "namespace";
2223             break;
2224         case XML_XINCLUDE_START:
2225             res = (const xmlChar *) "xinclude_start";
2226             break;
2227         case XML_XINCLUDE_END:
2228             res = (const xmlChar *) "xinclude_end";
2229             break;
2230 #ifdef LIBXML_DOCB_ENABLED
2231         case XML_DOCB_DOCUMENT_NODE:
2232             res = (const xmlChar *) "document_docbook";
2233             break;
2234 #endif
2235     }
2236 #ifdef DEBUG
2237     printf("libxml_type: cur = %p: %s\n", cur, res);
2238 #endif
2239
2240     resultobj = libxml_constxmlCharPtrWrap(res);
2241     return resultobj;
2242 }
2243
2244 /************************************************************************
2245  *                                                                      *
2246  *                      Specific accessor functions                     *
2247  *                                                                      *
2248  ************************************************************************/
2249 PyObject *
2250 libxml_xmlNodeGetNsDefs(ATTRIBUTE_UNUSED PyObject * self, PyObject * args)
2251 {
2252     PyObject *py_retval;
2253     xmlNsPtr c_retval;
2254     xmlNodePtr node;
2255     PyObject *pyobj_node;
2256
2257     if (!PyArg_ParseTuple
2258         (args, (char *) "O:xmlNodeGetNsDefs", &pyobj_node))
2259         return (NULL);
2260     node = (xmlNodePtr) PyxmlNode_Get(pyobj_node);
2261
2262     if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) {
2263         Py_INCREF(Py_None);
2264         return (Py_None);
2265     }
2266     c_retval = node->nsDef;
2267     py_retval = libxml_xmlNsPtrWrap((xmlNsPtr) c_retval);
2268     return (py_retval);
2269 }
2270
2271 PyObject *
2272 libxml_xmlNodeGetNs(ATTRIBUTE_UNUSED PyObject * self, PyObject * args)
2273 {
2274     PyObject *py_retval;
2275     xmlNsPtr c_retval;
2276     xmlNodePtr node;
2277     PyObject *pyobj_node;
2278
2279     if (!PyArg_ParseTuple(args, (char *) "O:xmlNodeGetNs", &pyobj_node))
2280         return (NULL);
2281     node = (xmlNodePtr) PyxmlNode_Get(pyobj_node);
2282
2283     if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) {
2284         Py_INCREF(Py_None);
2285         return (Py_None);
2286     }
2287     c_retval = node->ns;
2288     py_retval = libxml_xmlNsPtrWrap((xmlNsPtr) c_retval);
2289     return (py_retval);
2290 }
2291
2292 /************************************************************************
2293  *                                                                      *
2294  *                      Serialization front-end                         *
2295  *                                                                      *
2296  ************************************************************************/
2297
2298 static PyObject *
2299 libxml_serializeNode(ATTRIBUTE_UNUSED PyObject * self, PyObject * args)
2300 {
2301     PyObject *py_retval = NULL;
2302     xmlChar *c_retval;
2303     PyObject *pyobj_node;
2304     xmlNodePtr node;
2305     xmlDocPtr doc;
2306     const char *encoding;
2307     int format;
2308     int len;
2309
2310     if (!PyArg_ParseTuple(args, (char *) "Ozi:serializeNode", &pyobj_node,
2311                           &encoding, &format))
2312         return (NULL);
2313     node = (xmlNodePtr) PyxmlNode_Get(pyobj_node);
2314
2315     if (node == NULL) {
2316         Py_INCREF(Py_None);
2317         return (Py_None);
2318     }
2319     if (node->type == XML_DOCUMENT_NODE) {
2320         doc = (xmlDocPtr) node;
2321         xmlDocDumpFormatMemoryEnc(doc, &c_retval, &len,
2322                                   (const char *) encoding, format);
2323         py_retval = libxml_charPtrWrap((char *) c_retval);
2324     } else if (node->type == XML_HTML_DOCUMENT_NODE) {
2325         xmlOutputBufferPtr buf;
2326         xmlCharEncodingHandlerPtr handler = NULL;
2327
2328         doc = (xmlDocPtr) node;
2329         if (encoding != NULL)
2330             htmlSetMetaEncoding(doc, (const xmlChar *) encoding);
2331         encoding = (const char *) htmlGetMetaEncoding(doc);
2332
2333         if (encoding != NULL) {
2334             handler = xmlFindCharEncodingHandler(encoding);
2335             if (handler == NULL) {
2336                 Py_INCREF(Py_None);
2337                 return (Py_None);
2338             }
2339         }
2340
2341         /*
2342          * Fallback to HTML or ASCII when the encoding is unspecified
2343          */
2344         if (handler == NULL)
2345             handler = xmlFindCharEncodingHandler("HTML");
2346         if (handler == NULL)
2347             handler = xmlFindCharEncodingHandler("ascii");
2348
2349         buf = xmlAllocOutputBuffer(handler);
2350         if (buf == NULL) {
2351             Py_INCREF(Py_None);
2352             return (Py_None);
2353         }
2354         htmlDocContentDumpFormatOutput(buf, doc, encoding, format);
2355         xmlOutputBufferFlush(buf);
2356         if (buf->conv != NULL) {
2357             len = buf->conv->use;
2358             c_retval = buf->conv->content;
2359             buf->conv->content = NULL;
2360         } else {
2361             len = buf->buffer->use;
2362             c_retval = buf->buffer->content;
2363             buf->buffer->content = NULL;
2364         }
2365         (void) xmlOutputBufferClose(buf);
2366         py_retval = libxml_charPtrWrap((char *) c_retval);
2367     } else {
2368         doc = node->doc;
2369         if ((doc == NULL) || (doc->type == XML_DOCUMENT_NODE)) {
2370             xmlOutputBufferPtr buf;
2371             xmlCharEncodingHandlerPtr handler = NULL;
2372
2373             if (encoding != NULL) {
2374                 handler = xmlFindCharEncodingHandler(encoding);
2375                 if (handler == NULL) {
2376                     Py_INCREF(Py_None);
2377                     return (Py_None);
2378                 }
2379             }
2380
2381             buf = xmlAllocOutputBuffer(handler);
2382             if (buf == NULL) {
2383                 Py_INCREF(Py_None);
2384                 return (Py_None);
2385             }
2386             xmlNodeDumpOutput(buf, doc, node, 0, format, encoding);
2387             xmlOutputBufferFlush(buf);
2388             if (buf->conv != NULL) {
2389                 len = buf->conv->use;
2390                 c_retval = buf->conv->content;
2391                 buf->conv->content = NULL;
2392             } else {
2393                 len = buf->buffer->use;
2394                 c_retval = buf->buffer->content;
2395                 buf->buffer->content = NULL;
2396             }
2397             (void) xmlOutputBufferClose(buf);
2398             py_retval = libxml_charPtrWrap((char *) c_retval);
2399         } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2400             xmlOutputBufferPtr buf;
2401             xmlCharEncodingHandlerPtr handler = NULL;
2402
2403             if (encoding != NULL)
2404                 htmlSetMetaEncoding(doc, (const xmlChar *) encoding);
2405             encoding = (const char *) htmlGetMetaEncoding(doc);
2406             if (encoding != NULL) {
2407                 handler = xmlFindCharEncodingHandler(encoding);
2408                 if (handler == NULL) {
2409                     Py_INCREF(Py_None);
2410                     return (Py_None);
2411                 }
2412             }
2413
2414             /*
2415              * Fallback to HTML or ASCII when the encoding is unspecified
2416              */
2417             if (handler == NULL)
2418                 handler = xmlFindCharEncodingHandler("HTML");
2419             if (handler == NULL)
2420                 handler = xmlFindCharEncodingHandler("ascii");
2421
2422             buf = xmlAllocOutputBuffer(handler);
2423             if (buf == NULL) {
2424                 Py_INCREF(Py_None);
2425                 return (Py_None);
2426             }
2427             htmlNodeDumpFormatOutput(buf, doc, node, encoding, format);
2428             xmlOutputBufferFlush(buf);
2429             if (buf->conv != NULL) {
2430                 len = buf->conv->use;
2431                 c_retval = buf->conv->content;
2432                 buf->conv->content = NULL;
2433             } else {
2434                 len = buf->buffer->use;
2435                 c_retval = buf->buffer->content;
2436                 buf->buffer->content = NULL;
2437             }
2438             (void) xmlOutputBufferClose(buf);
2439             py_retval = libxml_charPtrWrap((char *) c_retval);
2440         } else {
2441             Py_INCREF(Py_None);
2442             return (Py_None);
2443         }
2444     }
2445     return (py_retval);
2446 }
2447
2448 static PyObject *
2449 libxml_saveNodeTo(ATTRIBUTE_UNUSED PyObject * self, PyObject * args)
2450 {
2451     PyObject *py_file = NULL;
2452     FILE *output;
2453     PyObject *pyobj_node;
2454     xmlNodePtr node;
2455     xmlDocPtr doc;
2456     const char *encoding;
2457     int format;
2458     int len;
2459     xmlOutputBufferPtr buf;
2460     xmlCharEncodingHandlerPtr handler = NULL;
2461
2462     if (!PyArg_ParseTuple(args, (char *) "OOzi:serializeNode", &pyobj_node,
2463                           &py_file, &encoding, &format))
2464         return (NULL);
2465     node = (xmlNodePtr) PyxmlNode_Get(pyobj_node);
2466
2467     if (node == NULL) {
2468         return (PyInt_FromLong((long) -1));
2469     }
2470     if ((py_file == NULL) || (!(PyFile_Check(py_file)))) {
2471         return (PyInt_FromLong((long) -1));
2472     }
2473     output = PyFile_AsFile(py_file);
2474     if (output == NULL) {
2475         return (PyInt_FromLong((long) -1));
2476     }
2477
2478     if (node->type == XML_DOCUMENT_NODE) {
2479         doc = (xmlDocPtr) node;
2480     } else if (node->type == XML_HTML_DOCUMENT_NODE) {
2481         doc = (xmlDocPtr) node;
2482     } else {
2483         doc = node->doc;
2484     }
2485     if (doc->type == XML_HTML_DOCUMENT_NODE) {
2486         if (encoding == NULL)
2487             encoding = (const char *) htmlGetMetaEncoding(doc);
2488     }
2489     if (encoding != NULL) {
2490         handler = xmlFindCharEncodingHandler(encoding);
2491         if (handler == NULL) {
2492             return (PyInt_FromLong((long) -1));
2493         }
2494     }
2495     if (doc->type == XML_HTML_DOCUMENT_NODE) {
2496         if (handler == NULL)
2497             handler = xmlFindCharEncodingHandler("HTML");
2498         if (handler == NULL)
2499             handler = xmlFindCharEncodingHandler("ascii");
2500     }
2501
2502     buf = xmlOutputBufferCreateFile(output, handler);
2503     if (node->type == XML_DOCUMENT_NODE) {
2504         len = xmlSaveFormatFileTo(buf, doc, encoding, format);
2505     } else if (node->type == XML_HTML_DOCUMENT_NODE) {
2506         htmlDocContentDumpFormatOutput(buf, doc, encoding, format);
2507         len = xmlOutputBufferClose(buf);
2508     } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2509         htmlNodeDumpFormatOutput(buf, doc, node, encoding, format);
2510         len = xmlOutputBufferClose(buf);
2511     } else {
2512         xmlNodeDumpOutput(buf, doc, node, 0, format, encoding);
2513         len = xmlOutputBufferClose(buf);
2514     }
2515     return (PyInt_FromLong((long) len));
2516 }
2517
2518 /************************************************************************
2519  *                                                                      *
2520  *                      Extra stuff                                     *
2521  *                                                                      *
2522  ************************************************************************/
2523 PyObject *
2524 libxml_xmlNewNode(ATTRIBUTE_UNUSED PyObject * self, PyObject * args)
2525 {
2526     PyObject *py_retval;
2527     xmlChar *name;
2528     xmlNodePtr node;
2529
2530     if (!PyArg_ParseTuple(args, (char *) "s:xmlNewNode", &name))
2531         return (NULL);
2532     node = (xmlNodePtr) xmlNewNode(NULL, name);
2533 #ifdef DEBUG
2534     printf("NewNode: %s : %p\n", name, (void *) node);
2535 #endif
2536
2537     if (node == NULL) {
2538         Py_INCREF(Py_None);
2539         return (Py_None);
2540     }
2541     py_retval = libxml_xmlNodePtrWrap(node);
2542     return (py_retval);
2543 }
2544
2545 /************************************************************************
2546  *                                                                      *
2547  *                      The registration stuff                          *
2548  *                                                                      *
2549  ************************************************************************/
2550 static PyMethodDef libxmlMethods[] = {
2551 #include "libxml2-export.c"
2552     {(char *) "name", libxml_name, METH_VARARGS, NULL},
2553     {(char *) "children", libxml_children, METH_VARARGS, NULL},
2554     {(char *) "properties", libxml_properties, METH_VARARGS, NULL},
2555     {(char *) "last", libxml_last, METH_VARARGS, NULL},
2556     {(char *) "prev", libxml_prev, METH_VARARGS, NULL},
2557     {(char *) "next", libxml_next, METH_VARARGS, NULL},
2558     {(char *) "parent", libxml_parent, METH_VARARGS, NULL},
2559     {(char *) "type", libxml_type, METH_VARARGS, NULL},
2560     {(char *) "doc", libxml_doc, METH_VARARGS, NULL},
2561     {(char *) "xmlNewNode", libxml_xmlNewNode, METH_VARARGS, NULL},
2562     {(char *) "serializeNode", libxml_serializeNode, METH_VARARGS, NULL},
2563     {(char *) "saveNodeTo", libxml_saveNodeTo, METH_VARARGS, NULL},
2564     {(char *) "outputBufferCreate", libxml_xmlCreateOutputBuffer, METH_VARARGS, NULL},
2565     {(char *) "inputBufferCreate", libxml_xmlCreateInputBuffer, METH_VARARGS, NULL},
2566     {(char *) "setEntityLoader", libxml_xmlSetEntityLoader, METH_VARARGS, NULL},
2567     {(char *)"xmlRegisterErrorHandler", libxml_xmlRegisterErrorHandler, METH_VARARGS, NULL },
2568     {(char *)"xmlParserCtxtSetErrorHandler", libxml_xmlParserCtxtSetErrorHandler, METH_VARARGS, NULL },
2569     {(char *)"xmlParserCtxtGetErrorHandler", libxml_xmlParserCtxtGetErrorHandler, METH_VARARGS, NULL },
2570     {(char *)"xmlFreeParserCtxt", libxml_xmlFreeParserCtxt, METH_VARARGS, NULL },
2571     {(char *)"xmlTextReaderSetErrorHandler", libxml_xmlTextReaderSetErrorHandler, METH_VARARGS, NULL },
2572     {(char *)"xmlTextReaderGetErrorHandler", libxml_xmlTextReaderGetErrorHandler, METH_VARARGS, NULL },
2573     {(char *)"xmlFreeTextReader", libxml_xmlFreeTextReader, METH_VARARGS, NULL },
2574     {NULL, NULL, 0, NULL}
2575 };
2576
2577 #ifdef MERGED_MODULES
2578 extern void initlibxsltmod(void);
2579 #endif
2580
2581 void
2582 initlibxml2mod(void)
2583 {
2584     static int initialized = 0;
2585     PyObject *m;
2586
2587     if (initialized != 0)
2588         return;
2589     xmlRegisterDefaultOutputCallbacks();
2590     xmlRegisterDefaultInputCallbacks();
2591     m = Py_InitModule((char *) "libxml2mod", libxmlMethods);
2592     initialized = 1;
2593     libxml_xmlErrorInitialize();
2594
2595 #ifdef MERGED_MODULES
2596     initlibxsltmod();
2597 #endif
2598 }