From a0116212e6dde5efe311e8240e45ae1477f8988f Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Sun, 4 Aug 2013 20:28:19 +0200
Subject: [PATCH 07/14] Separate function for predicate matching in patterns

No functional change, only make the predicate matching code more
readable.
---
 libxslt/pattern.c | 546 +++++++++++++++++++++++++++---------------------------
 1 file changed, 274 insertions(+), 272 deletions(-)

diff --git a/libxslt/pattern.c b/libxslt/pattern.c
index 63ec25a..414363b 100644
--- a/libxslt/pattern.c
+++ b/libxslt/pattern.c
@@ -621,6 +621,278 @@ xsltTestCompMatchDirect(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,
 }
 
 /**
+ * xsltTestPredicateMatch:
+ * @ctxt: a XSLT process context
+ * @comp: the precompiled pattern
+ * @node: a node
+ * @step: the predicate step
+ * @sel:  the previous step
+ *
+ * Test whether the node matches the predicate
+ *
+ * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure
+ */
+static int
+xsltTestPredicateMatch(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,
+                       xmlNodePtr node, xsltStepOpPtr step,
+                       xsltStepOpPtr sel) {
+    xmlNodePtr oldNode;
+    xmlDocPtr doc;
+    int oldCS, oldCP;
+    int pos = 0, len = 0;
+    int isRVT;
+    int match;
+
+    if (step->value == NULL)
+        return(0);
+    if (step->comp == NULL)
+        return(0);
+
+    doc = node->doc;
+    if (XSLT_IS_RES_TREE_FRAG(doc))
+        isRVT = 1;
+    else
+        isRVT = 0;
+
+    /*
+     * Depending on the last selection, one may need to
+     * recompute contextSize and proximityPosition.
+     */
+    oldCS = ctxt->xpathCtxt->contextSize;
+    oldCP = ctxt->xpathCtxt->proximityPosition;
+    if ((sel != NULL) &&
+        (sel->op == XSLT_OP_ELEM) &&
+        (sel->value != NULL) &&
+        (node->type == XML_ELEMENT_NODE) &&
+        (node->parent != NULL)) {
+        xmlNodePtr previous;
+        int nocache = 0;
+
+        previous = (xmlNodePtr)
+            XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);
+        if ((previous != NULL) &&
+            (previous->parent == node->parent)) {
+            /*
+             * just walk back to adjust the index
+             */
+            int indx = 0;
+            xmlNodePtr sibling = node;
+
+            while (sibling != NULL) {
+                if (sibling == previous)
+                    break;
+                if ((sibling->type == XML_ELEMENT_NODE) &&
+                    (previous->name != NULL) &&
+                    (sibling->name != NULL) &&
+                    (previous->name[0] == sibling->name[0]) &&
+                    (xmlStrEqual(previous->name, sibling->name)))
+                {
+                    if ((sel->value2 == NULL) ||
+                        ((sibling->ns != NULL) &&
+                         (xmlStrEqual(sel->value2, sibling->ns->href))))
+                        indx++;
+                }
+                sibling = sibling->prev;
+            }
+            if (sibling == NULL) {
+                /* hum going backward in document order ... */
+                indx = 0;
+                sibling = node;
+                while (sibling != NULL) {
+                    if (sibling == previous)
+                        break;
+                    if ((sibling->type == XML_ELEMENT_NODE) &&
+                        (previous->name != NULL) &&
+                        (sibling->name != NULL) &&
+                        (previous->name[0] == sibling->name[0]) &&
+                        (xmlStrEqual(previous->name, sibling->name)))
+                    {
+                        if ((sel->value2 == NULL) ||
+                            ((sibling->ns != NULL) &&
+                            (xmlStrEqual(sel->value2,
+                            sibling->ns->href))))
+                        {
+                            indx--;
+                        }
+                    }
+                    sibling = sibling->next;
+                }
+            }
+            if (sibling != NULL) {
+                pos = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) + indx;
+                /*
+                 * If the node is in a Value Tree we need to
+                 * save len, but cannot cache the node!
+                 * (bugs 153137 and 158840)
+                 */
+                if (node->doc != NULL) {
+                    len = XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival);
+                    if (!isRVT) {
+                        XSLT_RUNTIME_EXTRA(ctxt,
+                            sel->previousExtra, ptr) = node;
+                        XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = pos;
+                    }
+                }
+            } else
+                pos = 0;
+        } else {
+            /*
+             * recompute the index
+             */
+            xmlNodePtr parent = node->parent;
+            xmlNodePtr siblings = NULL;
+
+            if (parent) siblings = parent->children;
+
+            while (siblings != NULL) {
+                if (siblings->type == XML_ELEMENT_NODE) {
+                    if (siblings == node) {
+                        len++;
+                        pos = len;
+                    } else if ((node->name != NULL) &&
+                               (siblings->name != NULL) &&
+                        (node->name[0] == siblings->name[0]) &&
+                        (xmlStrEqual(node->name, siblings->name))) {
+                        if ((sel->value2 == NULL) ||
+                            ((siblings->ns != NULL) &&
+                             (xmlStrEqual(sel->value2, siblings->ns->href))))
+                            len++;
+                    }
+                }
+                siblings = siblings->next;
+            }
+            if ((parent == NULL) || (node->doc == NULL))
+                nocache = 1;
+            else {
+                while (parent->parent != NULL)
+                    parent = parent->parent;
+                if (((parent->type != XML_DOCUMENT_NODE) &&
+                     (parent->type != XML_HTML_DOCUMENT_NODE)) ||
+                     (parent != (xmlNodePtr) node->doc))
+                    nocache = 1;
+            }
+        }
+        if (pos != 0) {
+            ctxt->xpathCtxt->contextSize = len;
+            ctxt->xpathCtxt->proximityPosition = pos;
+            /*
+             * If the node is in a Value Tree we cannot
+             * cache it !
+             */
+            if ((!isRVT) && (node->doc != NULL) &&
+                (nocache == 0)) {
+                XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) = node;
+                XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = pos;
+                XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) = len;
+            }
+        }
+    } else if ((sel != NULL) && (sel->op == XSLT_OP_ALL) &&
+               (node->type == XML_ELEMENT_NODE)) {
+        xmlNodePtr previous;
+        int nocache = 0;
+
+        previous = (xmlNodePtr)
+            XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);
+        if ((previous != NULL) &&
+            (previous->parent == node->parent)) {
+            /*
+             * just walk back to adjust the index
+             */
+            int indx = 0;
+            xmlNodePtr sibling = node;
+
+            while (sibling != NULL) {
+                if (sibling == previous)
+                    break;
+                if (sibling->type == XML_ELEMENT_NODE)
+                    indx++;
+                sibling = sibling->prev;
+            }
+            if (sibling == NULL) {
+                /* hum going backward in document order ... */
+                indx = 0;
+                sibling = node;
+                while (sibling != NULL) {
+                    if (sibling == previous)
+                        break;
+                    if (sibling->type == XML_ELEMENT_NODE)
+                        indx--;
+                    sibling = sibling->next;
+                }
+            }
+            if (sibling != NULL) {
+                pos = XSLT_RUNTIME_EXTRA(ctxt,
+                    sel->indexExtra, ival) + indx;
+                /*
+                 * If the node is in a Value Tree we cannot
+                 * cache it !
+                 */
+                if ((node->doc != NULL) && !isRVT) {
+                    len = XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival);
+                    XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) = node;
+                    XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = pos;
+                }
+            } else
+                pos = 0;
+        } else {
+            /*
+             * recompute the index
+             */
+            xmlNodePtr parent = node->parent;
+            xmlNodePtr siblings = NULL;
+
+            if (parent) siblings = parent->children;
+
+            while (siblings != NULL) {
+                if (siblings->type == XML_ELEMENT_NODE) {
+                    len++;
+                    if (siblings == node) {
+                        pos = len;
+                    }
+                }
+                siblings = siblings->next;
+            }
+            if ((parent == NULL) || (node->doc == NULL))
+                nocache = 1;
+            else {
+                while (parent->parent != NULL)
+                    parent = parent->parent;
+                if (((parent->type != XML_DOCUMENT_NODE) &&
+                     (parent->type != XML_HTML_DOCUMENT_NODE)) ||
+                     (parent != (xmlNodePtr) node->doc))
+                    nocache = 1;
+            }
+        }
+        if (pos != 0) {
+            ctxt->xpathCtxt->contextSize = len;
+            ctxt->xpathCtxt->proximityPosition = pos;
+            /*
+             * If the node is in a Value Tree we cannot
+             * cache it !
+             */
+            if ((node->doc != NULL) && (nocache == 0) && !isRVT) {
+                XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) = node;
+                XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = pos;
+                XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) = len;
+            }
+        }
+    }
+
+    oldNode = ctxt->node;
+    ctxt->node = node;
+
+    match = xsltEvalXPathPredicate(ctxt, step->comp, comp->nsList, comp->nsNr);
+
+    if (pos != 0) {
+        ctxt->xpathCtxt->contextSize = oldCS;
+        ctxt->xpathCtxt->proximityPosition = oldCP;
+    }
+    ctxt->node = oldNode;
+
+    return match;
+}
+
+/**
  * xsltTestCompMatch:
  * @ctxt:  a XSLT process context
  * @comp: the precompiled pattern
@@ -854,12 +1126,6 @@ restart:
 		    goto rollback;
 		break;
 	    case XSLT_OP_PREDICATE: {
-		xmlNodePtr oldNode;
-		xmlDocPtr doc;
-		int oldCS, oldCP;
-		int pos = 0, len = 0;
-		int isRVT;
-
 		/*
 		 * when there is cascading XSLT_OP_PREDICATE, then use a
 		 * direct computation approach. It's not done directly
@@ -875,274 +1141,10 @@ restart:
 						   comp->nsList, comp->nsNr));
 		}
 
-		doc = node->doc;
-		if (XSLT_IS_RES_TREE_FRAG(doc))
-		    isRVT = 1;
-		else
-		    isRVT = 0;
-
-		/*
-		 * Depending on the last selection, one may need to
-		 * recompute contextSize and proximityPosition.
-		 */
-		oldCS = ctxt->xpathCtxt->contextSize;
-		oldCP = ctxt->xpathCtxt->proximityPosition;
-		if ((sel != NULL) &&
-		    (sel->op == XSLT_OP_ELEM) &&
-		    (sel->value != NULL) &&
-		    (node->type == XML_ELEMENT_NODE) &&
-		    (node->parent != NULL)) {
-		    xmlNodePtr previous;
-		    int nocache = 0;
-
-		    previous = (xmlNodePtr)
-			XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);
-		    if ((previous != NULL) &&
-			(previous->parent == node->parent)) {
-			/*
-			 * just walk back to adjust the index
-			 */
-			int indx = 0;
-			xmlNodePtr sibling = node;
-
-			while (sibling != NULL) {
-			    if (sibling == previous)
-				break;
-			    if ((sibling->type == XML_ELEMENT_NODE) &&
-				(previous->name != NULL) &&
-				(sibling->name != NULL) &&
-				(previous->name[0] == sibling->name[0]) &&
-				(xmlStrEqual(previous->name, sibling->name)))
-			    {
-				if ((sel->value2 == NULL) ||
-				    ((sibling->ns != NULL) &&
-				     (xmlStrEqual(sel->value2,
-						  sibling->ns->href))))
-				    indx++;
-			    }
-			    sibling = sibling->prev;
-			}
-			if (sibling == NULL) {
-			    /* hum going backward in document order ... */
-			    indx = 0;
-			    sibling = node;
-			    while (sibling != NULL) {
-				if (sibling == previous)
-				    break;
-				if ((sibling->type == XML_ELEMENT_NODE) &&
-				    (previous->name != NULL) &&
-				    (sibling->name != NULL) &&
-				    (previous->name[0] == sibling->name[0]) &&
-				    (xmlStrEqual(previous->name, sibling->name)))
-				{
-				    if ((sel->value2 == NULL) ||
-					((sibling->ns != NULL) &&
-					(xmlStrEqual(sel->value2,
-					sibling->ns->href))))
-				    {
-					indx--;
-				    }
-				}
-				sibling = sibling->next;
-			    }
-			}
-			if (sibling != NULL) {
-		            pos = XSLT_RUNTIME_EXTRA(ctxt,
-                                sel->indexExtra, ival) + indx;
-			    /*
-			     * If the node is in a Value Tree we need to
-			     * save len, but cannot cache the node!
-			     * (bugs 153137 and 158840)
-			     */
-			    if (node->doc != NULL) {
-				len = XSLT_RUNTIME_EXTRA(ctxt,
-				        sel->lenExtra, ival);
-				if (!isRVT) {
-				    XSLT_RUNTIME_EXTRA(ctxt,
-					sel->previousExtra, ptr) = node;
-				    XSLT_RUNTIME_EXTRA(ctxt,
-				        sel->indexExtra, ival) = pos;
-				}
-			    }
-			} else
-			    pos = 0;
-		    } else {
-			/*
-			 * recompute the index
-			 */
-			xmlNodePtr parent = node->parent;
-			xmlNodePtr siblings = NULL;
-
-                        if (parent) siblings = parent->children;
-
-			while (siblings != NULL) {
-			    if (siblings->type == XML_ELEMENT_NODE) {
-				if (siblings == node) {
-				    len++;
-				    pos = len;
-				} else if ((node->name != NULL) &&
-					   (siblings->name != NULL) &&
-				    (node->name[0] == siblings->name[0]) &&
-				    (xmlStrEqual(node->name, siblings->name))) {
-				    if ((sel->value2 == NULL) ||
-					((siblings->ns != NULL) &&
-					 (xmlStrEqual(sel->value2,
-						      siblings->ns->href))))
-					len++;
-				}
-			    }
-			    siblings = siblings->next;
-			}
-			if ((parent == NULL) || (node->doc == NULL))
-			    nocache = 1;
-			else {
-			    while (parent->parent != NULL)
-				parent = parent->parent;
-			    if (((parent->type != XML_DOCUMENT_NODE) &&
-				 (parent->type != XML_HTML_DOCUMENT_NODE)) ||
-				 (parent != (xmlNodePtr) node->doc))
-				nocache = 1;
-			}
-		    }
-		    if (pos != 0) {
-			ctxt->xpathCtxt->contextSize = len;
-			ctxt->xpathCtxt->proximityPosition = pos;
-			/*
-			 * If the node is in a Value Tree we cannot
-			 * cache it !
-			 */
-			if ((!isRVT) && (node->doc != NULL) &&
-			    (nocache == 0)) {
-			    XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) =
-				node;
-			    XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) =
-				pos;
-			    XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) =
-				len;
-			}
-		    }
-		} else if ((sel != NULL) && (sel->op == XSLT_OP_ALL) &&
-			   (node->type == XML_ELEMENT_NODE)) {
-		    xmlNodePtr previous;
-		    int nocache = 0;
-
-		    previous = (xmlNodePtr)
-			XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);
-		    if ((previous != NULL) &&
-			(previous->parent == node->parent)) {
-			/*
-			 * just walk back to adjust the index
-			 */
-			int indx = 0;
-			xmlNodePtr sibling = node;
-
-			while (sibling != NULL) {
-			    if (sibling == previous)
-				break;
-			    if (sibling->type == XML_ELEMENT_NODE)
-				indx++;
-			    sibling = sibling->prev;
-			}
-			if (sibling == NULL) {
-			    /* hum going backward in document order ... */
-			    indx = 0;
-			    sibling = node;
-			    while (sibling != NULL) {
-				if (sibling == previous)
-				    break;
-				if (sibling->type == XML_ELEMENT_NODE)
-				    indx--;
-				sibling = sibling->next;
-			    }
-			}
-			if (sibling != NULL) {
-			    pos = XSLT_RUNTIME_EXTRA(ctxt,
-                                sel->indexExtra, ival) + indx;
-			    /*
-			     * If the node is in a Value Tree we cannot
-			     * cache it !
-			     */
-			    if ((node->doc != NULL) && !isRVT) {
-				len = XSLT_RUNTIME_EXTRA(ctxt,
-				        sel->lenExtra, ival);
-				XSLT_RUNTIME_EXTRA(ctxt,
-					sel->previousExtra, ptr) = node;
-				XSLT_RUNTIME_EXTRA(ctxt,
-					sel->indexExtra, ival) = pos;
-			    }
-			} else
-			    pos = 0;
-		    } else {
-			/*
-			 * recompute the index
-			 */
-			xmlNodePtr parent = node->parent;
-			xmlNodePtr siblings = NULL;
-
-                        if (parent) siblings = parent->children;
-
-			while (siblings != NULL) {
-			    if (siblings->type == XML_ELEMENT_NODE) {
-				len++;
-				if (siblings == node) {
-				    pos = len;
-				}
-			    }
-			    siblings = siblings->next;
-			}
-			if ((parent == NULL) || (node->doc == NULL))
-			    nocache = 1;
-			else {
-			    while (parent->parent != NULL)
-				parent = parent->parent;
-			    if (((parent->type != XML_DOCUMENT_NODE) &&
-				 (parent->type != XML_HTML_DOCUMENT_NODE)) ||
-				 (parent != (xmlNodePtr) node->doc))
-				nocache = 1;
-			}
-		    }
-		    if (pos != 0) {
-			ctxt->xpathCtxt->contextSize = len;
-			ctxt->xpathCtxt->proximityPosition = pos;
-			/*
-			 * If the node is in a Value Tree we cannot
-			 * cache it !
-			 */
-			if ((node->doc != NULL) && (nocache == 0) && !isRVT) {
-			    XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) =
-				node;
-			    XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) =
-				pos;
-			    XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) =
-				len;
-			}
-		    }
-		}
-		oldNode = ctxt->node;
-		ctxt->node = node;
-
-		if (step->value == NULL)
-		    goto wrong_index;
-		if (step->comp == NULL)
-		    goto wrong_index;
-
-		if (!xsltEvalXPathPredicate(ctxt, step->comp, comp->nsList,
-			                    comp->nsNr))
-		    goto wrong_index;
+		if (!xsltTestPredicateMatch(ctxt, comp, node, step, sel))
+		    goto rollback;
 
-		if (pos != 0) {
-		    ctxt->xpathCtxt->contextSize = oldCS;
-		    ctxt->xpathCtxt->proximityPosition = oldCP;
-		}
-		ctxt->node = oldNode;
 		break;
-wrong_index:
-		if (pos != 0) {
-		    ctxt->xpathCtxt->contextSize = oldCS;
-		    ctxt->xpathCtxt->proximityPosition = oldCP;
-		}
-		ctxt->node = oldNode;
-		goto rollback;
 	    }
             case XSLT_OP_PI:
 		if (node->type != XML_PI_NODE)
-- 
1.8.4.1

