From 55f8249d65af3f1b83df81fa46f6fc6e452ed944 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 19 Oct 2018 18:00:51 +0300 Subject: [PATCH] bpo-34741: Get rid of tp_getattro and tp_setattro in pyexpat.xmlparser. (GH-9422) Use tp_members and tp_getset instead. --- Modules/clinic/pyexpat.c.h | 19 +- Modules/pyexpat.c | 595 +++++++++++++++++-------------------- 2 files changed, 269 insertions(+), 345 deletions(-) diff --git a/Modules/clinic/pyexpat.c.h b/Modules/clinic/pyexpat.c.h index 777b6f3114..b7687e5a36 100644 --- a/Modules/clinic/pyexpat.c.h +++ b/Modules/clinic/pyexpat.c.h @@ -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]*/ diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c index ab3dac6db1..10d5aedf1c 100644 --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1,6 +1,7 @@ #include "Python.h" #include +#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,221 +1174,153 @@ 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) +static int +xmlparse_handler_setter(xmlparseobject *self, PyObject *v, struct HandlerInfo *hi) { - Py_UCS4 first_char; - int handlernum = -1; - - if (!PyUnicode_Check(nameobj)) - goto generic; - if (PyUnicode_READY(nameobj)) - return NULL; + int handlernum = hi - handler_info; + if (v == NULL) { + PyErr_SetString(PyExc_RuntimeError, "Cannot delete attribute"); + return -1; + } + 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 + * happen. + */ + if (flush_character_buffer(self) < 0) + return -1; + } - handlernum = handlername2int(nameobj); + 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; +} - if (handlernum != -1) { - PyObject *result = self->handlers[handlernum]; - if (result == NULL) - result = Py_None; - Py_INCREF(result); - return result; +#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) - 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); -} +#undef INT_GETTER -static int -sethandler(xmlparseobject *self, PyObject *name, PyObject* v) +static PyObject * +xmlparse_buffer_text_getter(xmlparseobject *self, void *closure) { - 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; + return PyBool_FromLong(self->buffer != NULL); } static int -xmlparse_setattro(xmlparseobject *self, PyObject *name, PyObject *v) +xmlparse_buffer_text_setter(xmlparseobject *self, PyObject *v, void *closure) { - /* 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; - } 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) { + 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) { - 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) + PyErr_NoMemory(); return -1; - PyMem_Free(self->buffer); - self->buffer = NULL; + } + self->buffer_used = 0; } - 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) + else if (self->buffer != NULL) { + if (flush_character_buffer(self) < 0) return -1; - self->specified_attributes = b; - return 0; + PyMem_Free(self->buffer); + self->buffer = NULL; } + return 0; +} - if (_PyUnicode_EqualToASCIIString(name, "buffer_size")) { - long new_buffer_size; - if (!PyLong_Check(v)) { +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) { + 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"); + PyErr_SetString(PyExc_ValueError, "buffer_size must be greater than zero"); return -1; - } + } - /* trivial case -- no change */ - if (new_buffer_size == self->buffer_size) { + /* trivial case -- no change */ + if (new_buffer_size == self->buffer_size) { return 0; - } + } - /* check maximum */ - if (new_buffer_size > INT_MAX) { + /* 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) { + if (self->buffer != NULL) { /* there is already a buffer */ if (self->buffer_used != 0) { if (flush_character_buffer(self) < 0) { @@ -1461,32 +1329,114 @@ xmlparse_setattro(xmlparseobject *self, PyObject *name, PyObject *v) } /* free existing buffer */ PyMem_Free(self->buffer); - } - self->buffer = PyMem_Malloc(new_buffer_size); - if (self->buffer == NULL) { + } + self->buffer = PyMem_Malloc(new_buffer_size); + if (self->buffer == NULL) { PyErr_NoMemory(); return -1; - } - self->buffer_size = new_buffer_size; - return 0; } + self->buffer_size = new_buffer_size; + return 0; +} - if (_PyUnicode_EqualToASCIIString(name, "CharacterDataHandler")) { - /* 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 - * happen. - */ - if (flush_character_buffer(self) < 0) - return -1; +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; } - if (sethandler(self, name, v)) { - return 0; + 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; } - PyErr_SetObject(PyExc_AttributeError, name); - 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 */ }; -- 2.40.0