374 lines
13 KiB
C
374 lines
13 KiB
C
|
#ifndef HAS_ETREE_DEFS_H
|
||
|
#define HAS_ETREE_DEFS_H
|
||
|
|
||
|
/* quick check for Python/libxml2/libxslt devel setup */
|
||
|
#include "Python.h"
|
||
|
#ifndef PY_VERSION_HEX
|
||
|
# error the development package of Python (header files etc.) is not installed correctly
|
||
|
#else
|
||
|
# if PY_VERSION_HEX < 0x02060000 || PY_MAJOR_VERSION >= 3 && PY_VERSION_HEX < 0x03020000
|
||
|
# error this version of lxml requires Python 2.6, 2.7, 3.2 or later
|
||
|
# endif
|
||
|
#endif
|
||
|
|
||
|
#include "libxml/xmlversion.h"
|
||
|
#ifndef LIBXML_VERSION
|
||
|
# error the development package of libxml2 (header files etc.) is not installed correctly
|
||
|
#else
|
||
|
#if LIBXML_VERSION < 20700
|
||
|
# error minimum required version of libxml2 is 2.7.0
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#include "libxslt/xsltconfig.h"
|
||
|
#ifndef LIBXSLT_VERSION
|
||
|
# error the development package of libxslt (header files etc.) is not installed correctly
|
||
|
#else
|
||
|
#if LIBXSLT_VERSION < 10123
|
||
|
# error minimum required version of libxslt is 1.1.23
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/* v_arg functions */
|
||
|
#define va_int(ap) va_arg(ap, int)
|
||
|
#define va_charptr(ap) va_arg(ap, char *)
|
||
|
|
||
|
#ifdef PYPY_VERSION
|
||
|
# define IS_PYPY 1
|
||
|
#else
|
||
|
# define IS_PYPY 0
|
||
|
#endif
|
||
|
|
||
|
#if PY_MAJOR_VERSION >= 3
|
||
|
# define IS_PYTHON3 1
|
||
|
#else
|
||
|
# define IS_PYTHON3 0
|
||
|
#endif
|
||
|
|
||
|
#if IS_PYTHON3
|
||
|
#undef LXML_UNICODE_STRINGS
|
||
|
#define LXML_UNICODE_STRINGS 1
|
||
|
#else
|
||
|
#ifndef LXML_UNICODE_STRINGS
|
||
|
#define LXML_UNICODE_STRINGS 0
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#if !IS_PYPY
|
||
|
# define PyWeakref_LockObject(obj) (NULL)
|
||
|
#endif
|
||
|
|
||
|
/* Threading is not currently supported by PyPy */
|
||
|
#if IS_PYPY
|
||
|
# ifndef WITHOUT_THREADING
|
||
|
# define WITHOUT_THREADING
|
||
|
# endif
|
||
|
#endif
|
||
|
|
||
|
#if IS_PYPY
|
||
|
# undef PyFile_AsFile
|
||
|
# define PyFile_AsFile(o) (NULL)
|
||
|
# undef PyByteArray_Check
|
||
|
# define PyByteArray_Check(o) (0)
|
||
|
#elif IS_PYTHON3
|
||
|
/* Python 3 doesn't have PyFile_*() anymore */
|
||
|
# define PyFile_AsFile(o) (NULL)
|
||
|
#endif
|
||
|
|
||
|
#if PY_VERSION_HEX <= 0x03030000 && !(defined(CYTHON_PEP393_ENABLED) && CYTHON_PEP393_ENABLED)
|
||
|
#define PyUnicode_IS_READY(op) (0)
|
||
|
#define PyUnicode_GET_LENGTH(u) PyUnicode_GET_SIZE(u)
|
||
|
#define PyUnicode_KIND(u) (sizeof(Py_UNICODE))
|
||
|
#define PyUnicode_DATA(u) ((void*)PyUnicode_AS_UNICODE(u))
|
||
|
#endif
|
||
|
|
||
|
#if IS_PYPY
|
||
|
# ifndef PyUnicode_FromFormat
|
||
|
# define PyUnicode_FromFormat PyString_FromFormat
|
||
|
# endif
|
||
|
# if IS_PYTHON3 && !defined(PyBytes_FromFormat)
|
||
|
# ifdef PyString_FromFormat
|
||
|
# define PyBytes_FromFormat PyString_FromFormat
|
||
|
# else
|
||
|
#include <stdarg.h>
|
||
|
static PyObject* PyBytes_FromFormat(const char* format, ...) {
|
||
|
PyObject *string;
|
||
|
va_list vargs;
|
||
|
#ifdef HAVE_STDARG_PROTOTYPES
|
||
|
va_start(vargs, format);
|
||
|
#else
|
||
|
va_start(vargs);
|
||
|
#endif
|
||
|
string = PyUnicode_FromFormatV(format, vargs);
|
||
|
va_end(vargs);
|
||
|
if (string && PyUnicode_Check(string)) {
|
||
|
PyObject *bstring = PyUnicode_AsUTF8String(string);
|
||
|
Py_DECREF(string);
|
||
|
string = bstring;
|
||
|
}
|
||
|
if (string && !PyBytes_CheckExact(string)) {
|
||
|
Py_DECREF(string);
|
||
|
string = NULL;
|
||
|
PyErr_SetString(PyExc_TypeError, "String formatting and encoding failed to return bytes object");
|
||
|
}
|
||
|
return string;
|
||
|
}
|
||
|
# endif
|
||
|
# endif
|
||
|
#endif
|
||
|
|
||
|
/* PySlice_GetIndicesEx() has wrong signature in Py<=3.1 */
|
||
|
#if PY_VERSION_HEX >= 0x03020000
|
||
|
# define _lx_PySlice_GetIndicesEx(o, l, b, e, s, sl) PySlice_GetIndicesEx(o, l, b, e, s, sl)
|
||
|
#else
|
||
|
# define _lx_PySlice_GetIndicesEx(o, l, b, e, s, sl) PySlice_GetIndicesEx(((PySliceObject*)o), l, b, e, s, sl)
|
||
|
#endif
|
||
|
|
||
|
#ifdef WITHOUT_THREADING
|
||
|
# undef PyEval_SaveThread
|
||
|
# define PyEval_SaveThread() (NULL)
|
||
|
# undef PyEval_RestoreThread
|
||
|
# define PyEval_RestoreThread(state) if (state); else {}
|
||
|
# undef PyGILState_Ensure
|
||
|
# define PyGILState_Ensure() (PyGILState_UNLOCKED)
|
||
|
# undef PyGILState_Release
|
||
|
# define PyGILState_Release(state) if (state); else {}
|
||
|
# undef Py_UNBLOCK_THREADS
|
||
|
# define Py_UNBLOCK_THREADS _save = NULL;
|
||
|
# undef Py_BLOCK_THREADS
|
||
|
# define Py_BLOCK_THREADS if (_save); else {}
|
||
|
#endif
|
||
|
|
||
|
#ifdef WITHOUT_THREADING
|
||
|
# define ENABLE_THREADING 0
|
||
|
#else
|
||
|
# define ENABLE_THREADING 1
|
||
|
#endif
|
||
|
|
||
|
#if LIBXML_VERSION < 20704
|
||
|
/* FIXME: hack to make new error reporting compile in old libxml2 versions */
|
||
|
# define xmlStructuredErrorContext NULL
|
||
|
# define xmlXIncludeProcessTreeFlagsData(n,o,d) xmlXIncludeProcessTreeFlags(n,o)
|
||
|
#endif
|
||
|
|
||
|
/* schematron was added in libxml2 2.6.21 */
|
||
|
#ifdef LIBXML_SCHEMATRON_ENABLED
|
||
|
# define ENABLE_SCHEMATRON 1
|
||
|
#else
|
||
|
# define ENABLE_SCHEMATRON 0
|
||
|
# define XML_SCHEMATRON_OUT_QUIET 0
|
||
|
# define XML_SCHEMATRON_OUT_XML 0
|
||
|
# define XML_SCHEMATRON_OUT_ERROR 0
|
||
|
typedef void xmlSchematron;
|
||
|
typedef void xmlSchematronParserCtxt;
|
||
|
typedef void xmlSchematronValidCtxt;
|
||
|
# define xmlSchematronNewDocParserCtxt(doc) NULL
|
||
|
# define xmlSchematronNewParserCtxt(file) NULL
|
||
|
# define xmlSchematronParse(ctxt) NULL
|
||
|
# define xmlSchematronFreeParserCtxt(ctxt)
|
||
|
# define xmlSchematronFree(schema)
|
||
|
# define xmlSchematronNewValidCtxt(schema, options) NULL
|
||
|
# define xmlSchematronValidateDoc(ctxt, doc) 0
|
||
|
# define xmlSchematronFreeValidCtxt(ctxt)
|
||
|
# define xmlSchematronSetValidStructuredErrors(ctxt, errorfunc, data)
|
||
|
#endif
|
||
|
|
||
|
#if LIBXML_VERSION < 20900
|
||
|
# define XML_PARSE_BIG_LINES 4194304
|
||
|
#endif
|
||
|
|
||
|
#include "libxml/tree.h"
|
||
|
#ifndef LIBXML2_NEW_BUFFER
|
||
|
typedef xmlBuffer xmlBuf;
|
||
|
# define xmlBufContent(buf) xmlBufferContent(buf)
|
||
|
# define xmlBufUse(buf) xmlBufferLength(buf)
|
||
|
#endif
|
||
|
|
||
|
/* libexslt 1.1.25+ support EXSLT functions in XPath */
|
||
|
#if LIBXSLT_VERSION < 10125
|
||
|
#define exsltDateXpathCtxtRegister(ctxt, prefix)
|
||
|
#define exsltSetsXpathCtxtRegister(ctxt, prefix)
|
||
|
#define exsltMathXpathCtxtRegister(ctxt, prefix)
|
||
|
#define exsltStrXpathCtxtRegister(ctxt, prefix)
|
||
|
#endif
|
||
|
|
||
|
/* work around MSDEV 6.0 */
|
||
|
#if (_MSC_VER == 1200) && (WINVER < 0x0500)
|
||
|
long _ftol( double ); //defined by VC6 C libs
|
||
|
long _ftol2( double dblSource ) { return _ftol( dblSource ); }
|
||
|
#endif
|
||
|
|
||
|
#ifdef __GNUC__
|
||
|
/* Test for GCC > 2.95 */
|
||
|
#if __GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))
|
||
|
#define unlikely_condition(x) __builtin_expect((x), 0)
|
||
|
#else /* __GNUC__ > 2 ... */
|
||
|
#define unlikely_condition(x) (x)
|
||
|
#endif /* __GNUC__ > 2 ... */
|
||
|
#else /* __GNUC__ */
|
||
|
#define unlikely_condition(x) (x)
|
||
|
#endif /* __GNUC__ */
|
||
|
|
||
|
#ifndef Py_TYPE
|
||
|
#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
|
||
|
#endif
|
||
|
|
||
|
#define PY_NEW(T) \
|
||
|
(((PyTypeObject*)(T))->tp_new( \
|
||
|
(PyTypeObject*)(T), __pyx_empty_tuple, NULL))
|
||
|
|
||
|
#define _fqtypename(o) ((Py_TYPE(o))->tp_name)
|
||
|
|
||
|
#define lxml_malloc(count, item_size) \
|
||
|
(unlikely_condition((size_t)(count) > (size_t) (PY_SSIZE_T_MAX / item_size)) ? NULL : \
|
||
|
(PyMem_Malloc((count) * item_size)))
|
||
|
|
||
|
#define lxml_realloc(mem, count, item_size) \
|
||
|
(unlikely_condition((size_t)(count) > (size_t) (PY_SSIZE_T_MAX / item_size)) ? NULL : \
|
||
|
(PyMem_Realloc(mem, (count) * item_size)))
|
||
|
|
||
|
#define lxml_free(mem) PyMem_Free(mem)
|
||
|
|
||
|
#if PY_MAJOR_VERSION < 3
|
||
|
#define _isString(obj) (PyString_CheckExact(obj) || \
|
||
|
PyUnicode_CheckExact(obj) || \
|
||
|
PyType_IsSubtype(Py_TYPE(obj), &PyBaseString_Type))
|
||
|
#else
|
||
|
/* builtin subtype type checks are almost as fast as exact checks in Py2.7+
|
||
|
* and Unicode is more common in Py3 */
|
||
|
#define _isString(obj) (PyUnicode_Check(obj) || PyBytes_Check(obj))
|
||
|
#endif
|
||
|
|
||
|
#define _isElement(c_node) \
|
||
|
(((c_node)->type == XML_ELEMENT_NODE) || \
|
||
|
((c_node)->type == XML_COMMENT_NODE) || \
|
||
|
((c_node)->type == XML_ENTITY_REF_NODE) || \
|
||
|
((c_node)->type == XML_PI_NODE))
|
||
|
|
||
|
#define _isElementOrXInclude(c_node) \
|
||
|
(_isElement(c_node) || \
|
||
|
((c_node)->type == XML_XINCLUDE_START) || \
|
||
|
((c_node)->type == XML_XINCLUDE_END))
|
||
|
|
||
|
#define _getNs(c_node) \
|
||
|
(((c_node)->ns == 0) ? 0 : ((c_node)->ns->href))
|
||
|
|
||
|
|
||
|
/* Macro pair implementation of a depth first tree walker
|
||
|
*
|
||
|
* Calls the code block between the BEGIN and END macros for all elements
|
||
|
* below c_tree_top (exclusively), starting at c_node (inclusively iff
|
||
|
* 'inclusive' is 1). The _ELEMENT_ variants will only stop on nodes
|
||
|
* that match _isElement(), the normal variant will stop on every node
|
||
|
* except text nodes.
|
||
|
*
|
||
|
* To traverse the node and all of its children and siblings in Pyrex, call
|
||
|
* cdef xmlNode* some_node
|
||
|
* BEGIN_FOR_EACH_ELEMENT_FROM(some_node.parent, some_node, 1)
|
||
|
* # do something with some_node
|
||
|
* END_FOR_EACH_ELEMENT_FROM(some_node)
|
||
|
*
|
||
|
* To traverse only the children and siblings of a node, call
|
||
|
* cdef xmlNode* some_node
|
||
|
* BEGIN_FOR_EACH_ELEMENT_FROM(some_node.parent, some_node, 0)
|
||
|
* # do something with some_node
|
||
|
* END_FOR_EACH_ELEMENT_FROM(some_node)
|
||
|
*
|
||
|
* To traverse only the children, do:
|
||
|
* cdef xmlNode* some_node
|
||
|
* some_node = parent_node.children
|
||
|
* BEGIN_FOR_EACH_ELEMENT_FROM(parent_node, some_node, 1)
|
||
|
* # do something with some_node
|
||
|
* END_FOR_EACH_ELEMENT_FROM(some_node)
|
||
|
*
|
||
|
* NOTE: 'some_node' MUST be a plain 'xmlNode*' !
|
||
|
*
|
||
|
* NOTE: parent modification during the walk can divert the iterator, but
|
||
|
* should not segfault !
|
||
|
*/
|
||
|
|
||
|
#define _LX__ELEMENT_MATCH(c_node, only_elements) \
|
||
|
((only_elements) ? (_isElement(c_node)) : 1)
|
||
|
|
||
|
#define _LX__ADVANCE_TO_NEXT(c_node, only_elements) \
|
||
|
while ((c_node != 0) && (!_LX__ELEMENT_MATCH(c_node, only_elements))) \
|
||
|
c_node = c_node->next;
|
||
|
|
||
|
#define _LX__TRAVERSE_TO_NEXT(c_stop_node, c_node, only_elements) \
|
||
|
{ \
|
||
|
/* walk through children first */ \
|
||
|
xmlNode* _lx__next = c_node->children; \
|
||
|
if (_lx__next != 0) { \
|
||
|
if (c_node->type == XML_ENTITY_REF_NODE || c_node->type == XML_DTD_NODE) { \
|
||
|
_lx__next = 0; \
|
||
|
} else { \
|
||
|
_LX__ADVANCE_TO_NEXT(_lx__next, only_elements) \
|
||
|
} \
|
||
|
} \
|
||
|
if ((_lx__next == 0) && (c_node != c_stop_node)) { \
|
||
|
/* try siblings */ \
|
||
|
_lx__next = c_node->next; \
|
||
|
_LX__ADVANCE_TO_NEXT(_lx__next, only_elements) \
|
||
|
/* back off through parents */ \
|
||
|
while (_lx__next == 0) { \
|
||
|
c_node = c_node->parent; \
|
||
|
if (c_node == 0) \
|
||
|
break; \
|
||
|
if (c_node == c_stop_node) \
|
||
|
break; \
|
||
|
if ((only_elements) && !_isElement(c_node)) \
|
||
|
break; \
|
||
|
/* we already traversed the parents -> siblings */ \
|
||
|
_lx__next = c_node->next; \
|
||
|
_LX__ADVANCE_TO_NEXT(_lx__next, only_elements) \
|
||
|
} \
|
||
|
} \
|
||
|
c_node = _lx__next; \
|
||
|
}
|
||
|
|
||
|
#define _LX__BEGIN_FOR_EACH_FROM(c_tree_top, c_node, inclusive, only_elements) \
|
||
|
{ \
|
||
|
if (c_node != 0) { \
|
||
|
const xmlNode* _lx__tree_top = (c_tree_top); \
|
||
|
const int _lx__only_elements = (only_elements); \
|
||
|
/* make sure we start at an element */ \
|
||
|
if (!_LX__ELEMENT_MATCH(c_node, _lx__only_elements)) { \
|
||
|
/* we skip the node, so 'inclusive' is irrelevant */ \
|
||
|
if (c_node == _lx__tree_top) \
|
||
|
c_node = 0; /* nothing to traverse */ \
|
||
|
else { \
|
||
|
c_node = c_node->next; \
|
||
|
_LX__ADVANCE_TO_NEXT(c_node, _lx__only_elements) \
|
||
|
} \
|
||
|
} else if (! (inclusive)) { \
|
||
|
/* skip the first node */ \
|
||
|
_LX__TRAVERSE_TO_NEXT(_lx__tree_top, c_node, _lx__only_elements) \
|
||
|
} \
|
||
|
\
|
||
|
/* now run the user code on the elements we find */ \
|
||
|
while (c_node != 0) { \
|
||
|
/* here goes the code to be run for each element */
|
||
|
|
||
|
#define _LX__END_FOR_EACH_FROM(c_node) \
|
||
|
_LX__TRAVERSE_TO_NEXT(_lx__tree_top, c_node, _lx__only_elements) \
|
||
|
} \
|
||
|
} \
|
||
|
}
|
||
|
|
||
|
|
||
|
#define BEGIN_FOR_EACH_ELEMENT_FROM(c_tree_top, c_node, inclusive) \
|
||
|
_LX__BEGIN_FOR_EACH_FROM(c_tree_top, c_node, inclusive, 1)
|
||
|
|
||
|
#define END_FOR_EACH_ELEMENT_FROM(c_node) \
|
||
|
_LX__END_FOR_EACH_FROM(c_node)
|
||
|
|
||
|
#define BEGIN_FOR_EACH_FROM(c_tree_top, c_node, inclusive) \
|
||
|
_LX__BEGIN_FOR_EACH_FROM(c_tree_top, c_node, inclusive, 0)
|
||
|
|
||
|
#define END_FOR_EACH_FROM(c_node) \
|
||
|
_LX__END_FOR_EACH_FROM(c_node)
|
||
|
|
||
|
|
||
|
#endif /* HAS_ETREE_DEFS_H */
|