bpo-34741: Get rid of tp_getattro and tp_setattro in pyexpat.xmlparser. (GH-9422)

Use tp_members and tp_getset instead.
This commit is contained in:
Serhiy Storchaka 2018-10-19 18:00:51 +03:00 committed by GitHub
parent 6543912c90
commit 55f8249d65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 302 additions and 378 deletions

View File

@ -208,23 +208,6 @@ exit:
#endif /* (XML_COMBINED_VERSION >= 19505) */
PyDoc_STRVAR(pyexpat_xmlparser___dir____doc__,
"__dir__($self, /)\n"
"--\n"
"\n");
#define PYEXPAT_XMLPARSER___DIR___METHODDEF \
{"__dir__", (PyCFunction)pyexpat_xmlparser___dir__, METH_NOARGS, pyexpat_xmlparser___dir____doc__},
static PyObject *
pyexpat_xmlparser___dir___impl(xmlparseobject *self);
static PyObject *
pyexpat_xmlparser___dir__(xmlparseobject *self, PyObject *Py_UNUSED(ignored))
{
return pyexpat_xmlparser___dir___impl(self);
}
PyDoc_STRVAR(pyexpat_ParserCreate__doc__,
"ParserCreate($module, /, encoding=None, namespace_separator=None,\n"
" intern=None)\n"
@ -289,4 +272,4 @@ exit:
#ifndef PYEXPAT_XMLPARSER_USEFOREIGNDTD_METHODDEF
#define PYEXPAT_XMLPARSER_USEFOREIGNDTD_METHODDEF
#endif /* !defined(PYEXPAT_XMLPARSER_USEFOREIGNDTD_METHODDEF) */
/*[clinic end generated code: output=34d02345deee104c input=a9049054013a1b77]*/
/*[clinic end generated code: output=6bdf1faf8ba1af32 input=a9049054013a1b77]*/

View File

@ -1,6 +1,7 @@
#include "Python.h"
#include <ctype.h>
#include "structmember.h"
#include "frameobject.h"
#include "expat.h"
@ -81,8 +82,7 @@ struct HandlerInfo {
const char *name;
xmlhandlersetter setter;
xmlhandler handler;
PyCodeObject *tb_code;
PyObject *nameobj;
PyGetSetDef getset;
};
static struct HandlerInfo handler_info[64];
@ -138,19 +138,6 @@ have_handler(xmlparseobject *self, int type)
return handler != NULL;
}
static PyObject *
get_handler_name(struct HandlerInfo *hinfo)
{
PyObject *name = hinfo->nameobj;
if (name == NULL) {
name = PyUnicode_FromString(hinfo->name);
hinfo->nameobj = name;
}
Py_XINCREF(name);
return name;
}
/* Convert a string of XML_Chars into a Unicode string.
Returns None if str is a null pointer. */
@ -651,6 +638,7 @@ VOID_HANDLER(Default,
VOID_HANDLER(DefaultHandlerExpand,
(void *userData, const XML_Char *s, int len),
("(N)", (conv_string_len_to_unicode(s,len))))
#define my_DefaultHandlerExpand my_DefaultHandlerExpandHandler
INT_HANDLER(NotStandalone,
(void *userData),
@ -1036,57 +1024,6 @@ pyexpat_xmlparser_UseForeignDTD_impl(xmlparseobject *self, int flag)
}
#endif
/*[clinic input]
pyexpat.xmlparser.__dir__
[clinic start generated code]*/
static PyObject *
pyexpat_xmlparser___dir___impl(xmlparseobject *self)
/*[clinic end generated code: output=bc22451efb9e4d17 input=76aa455f2a661384]*/
{
#define APPEND(list, str) \
do { \
PyObject *o = PyUnicode_FromString(str); \
if (o != NULL) \
PyList_Append(list, o); \
Py_XDECREF(o); \
} while (0)
int i;
PyObject *rc = PyList_New(0);
if (!rc)
return NULL;
for (i = 0; handler_info[i].name != NULL; i++) {
PyObject *o = get_handler_name(&handler_info[i]);
if (o != NULL)
PyList_Append(rc, o);
Py_XDECREF(o);
}
APPEND(rc, "ErrorCode");
APPEND(rc, "ErrorLineNumber");
APPEND(rc, "ErrorColumnNumber");
APPEND(rc, "ErrorByteIndex");
APPEND(rc, "CurrentLineNumber");
APPEND(rc, "CurrentColumnNumber");
APPEND(rc, "CurrentByteIndex");
APPEND(rc, "buffer_size");
APPEND(rc, "buffer_text");
APPEND(rc, "buffer_used");
APPEND(rc, "namespace_prefixes");
APPEND(rc, "ordered_attributes");
APPEND(rc, "specified_attributes");
APPEND(rc, "intern");
#undef APPEND
if (PyErr_Occurred()) {
Py_DECREF(rc);
rc = NULL;
}
return rc;
}
static struct PyMethodDef xmlparse_methods[] = {
PYEXPAT_XMLPARSER_PARSE_METHODDEF
PYEXPAT_XMLPARSER_PARSEFILE_METHODDEF
@ -1098,7 +1035,6 @@ static struct PyMethodDef xmlparse_methods[] = {
#if XML_COMBINED_VERSION >= 19505
PYEXPAT_XMLPARSER_USEFOREIGNDTD_METHODDEF
#endif
PYEXPAT_XMLPARSER___DIR___METHODDEF
{NULL, NULL} /* sentinel */
};
@ -1238,240 +1174,27 @@ xmlparse_dealloc(xmlparseobject *self)
PyObject_GC_Del(self);
}
static int
handlername2int(PyObject *name)
{
int i;
for (i = 0; handler_info[i].name != NULL; i++) {
if (_PyUnicode_EqualToASCIIString(name, handler_info[i].name)) {
return i;
}
}
return -1;
}
static PyObject *
get_pybool(int istrue)
xmlparse_handler_getter(xmlparseobject *self, struct HandlerInfo *hi)
{
PyObject *result = istrue ? Py_True : Py_False;
int handlernum = hi - handler_info;
PyObject *result = self->handlers[handlernum];
if (result == NULL)
result = Py_None;
Py_INCREF(result);
return result;
}
static PyObject *
xmlparse_getattro(xmlparseobject *self, PyObject *nameobj)
{
Py_UCS4 first_char;
int handlernum = -1;
if (!PyUnicode_Check(nameobj))
goto generic;
if (PyUnicode_READY(nameobj))
return NULL;
handlernum = handlername2int(nameobj);
if (handlernum != -1) {
PyObject *result = self->handlers[handlernum];
if (result == NULL)
result = Py_None;
Py_INCREF(result);
return result;
}
first_char = PyUnicode_READ_CHAR(nameobj, 0);
if (first_char == 'E') {
if (_PyUnicode_EqualToASCIIString(nameobj, "ErrorCode"))
return PyLong_FromLong((long)
XML_GetErrorCode(self->itself));
if (_PyUnicode_EqualToASCIIString(nameobj, "ErrorLineNumber"))
return PyLong_FromLong((long)
XML_GetErrorLineNumber(self->itself));
if (_PyUnicode_EqualToASCIIString(nameobj, "ErrorColumnNumber"))
return PyLong_FromLong((long)
XML_GetErrorColumnNumber(self->itself));
if (_PyUnicode_EqualToASCIIString(nameobj, "ErrorByteIndex"))
return PyLong_FromLong((long)
XML_GetErrorByteIndex(self->itself));
}
if (first_char == 'C') {
if (_PyUnicode_EqualToASCIIString(nameobj, "CurrentLineNumber"))
return PyLong_FromLong((long)
XML_GetCurrentLineNumber(self->itself));
if (_PyUnicode_EqualToASCIIString(nameobj, "CurrentColumnNumber"))
return PyLong_FromLong((long)
XML_GetCurrentColumnNumber(self->itself));
if (_PyUnicode_EqualToASCIIString(nameobj, "CurrentByteIndex"))
return PyLong_FromLong((long)
XML_GetCurrentByteIndex(self->itself));
}
if (first_char == 'b') {
if (_PyUnicode_EqualToASCIIString(nameobj, "buffer_size"))
return PyLong_FromLong((long) self->buffer_size);
if (_PyUnicode_EqualToASCIIString(nameobj, "buffer_text"))
return get_pybool(self->buffer != NULL);
if (_PyUnicode_EqualToASCIIString(nameobj, "buffer_used"))
return PyLong_FromLong((long) self->buffer_used);
}
if (_PyUnicode_EqualToASCIIString(nameobj, "namespace_prefixes"))
return get_pybool(self->ns_prefixes);
if (_PyUnicode_EqualToASCIIString(nameobj, "ordered_attributes"))
return get_pybool(self->ordered_attributes);
if (_PyUnicode_EqualToASCIIString(nameobj, "specified_attributes"))
return get_pybool((long) self->specified_attributes);
if (_PyUnicode_EqualToASCIIString(nameobj, "intern")) {
if (self->intern == NULL) {
Py_RETURN_NONE;
}
else {
Py_INCREF(self->intern);
return self->intern;
}
}
generic:
return PyObject_GenericGetAttr((PyObject*)self, nameobj);
}
static int
sethandler(xmlparseobject *self, PyObject *name, PyObject* v)
xmlparse_handler_setter(xmlparseobject *self, PyObject *v, struct HandlerInfo *hi)
{
int handlernum = handlername2int(name);
if (handlernum >= 0) {
xmlhandler c_handler = NULL;
if (v == Py_None) {
/* If this is the character data handler, and a character
data handler is already active, we need to be more
careful. What we can safely do is replace the existing
character data handler callback function with a no-op
function that will refuse to call Python. The downside
is that this doesn't completely remove the character
data handler from the C layer if there's any callback
active, so Expat does a little more work than it
otherwise would, but that's really an odd case. A more
elaborate system of handlers and state could remove the
C handler more effectively. */
if (handlernum == CharacterData && self->in_callback)
c_handler = noop_character_data_handler;
v = NULL;
}
else if (v != NULL) {
Py_INCREF(v);
c_handler = handler_info[handlernum].handler;
}
Py_XSETREF(self->handlers[handlernum], v);
handler_info[handlernum].setter(self->itself, c_handler);
return 1;
}
return 0;
}
static int
xmlparse_setattro(xmlparseobject *self, PyObject *name, PyObject *v)
{
/* Set attribute 'name' to value 'v'. v==NULL means delete */
if (!PyUnicode_Check(name)) {
PyErr_Format(PyExc_TypeError,
"attribute name must be string, not '%.200s'",
name->ob_type->tp_name);
return -1;
}
int handlernum = hi - handler_info;
if (v == NULL) {
PyErr_SetString(PyExc_RuntimeError, "Cannot delete attribute");
return -1;
}
if (_PyUnicode_EqualToASCIIString(name, "buffer_text")) {
int b = PyObject_IsTrue(v);
if (b < 0)
return -1;
if (b) {
if (self->buffer == NULL) {
self->buffer = PyMem_Malloc(self->buffer_size);
if (self->buffer == NULL) {
PyErr_NoMemory();
return -1;
}
self->buffer_used = 0;
}
}
else if (self->buffer != NULL) {
if (flush_character_buffer(self) < 0)
return -1;
PyMem_Free(self->buffer);
self->buffer = NULL;
}
return 0;
}
if (_PyUnicode_EqualToASCIIString(name, "namespace_prefixes")) {
int b = PyObject_IsTrue(v);
if (b < 0)
return -1;
self->ns_prefixes = b;
XML_SetReturnNSTriplet(self->itself, self->ns_prefixes);
return 0;
}
if (_PyUnicode_EqualToASCIIString(name, "ordered_attributes")) {
int b = PyObject_IsTrue(v);
if (b < 0)
return -1;
self->ordered_attributes = b;
return 0;
}
if (_PyUnicode_EqualToASCIIString(name, "specified_attributes")) {
int b = PyObject_IsTrue(v);
if (b < 0)
return -1;
self->specified_attributes = b;
return 0;
}
if (_PyUnicode_EqualToASCIIString(name, "buffer_size")) {
long new_buffer_size;
if (!PyLong_Check(v)) {
PyErr_SetString(PyExc_TypeError, "buffer_size must be an integer");
return -1;
}
new_buffer_size = PyLong_AsLong(v);
if (new_buffer_size <= 0) {
if (!PyErr_Occurred())
PyErr_SetString(PyExc_ValueError, "buffer_size must be greater than zero");
return -1;
}
/* trivial case -- no change */
if (new_buffer_size == self->buffer_size) {
return 0;
}
/* check maximum */
if (new_buffer_size > INT_MAX) {
char errmsg[100];
sprintf(errmsg, "buffer_size must not be greater than %i", INT_MAX);
PyErr_SetString(PyExc_ValueError, errmsg);
return -1;
}
if (self->buffer != NULL) {
/* there is already a buffer */
if (self->buffer_used != 0) {
if (flush_character_buffer(self) < 0) {
return -1;
}
}
/* free existing buffer */
PyMem_Free(self->buffer);
}
self->buffer = PyMem_Malloc(new_buffer_size);
if (self->buffer == NULL) {
PyErr_NoMemory();
return -1;
}
self->buffer_size = new_buffer_size;
return 0;
}
if (_PyUnicode_EqualToASCIIString(name, "CharacterDataHandler")) {
if (handlernum == CharacterData) {
/* If we're changing the character data handler, flush all
* cached data with the old handler. Not sure there's a
* "right" thing to do, though, but this probably won't
@ -1480,13 +1203,240 @@ xmlparse_setattro(xmlparseobject *self, PyObject *name, PyObject *v)
if (flush_character_buffer(self) < 0)
return -1;
}
if (sethandler(self, name, v)) {
xmlhandler c_handler = NULL;
if (v == Py_None) {
/* If this is the character data handler, and a character
data handler is already active, we need to be more
careful. What we can safely do is replace the existing
character data handler callback function with a no-op
function that will refuse to call Python. The downside
is that this doesn't completely remove the character
data handler from the C layer if there's any callback
active, so Expat does a little more work than it
otherwise would, but that's really an odd case. A more
elaborate system of handlers and state could remove the
C handler more effectively. */
if (handlernum == CharacterData && self->in_callback)
c_handler = noop_character_data_handler;
v = NULL;
}
else if (v != NULL) {
Py_INCREF(v);
c_handler = handler_info[handlernum].handler;
}
Py_XSETREF(self->handlers[handlernum], v);
handler_info[handlernum].setter(self->itself, c_handler);
return 0;
}
#define INT_GETTER(name) \
static PyObject * \
xmlparse_##name##_getter(xmlparseobject *self, void *closure) \
{ \
return PyLong_FromLong((long) XML_Get##name(self->itself)); \
}
INT_GETTER(ErrorCode)
INT_GETTER(ErrorLineNumber)
INT_GETTER(ErrorColumnNumber)
INT_GETTER(ErrorByteIndex)
INT_GETTER(CurrentLineNumber)
INT_GETTER(CurrentColumnNumber)
INT_GETTER(CurrentByteIndex)
#undef INT_GETTER
static PyObject *
xmlparse_buffer_text_getter(xmlparseobject *self, void *closure)
{
return PyBool_FromLong(self->buffer != NULL);
}
static int
xmlparse_buffer_text_setter(xmlparseobject *self, PyObject *v, void *closure)
{
if (v == NULL) {
PyErr_SetString(PyExc_RuntimeError, "Cannot delete attribute");
return -1;
}
int b = PyObject_IsTrue(v);
if (b < 0)
return -1;
if (b) {
if (self->buffer == NULL) {
self->buffer = PyMem_Malloc(self->buffer_size);
if (self->buffer == NULL) {
PyErr_NoMemory();
return -1;
}
self->buffer_used = 0;
}
}
else if (self->buffer != NULL) {
if (flush_character_buffer(self) < 0)
return -1;
PyMem_Free(self->buffer);
self->buffer = NULL;
}
return 0;
}
static PyObject *
xmlparse_buffer_size_getter(xmlparseobject *self, void *closure)
{
return PyLong_FromLong((long) self->buffer_size);
}
static int
xmlparse_buffer_size_setter(xmlparseobject *self, PyObject *v, void *closure)
{
if (v == NULL) {
PyErr_SetString(PyExc_RuntimeError, "Cannot delete attribute");
return -1;
}
long new_buffer_size;
if (!PyLong_Check(v)) {
PyErr_SetString(PyExc_TypeError, "buffer_size must be an integer");
return -1;
}
new_buffer_size = PyLong_AsLong(v);
if (new_buffer_size <= 0) {
if (!PyErr_Occurred())
PyErr_SetString(PyExc_ValueError, "buffer_size must be greater than zero");
return -1;
}
/* trivial case -- no change */
if (new_buffer_size == self->buffer_size) {
return 0;
}
PyErr_SetObject(PyExc_AttributeError, name);
return -1;
/* check maximum */
if (new_buffer_size > INT_MAX) {
char errmsg[100];
sprintf(errmsg, "buffer_size must not be greater than %i", INT_MAX);
PyErr_SetString(PyExc_ValueError, errmsg);
return -1;
}
if (self->buffer != NULL) {
/* there is already a buffer */
if (self->buffer_used != 0) {
if (flush_character_buffer(self) < 0) {
return -1;
}
}
/* free existing buffer */
PyMem_Free(self->buffer);
}
self->buffer = PyMem_Malloc(new_buffer_size);
if (self->buffer == NULL) {
PyErr_NoMemory();
return -1;
}
self->buffer_size = new_buffer_size;
return 0;
}
static PyObject *
xmlparse_buffer_used_getter(xmlparseobject *self, void *closure)
{
return PyLong_FromLong((long) self->buffer_used);
}
static PyObject *
xmlparse_namespace_prefixes_getter(xmlparseobject *self, void *closure)
{
return PyBool_FromLong(self->ns_prefixes);
}
static int
xmlparse_namespace_prefixes_setter(xmlparseobject *self, PyObject *v, void *closure)
{
if (v == NULL) {
PyErr_SetString(PyExc_RuntimeError, "Cannot delete attribute");
return -1;
}
int b = PyObject_IsTrue(v);
if (b < 0)
return -1;
self->ns_prefixes = b;
XML_SetReturnNSTriplet(self->itself, self->ns_prefixes);
return 0;
}
static PyObject *
xmlparse_ordered_attributes_getter(xmlparseobject *self, void *closure)
{
return PyBool_FromLong(self->ordered_attributes);
}
static int
xmlparse_ordered_attributes_setter(xmlparseobject *self, PyObject *v, void *closure)
{
if (v == NULL) {
PyErr_SetString(PyExc_RuntimeError, "Cannot delete attribute");
return -1;
}
int b = PyObject_IsTrue(v);
if (b < 0)
return -1;
self->ordered_attributes = b;
return 0;
}
static PyObject *
xmlparse_specified_attributes_getter(xmlparseobject *self, void *closure)
{
return PyBool_FromLong((long) self->specified_attributes);
}
static int
xmlparse_specified_attributes_setter(xmlparseobject *self, PyObject *v, void *closure)
{
if (v == NULL) {
PyErr_SetString(PyExc_RuntimeError, "Cannot delete attribute");
return -1;
}
int b = PyObject_IsTrue(v);
if (b < 0)
return -1;
self->specified_attributes = b;
return 0;
}
static PyMemberDef xmlparse_members[] = {
{"intern", T_OBJECT, offsetof(xmlparseobject, intern), READONLY, NULL},
{NULL}
};
#define XMLPARSE_GETTER_DEF(name) \
{#name, (getter)xmlparse_##name##_getter, NULL, NULL},
#define XMLPARSE_GETTER_SETTER_DEF(name) \
{#name, (getter)xmlparse_##name##_getter, \
(setter)xmlparse_##name##_setter, NULL},
static PyGetSetDef xmlparse_getsetlist[] = {
XMLPARSE_GETTER_DEF(ErrorCode)
XMLPARSE_GETTER_DEF(ErrorLineNumber)
XMLPARSE_GETTER_DEF(ErrorColumnNumber)
XMLPARSE_GETTER_DEF(ErrorByteIndex)
XMLPARSE_GETTER_DEF(CurrentLineNumber)
XMLPARSE_GETTER_DEF(CurrentColumnNumber)
XMLPARSE_GETTER_DEF(CurrentByteIndex)
XMLPARSE_GETTER_SETTER_DEF(buffer_size)
XMLPARSE_GETTER_SETTER_DEF(buffer_text)
XMLPARSE_GETTER_DEF(buffer_used)
XMLPARSE_GETTER_SETTER_DEF(namespace_prefixes)
XMLPARSE_GETTER_SETTER_DEF(ordered_attributes)
XMLPARSE_GETTER_SETTER_DEF(specified_attributes)
{NULL},
};
#undef XMLPARSE_GETTER_DEF
#undef XMLPARSE_GETTER_SETTER_DEF
static int
xmlparse_traverse(xmlparseobject *op, visitproc visit, void *arg)
{
@ -1524,8 +1474,8 @@ static PyTypeObject Xmlparsetype = {
(hashfunc)0, /*tp_hash*/
(ternaryfunc)0, /*tp_call*/
(reprfunc)0, /*tp_str*/
(getattrofunc)xmlparse_getattro, /* tp_getattro */
(setattrofunc)xmlparse_setattro, /* tp_setattro */
(getattrofunc)0, /* tp_getattro */
(setattrofunc)0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
Xmlparsetype__doc__, /* tp_doc - Documentation string */
@ -1536,6 +1486,8 @@ static PyTypeObject Xmlparsetype = {
0, /* tp_iter */
0, /* tp_iternext */
xmlparse_methods, /* tp_methods */
xmlparse_members, /* tp_members */
xmlparse_getsetlist, /* tp_getset */
};
/* End of code for xmlparser objects */
@ -1639,6 +1591,33 @@ static struct PyModuleDef pyexpatmodule = {
NULL
};
static int init_handler_descrs(void)
{
int i;
assert(!PyType_HasFeature(&Xmlparsetype, Py_TPFLAGS_VALID_VERSION_TAG));
for (i = 0; handler_info[i].name != NULL; i++) {
struct HandlerInfo *hi = &handler_info[i];
hi->getset.name = hi->name;
hi->getset.get = (getter)xmlparse_handler_getter;
hi->getset.set = (setter)xmlparse_handler_setter;
hi->getset.closure = &handler_info[i];
PyObject *descr;
if (PyDict_GetItemString(Xmlparsetype.tp_dict, hi->name))
continue;
descr = PyDescr_NewGetSet(&Xmlparsetype, &hi->getset);
if (descr == NULL)
return -1;
if (PyDict_SetItem(Xmlparsetype.tp_dict, PyDescr_NAME(descr), descr) < 0) {
Py_DECREF(descr);
return -1;
}
Py_DECREF(descr);
}
return 0;
}
PyMODINIT_FUNC
MODULE_INITFUNC(void)
{
@ -1660,7 +1639,7 @@ MODULE_INITFUNC(void)
if (modelmod_name == NULL)
return NULL;
if (PyType_Ready(&Xmlparsetype) < 0)
if (PyType_Ready(&Xmlparsetype) < 0 || init_handler_descrs() < 0)
return NULL;
/* Create the module and add the functions */
@ -1910,74 +1889,36 @@ clear_handlers(xmlparseobject *self, int initial)
}
static struct HandlerInfo handler_info[] = {
{"StartElementHandler",
(xmlhandlersetter)XML_SetStartElementHandler,
(xmlhandler)my_StartElementHandler},
{"EndElementHandler",
(xmlhandlersetter)XML_SetEndElementHandler,
(xmlhandler)my_EndElementHandler},
{"ProcessingInstructionHandler",
(xmlhandlersetter)XML_SetProcessingInstructionHandler,
(xmlhandler)my_ProcessingInstructionHandler},
{"CharacterDataHandler",
(xmlhandlersetter)XML_SetCharacterDataHandler,
(xmlhandler)my_CharacterDataHandler},
{"UnparsedEntityDeclHandler",
(xmlhandlersetter)XML_SetUnparsedEntityDeclHandler,
(xmlhandler)my_UnparsedEntityDeclHandler},
{"NotationDeclHandler",
(xmlhandlersetter)XML_SetNotationDeclHandler,
(xmlhandler)my_NotationDeclHandler},
{"StartNamespaceDeclHandler",
(xmlhandlersetter)XML_SetStartNamespaceDeclHandler,
(xmlhandler)my_StartNamespaceDeclHandler},
{"EndNamespaceDeclHandler",
(xmlhandlersetter)XML_SetEndNamespaceDeclHandler,
(xmlhandler)my_EndNamespaceDeclHandler},
{"CommentHandler",
(xmlhandlersetter)XML_SetCommentHandler,
(xmlhandler)my_CommentHandler},
{"StartCdataSectionHandler",
(xmlhandlersetter)XML_SetStartCdataSectionHandler,
(xmlhandler)my_StartCdataSectionHandler},
{"EndCdataSectionHandler",
(xmlhandlersetter)XML_SetEndCdataSectionHandler,
(xmlhandler)my_EndCdataSectionHandler},
{"DefaultHandler",
(xmlhandlersetter)XML_SetDefaultHandler,
(xmlhandler)my_DefaultHandler},
{"DefaultHandlerExpand",
(xmlhandlersetter)XML_SetDefaultHandlerExpand,
(xmlhandler)my_DefaultHandlerExpandHandler},
{"NotStandaloneHandler",
(xmlhandlersetter)XML_SetNotStandaloneHandler,
(xmlhandler)my_NotStandaloneHandler},
{"ExternalEntityRefHandler",
(xmlhandlersetter)XML_SetExternalEntityRefHandler,
(xmlhandler)my_ExternalEntityRefHandler},
{"StartDoctypeDeclHandler",
(xmlhandlersetter)XML_SetStartDoctypeDeclHandler,
(xmlhandler)my_StartDoctypeDeclHandler},
{"EndDoctypeDeclHandler",
(xmlhandlersetter)XML_SetEndDoctypeDeclHandler,
(xmlhandler)my_EndDoctypeDeclHandler},
{"EntityDeclHandler",
(xmlhandlersetter)XML_SetEntityDeclHandler,
(xmlhandler)my_EntityDeclHandler},
{"XmlDeclHandler",
(xmlhandlersetter)XML_SetXmlDeclHandler,
(xmlhandler)my_XmlDeclHandler},
{"ElementDeclHandler",
(xmlhandlersetter)XML_SetElementDeclHandler,
(xmlhandler)my_ElementDeclHandler},
{"AttlistDeclHandler",
(xmlhandlersetter)XML_SetAttlistDeclHandler,
(xmlhandler)my_AttlistDeclHandler},
#define HANDLER_INFO(name) \
{#name, (xmlhandlersetter)XML_Set##name, (xmlhandler)my_##name},
HANDLER_INFO(StartElementHandler)
HANDLER_INFO(EndElementHandler)
HANDLER_INFO(ProcessingInstructionHandler)
HANDLER_INFO(CharacterDataHandler)
HANDLER_INFO(UnparsedEntityDeclHandler)
HANDLER_INFO(NotationDeclHandler)
HANDLER_INFO(StartNamespaceDeclHandler)
HANDLER_INFO(EndNamespaceDeclHandler)
HANDLER_INFO(CommentHandler)
HANDLER_INFO(StartCdataSectionHandler)
HANDLER_INFO(EndCdataSectionHandler)
HANDLER_INFO(DefaultHandler)
HANDLER_INFO(DefaultHandlerExpand)
HANDLER_INFO(NotStandaloneHandler)
HANDLER_INFO(ExternalEntityRefHandler)
HANDLER_INFO(StartDoctypeDeclHandler)
HANDLER_INFO(EndDoctypeDeclHandler)
HANDLER_INFO(EntityDeclHandler)
HANDLER_INFO(XmlDeclHandler)
HANDLER_INFO(ElementDeclHandler)
HANDLER_INFO(AttlistDeclHandler)
#if XML_COMBINED_VERSION >= 19504
{"SkippedEntityHandler",
(xmlhandlersetter)XML_SetSkippedEntityHandler,
(xmlhandler)my_SkippedEntityHandler},
HANDLER_INFO(SkippedEntityHandler)
#endif
#undef HANDLER_INFO
{NULL, NULL, NULL} /* sentinel */
};