Store per-element parser state in a struct

Make the parser context's "pushTab" point to an array of structs
instead of void pointers. This avoids casting unrelated types to void
pointers, improving readability and portability, and allows for more
efficient packing. Ultimately, the struct could be extended to include
the contents of "nameTab" and "spaceTab", further simplifying the code.

Historically, "pushTab" was only used by the push parser (hence the
name), so the change to the public headers should be safe.

Also remove an unused parameter from xmlParseEndTag2.
diff --git a/include/libxml/parser.h b/include/libxml/parser.h
index 1c86a97..0ba1c38 100644
--- a/include/libxml/parser.h
+++ b/include/libxml/parser.h
@@ -169,6 +169,8 @@
     XML_PARSE_READER = 5
 } xmlParserMode;
 
+typedef struct _xmlStartTag xmlStartTag;
+
 /**
  * xmlParserCtxt:
  *
@@ -280,7 +282,7 @@
     int                nsMax;         /* the size of the arrays */
     const xmlChar *   *nsTab;         /* the array of prefix/namespace name */
     int               *attallocs;     /* which attribute were allocated */
-    void *            *pushTab;       /* array of data for push */
+    xmlStartTag       *pushTab;       /* array of data for push */
     xmlHashTablePtr    attsDefault;   /* defaulted attributes if any */
     xmlHashTablePtr    attsSpecial;   /* non-CDATA attributes if any */
     int                nsWellFormed;  /* is the document XML Namespace okay */
diff --git a/parser.c b/parser.c
index dd58282..9bda945 100644
--- a/parser.c
+++ b/parser.c
@@ -87,6 +87,13 @@
 #include "buf.h"
 #include "enc.h"
 
+struct _xmlStartTag {
+    const xmlChar *prefix;
+    const xmlChar *URI;
+    int line;
+    int nsNr;
+};
+
 static void
 xmlFatalErr(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *info);
 
@@ -1849,9 +1856,11 @@
 nameNsPush(xmlParserCtxtPtr ctxt, const xmlChar * value,
            const xmlChar *prefix, const xmlChar *URI, int line, int nsNr)
 {
+    xmlStartTag *tag;
+
     if (ctxt->nameNr >= ctxt->nameMax) {
         const xmlChar * *tmp;
-        void **tmp2;
+        xmlStartTag *tmp2;
         ctxt->nameMax *= 2;
         tmp = (const xmlChar * *) xmlRealloc((xmlChar * *)ctxt->nameTab,
                                     ctxt->nameMax *
@@ -1861,8 +1870,8 @@
 	    goto mem_error;
         }
 	ctxt->nameTab = tmp;
-        tmp2 = (void **) xmlRealloc((void * *)ctxt->pushTab,
-                                    ctxt->nameMax * 4 *
+        tmp2 = (xmlStartTag *) xmlRealloc((void * *)ctxt->pushTab,
+                                    ctxt->nameMax *
                                     sizeof(ctxt->pushTab[0]));
         if (tmp2 == NULL) {
 	    ctxt->nameMax /= 2;
@@ -1870,17 +1879,18 @@
         }
 	ctxt->pushTab = tmp2;
     } else if (ctxt->pushTab == NULL) {
-        ctxt->pushTab = (void **) xmlMalloc(ctxt->nameMax * 4 *
+        ctxt->pushTab = (xmlStartTag *) xmlMalloc(ctxt->nameMax *
                                             sizeof(ctxt->pushTab[0]));
         if (ctxt->pushTab == NULL)
             goto mem_error;
     }
     ctxt->nameTab[ctxt->nameNr] = value;
     ctxt->name = value;
-    ctxt->pushTab[ctxt->nameNr * 4] = (void *) prefix;
-    ctxt->pushTab[ctxt->nameNr * 4 + 1] = (void *) URI;
-    ctxt->pushTab[ctxt->nameNr * 4 + 2] = (void *) (ptrdiff_t) line;
-    ctxt->pushTab[ctxt->nameNr * 4 + 3] = (void *) (ptrdiff_t) nsNr;
+    tag = &ctxt->pushTab[ctxt->nameNr];
+    tag->prefix = prefix;
+    tag->URI = URI;
+    tag->line = line;
+    tag->nsNr = nsNr;
     return (ctxt->nameNr++);
 mem_error:
     xmlErrMemory(ctxt, NULL);
@@ -9652,10 +9662,8 @@
  */
 
 static void
-xmlParseEndTag2(xmlParserCtxtPtr ctxt, const xmlChar *prefix,
-                const xmlChar *URI, int line, int nsNr, int tlen) {
+xmlParseEndTag2(xmlParserCtxtPtr ctxt, const xmlStartTag *tag) {
     const xmlChar *name;
-    size_t curLength;
 
     GROW;
     if ((RAW != '<') || (NXT(1) != '/')) {
@@ -9664,24 +9672,10 @@
     }
     SKIP(2);
 
-    curLength = ctxt->input->end - ctxt->input->cur;
-    if ((tlen > 0) && (curLength >= (size_t)tlen) &&
-        (xmlStrncmp(ctxt->input->cur, ctxt->name, tlen) == 0)) {
-        if ((curLength >= (size_t)(tlen + 1)) &&
-	    (ctxt->input->cur[tlen] == '>')) {
-	    ctxt->input->cur += tlen + 1;
-	    ctxt->input->col += tlen + 1;
-	    goto done;
-	}
-	ctxt->input->cur += tlen;
-	ctxt->input->col += tlen;
-	name = (xmlChar*)1;
-    } else {
-	if (prefix == NULL)
-	    name = xmlParseNameAndCompare(ctxt, ctxt->name);
-	else
-	    name = xmlParseQNameAndCompare(ctxt, ctxt->name, prefix);
-    }
+    if (tag->prefix == NULL)
+        name = xmlParseNameAndCompare(ctxt, ctxt->name);
+    else
+        name = xmlParseQNameAndCompare(ctxt, ctxt->name, tag->prefix);
 
     /*
      * We should definitely be at the ending "S? '>'" part
@@ -9703,25 +9697,22 @@
      */
     if (name != (xmlChar*)1) {
         if (name == NULL) name = BAD_CAST "unparsable";
-        if ((line == 0) && (ctxt->node != NULL))
-            line = ctxt->node->line;
         xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NAME_MISMATCH,
 		     "Opening and ending tag mismatch: %s line %d and %s\n",
-		                ctxt->name, line, name);
+		                ctxt->name, tag->line, name);
     }
 
     /*
      * SAX: End of Tag
      */
-done:
     if ((ctxt->sax != NULL) && (ctxt->sax->endElementNs != NULL) &&
 	(!ctxt->disableSAX))
-	ctxt->sax->endElementNs(ctxt->userData, ctxt->name, prefix, URI);
+	ctxt->sax->endElementNs(ctxt->userData, ctxt->name, tag->prefix,
+                                tag->URI);
 
     spacePop(ctxt);
-    if (nsNr != 0)
-	nsPop(ctxt, nsNr);
-    return;
+    if (tag->nsNr != 0)
+	nsPop(ctxt, tag->nsNr);
 }
 
 /**
@@ -9937,7 +9928,7 @@
 
     if ((ctxt->instate != XML_PARSER_EOF) && (ctxt->nameNr > nameNr)) {
         const xmlChar *name = ctxt->nameTab[ctxt->nameNr - 1];
-        int line = (ptrdiff_t) ctxt->pushTab[ctxt->nameNr * 4 - 2];
+        int line = ctxt->pushTab[ctxt->nameNr - 1].line;
         xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NOT_FINISHED,
                 "Premature end of data in tag %s line %d\n",
 		name, line, NULL);
@@ -9969,7 +9960,7 @@
 
     if (CUR == 0) {
         const xmlChar *name = ctxt->nameTab[ctxt->nameNr - 1];
-        int line = (ptrdiff_t) ctxt->pushTab[ctxt->nameNr * 4 - 2];
+        int line = ctxt->pushTab[ctxt->nameNr - 1].line;
         xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NOT_FINISHED,
                 "Premature end of data in tag %s line %d\n",
 		name, line, NULL);
@@ -10132,11 +10123,7 @@
      * parse the end of tag: '</' should be here.
      */
     if (ctxt->sax2) {
-        const xmlChar *prefix = ctxt->pushTab[ctxt->nameNr * 4 - 4];
-        const xmlChar *URI = ctxt->pushTab[ctxt->nameNr * 4 - 3];
-        int line = (ptrdiff_t) ctxt->pushTab[ctxt->nameNr * 4 - 2];
-        int nsNr = (ptrdiff_t) ctxt->pushTab[ctxt->nameNr * 4 - 1];
-	xmlParseEndTag2(ctxt, prefix, URI, line, nsNr, 0);
+	xmlParseEndTag2(ctxt, &ctxt->pushTab[ctxt->nameNr - 1]);
 	namePop(ctxt);
     }
 #ifdef LIBXML_SAX1_ENABLED
@@ -11632,13 +11619,7 @@
 		    }
 		}
 		if (ctxt->sax2) {
-		    xmlParseEndTag2(ctxt,
-		            (void *) ctxt->pushTab[ctxt->nameNr * 4 - 4],
-		            (void *) ctxt->pushTab[ctxt->nameNr * 4 - 3],
-                            (int) (ptrdiff_t)
-                                ctxt->pushTab[ctxt->nameNr * 4 - 2],
-		            (int) (ptrdiff_t)
-                                ctxt->pushTab[ctxt->nameNr * 4 - 1], 0);
+	            xmlParseEndTag2(ctxt, &ctxt->pushTab[ctxt->nameNr - 1]);
 		    nameNsPop(ctxt);
 		}
 #ifdef LIBXML_SAX1_ENABLED