xml/libxml2libs/src/libxml2/libxml2_xpointer.c
changeset 0 e35f40988205
equal deleted inserted replaced
-1:000000000000 0:e35f40988205
       
     1 /*
       
     2  * libxml2_xpointer.c : Code to handle XML Pointer
       
     3  *
       
     4  * Base implementation was made accordingly to
       
     5  * W3C Candidate Recommendation 7 June 2000
       
     6  * http://www.w3.org/TR/2000/CR-xptr-20000607
       
     7  *
       
     8  * Added support for the element() scheme described in:
       
     9  * W3C Proposed Recommendation 13 November 2002
       
    10  * http://www.w3.org/TR/2002/PR-xptr-element-20021113/
       
    11  *
       
    12  * See Copyright for the status of this software.
       
    13  *
       
    14  * daniel@veillard.com
       
    15  * Portion Copyright © 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. 
       
    16  */
       
    17 
       
    18 #define IN_LIBXML
       
    19 #include "xmlenglibxml.h"
       
    20 
       
    21 /*
       
    22  * 
       
    23  *       
       
    24  * 
       
    25  *       
       
    26  *       
       
    27  */
       
    28 
       
    29 #include <string.h>
       
    30 #include <stdapis/libxml2/libxml2_xpointer.h>
       
    31 #include <stdapis/libxml2/libxml2_xmlmemory.h>
       
    32 #include <stdapis/libxml2/libxml2_parserinternals.h>
       
    33 #include <stdapis/libxml2/libxml2_uri.h>
       
    34 #include <stdapis/libxml2/libxml2_xpath.h>
       
    35 #include <stdapis/libxml2/libxml2_xpathinternals.h>
       
    36 #include <stdapis/libxml2/libxml2_xmlerror.h>
       
    37 #include "libxml2_xmlerror2.h"
       
    38 #include <stdapis/libxml2/libxml2_globals.h>
       
    39 
       
    40 #ifdef LIBXML_XPTR_ENABLED
       
    41 
       
    42 /* Add support of the xmlns() xpointer scheme to initialize the namespaces */
       
    43 #define XPTR_XMLNS_SCHEME
       
    44 
       
    45 /* #define DEBUG_RANGES */
       
    46 #ifdef DEBUG_RANGES
       
    47 #ifdef LIBXML_DEBUG_ENABLED
       
    48 #include "libxml2_debugxml.h"
       
    49 #endif
       
    50 #endif
       
    51 
       
    52 #define TODO                                                            \
       
    53     xmlGenericError(xmlGenericErrorContext,                             \
       
    54             "Unimplemented block at %s:%d\n",                           \
       
    55             __FILE__, __LINE__);
       
    56 
       
    57 #define STRANGE                                                         \
       
    58     xmlGenericError(xmlGenericErrorContext,                             \
       
    59             "Internal error at %s:%d\n",                                \
       
    60             __FILE__, __LINE__);
       
    61 
       
    62 /************************************************************************
       
    63  *                                                                      *
       
    64  *              Some factorized error routines                          *
       
    65  *                                                                      *
       
    66  ************************************************************************/
       
    67 
       
    68 /**
       
    69  * xmlXPtrErrMemory:
       
    70  * @param extra extra informations
       
    71  *
       
    72  * Handle a redefinition of attribute error
       
    73  */
       
    74 static void
       
    75 xmlXPtrErrMemory(const char *extra)
       
    76 {
       
    77     __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_XPOINTER,
       
    78                     XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0, extra,
       
    79                     NULL, NULL, 0, 0,
       
    80                     "Memory allocation failed : %s\n", extra);
       
    81 }
       
    82 
       
    83 /**
       
    84  * xmlXPtrErr:
       
    85  * @param ctxt an XPTR evaluation context
       
    86  * @param extra extra informations
       
    87  *
       
    88  * Handle a redefinition of attribute error
       
    89  */
       
    90 static void
       
    91 xmlXPtrErr(xmlXPathParserContextPtr ctxt, int error,
       
    92            const char * msg, const xmlChar *extra)
       
    93 {
       
    94     if (ctxt != NULL)
       
    95         ctxt->error = error;
       
    96     if ((ctxt == NULL) || (ctxt->context == NULL)) {
       
    97         __xmlRaiseError(NULL, NULL, NULL,
       
    98                         NULL, NULL, XML_FROM_XPOINTER, error,
       
    99                         XML_ERR_ERROR, NULL, 0,
       
   100                         (const char *) extra, NULL, NULL, 0, 0,
       
   101                         msg, extra);
       
   102         return;
       
   103     }
       
   104     ctxt->context->lastError.domain = XML_FROM_XPOINTER;
       
   105     ctxt->context->lastError.code = error;
       
   106     ctxt->context->lastError.level = XML_ERR_ERROR;
       
   107     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
       
   108     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
       
   109     ctxt->context->lastError.node = ctxt->context->debugNode;
       
   110     if (ctxt->context->error != NULL) {
       
   111         ctxt->context->error(ctxt->context->userData,
       
   112                              &ctxt->context->lastError);
       
   113     } else {
       
   114         __xmlRaiseError(NULL, NULL, NULL,
       
   115                         NULL, ctxt->context->debugNode, XML_FROM_XPOINTER,
       
   116                         error, XML_ERR_ERROR, NULL, 0,
       
   117                         (const char *) extra, (const char *) ctxt->base, NULL,
       
   118                         ctxt->cur - ctxt->base, 0,
       
   119                         msg, extra);
       
   120     }
       
   121 }
       
   122 
       
   123 /************************************************************************
       
   124  *                                                                      *
       
   125  *              A few helper functions for child sequences              *
       
   126  *                                                                      *
       
   127  ************************************************************************/
       
   128 /* xmlXPtrAdvanceNode is a private function, but used by xinclude.c */
       
   129 xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur, int *level);
       
   130 /**
       
   131  * xmlXPtrGetArity:
       
   132  * @param cur the node
       
   133  *
       
   134  * Returns the number of child for an element, -1 in case of error
       
   135  */
       
   136 static int
       
   137 xmlXPtrGetArity(xmlNodePtr cur) {
       
   138     int i;
       
   139     if (cur == NULL)
       
   140         return(-1);
       
   141     cur = cur->children;
       
   142     for (i = 0;cur != NULL;cur = cur->next) {
       
   143         if ((cur->type == XML_ELEMENT_NODE) ||
       
   144             (cur->type == XML_DOCUMENT_NODE) ||
       
   145             (cur->type == XML_HTML_DOCUMENT_NODE)) {
       
   146             i++;
       
   147         }
       
   148     }
       
   149     return(i);
       
   150 }
       
   151 
       
   152 /**
       
   153  * xmlXPtrGetIndex:
       
   154  * @param cur the node
       
   155  *
       
   156  * Returns the index of the node in its parent children list, -1
       
   157  *         in case of error
       
   158  */
       
   159 static int
       
   160 xmlXPtrGetIndex(xmlNodePtr cur) {
       
   161     int i;
       
   162     if (cur == NULL)
       
   163         return(-1);
       
   164     for (i = 1;cur != NULL;cur = cur->prev) {
       
   165         if ((cur->type == XML_ELEMENT_NODE) ||
       
   166             (cur->type == XML_DOCUMENT_NODE) ||
       
   167             (cur->type == XML_HTML_DOCUMENT_NODE)) {
       
   168             i++;
       
   169         }
       
   170     }
       
   171     return(i);
       
   172 }
       
   173 
       
   174 /**
       
   175  * xmlXPtrGetNthChild:
       
   176  * @param cur the node
       
   177  * @param no the child number
       
   178  *
       
   179  * Returns the no'th element child of cur or NULL
       
   180  */
       
   181 static xmlNodePtr
       
   182 xmlXPtrGetNthChild(xmlNodePtr cur, int no) {
       
   183     int i;
       
   184     if (cur == NULL)
       
   185         return(cur);
       
   186     cur = cur->children;
       
   187     for (i = 0;i <= no;cur = cur->next) {
       
   188         if (cur == NULL)
       
   189             return(cur);
       
   190         if ((cur->type == XML_ELEMENT_NODE) ||
       
   191             (cur->type == XML_DOCUMENT_NODE) ||
       
   192             (cur->type == XML_HTML_DOCUMENT_NODE)) {
       
   193             i++;
       
   194             if (i == no)
       
   195                 break;
       
   196         }
       
   197     }
       
   198     return(cur);
       
   199 }
       
   200 
       
   201 /************************************************************************
       
   202  *                                                                      *
       
   203  *              Handling of XPointer specific types                     *
       
   204  *                                                                      *
       
   205  ************************************************************************/
       
   206 
       
   207 /**
       
   208  * xmlXPtrCmpPoints:
       
   209  * @param node1 the first node
       
   210  * @param index1 the first index
       
   211  * @param node2 the second node
       
   212  * @param index2 the second index
       
   213  *
       
   214  * Compare two points w.r.t document order
       
   215  *
       
   216  * Returns -2 in case of error 1 if first point < second point, 0 if
       
   217  *         that's the same point, -1 otherwise
       
   218  */
       
   219 static int
       
   220 xmlXPtrCmpPoints(xmlNodePtr node1, int index1, xmlNodePtr node2, int index2) {
       
   221     if ((node1 == NULL) || (node2 == NULL))
       
   222         return(-2);
       
   223     /*
       
   224      * a couple of optimizations which will avoid computations in most cases
       
   225      */
       
   226     if (node1 == node2) {
       
   227         if (index1 < index2)
       
   228             return(1);
       
   229         if (index1 > index2)
       
   230             return(-1);
       
   231         return(0);
       
   232     }
       
   233     return(xmlXPathCmpNodes(node1, node2));
       
   234 }
       
   235 
       
   236 /**
       
   237  * xmlXPtrNewPoint:
       
   238  * @param node the xmlNodePtr
       
   239  * @param indx the indx within the node
       
   240  *
       
   241  * Create a new xmlXPathObjectPtr of type point
       
   242  *
       
   243  * Returns the newly created object.
       
   244  */
       
   245 static xmlXPathObjectPtr
       
   246 xmlXPtrNewPoint(xmlNodePtr node, int indx) {
       
   247     xmlXPathObjectPtr ret;
       
   248 
       
   249     if (node == NULL)
       
   250         return(NULL);
       
   251     if (indx < 0)
       
   252         return(NULL);
       
   253 
       
   254     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
       
   255     if (ret == NULL) {
       
   256         xmlXPtrErrMemory("allocating point");
       
   257         return(NULL);
       
   258     }
       
   259     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
       
   260     ret->type = XPATH_POINT;
       
   261     ret->user = (void *) node;
       
   262     ret->index = indx;
       
   263     return(ret);
       
   264 }
       
   265 
       
   266 /**
       
   267  * xmlXPtrRangeCheckOrder:
       
   268  * @param range an object range
       
   269  *
       
   270  * Make sure the points in the range are in the right order
       
   271  */
       
   272 static void
       
   273 xmlXPtrRangeCheckOrder(xmlXPathObjectPtr range) {
       
   274     int tmp;
       
   275     xmlNodePtr tmp2;
       
   276     if (range == NULL)
       
   277         return;
       
   278     if (range->type != XPATH_RANGE)
       
   279         return;
       
   280     if (range->user2 == NULL)
       
   281         return;
       
   282     tmp = xmlXPtrCmpPoints(range->user, range->index,
       
   283                              range->user2, range->index2);
       
   284     if (tmp == -1) {
       
   285         tmp2 = range->user;
       
   286         range->user = range->user2;
       
   287         range->user2 = tmp2;
       
   288         tmp = range->index;
       
   289         range->index = range->index2;
       
   290         range->index2 = tmp;
       
   291     }
       
   292 }
       
   293 
       
   294 /**
       
   295  * xmlXPtrRangesEqual:
       
   296  * @param range1 the first range
       
   297  * @param range2 the second range
       
   298  *
       
   299  * Compare two ranges
       
   300  *
       
   301  * Returns 1 if equal, 0 otherwise
       
   302  */
       
   303 static int
       
   304 xmlXPtrRangesEqual(xmlXPathObjectPtr range1, xmlXPathObjectPtr range2) {
       
   305     if (range1 == range2)
       
   306         return(1);
       
   307     if ((range1 == NULL) || (range2 == NULL))
       
   308         return(0);
       
   309     if (range1->type != range2->type)
       
   310         return(0);
       
   311     if (range1->type != XPATH_RANGE)
       
   312         return(0);
       
   313     if (range1->user != range2->user)
       
   314         return(0);
       
   315     if (range1->index != range2->index)
       
   316         return(0);
       
   317     if (range1->user2 != range2->user2)
       
   318         return(0);
       
   319     if (range1->index2 != range2->index2)
       
   320         return(0);
       
   321     return(1);
       
   322 }
       
   323 
       
   324 /**
       
   325  * xmlXPtrNewRange:
       
   326  * @param start the starting node
       
   327  * @param startindex the start index
       
   328  * @param end the ending point
       
   329  * @param endindex the ending index
       
   330  *
       
   331  * Create a new xmlXPathObjectPtr of type range
       
   332  *
       
   333  * Returns the newly created object.
       
   334  */
       
   335 XMLPUBFUNEXPORT xmlXPathObjectPtr
       
   336 xmlXPtrNewRange(xmlNodePtr start, int startindex,
       
   337                 xmlNodePtr end, int endindex) {
       
   338     xmlXPathObjectPtr ret;
       
   339 
       
   340     if (start == NULL)
       
   341         return(NULL);
       
   342     if (end == NULL)
       
   343         return(NULL);
       
   344     if (startindex < 0)
       
   345         return(NULL);
       
   346     if (endindex < 0)
       
   347         return(NULL);
       
   348 
       
   349     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
       
   350     if (ret == NULL) {
       
   351         xmlXPtrErrMemory("allocating range");
       
   352         return(NULL);
       
   353     }
       
   354     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
       
   355     ret->type = XPATH_RANGE;
       
   356     ret->user = start;
       
   357     ret->index = startindex;
       
   358     ret->user2 = end;
       
   359     ret->index2 = endindex;
       
   360     xmlXPtrRangeCheckOrder(ret);
       
   361     return(ret);
       
   362 }
       
   363 
       
   364 /**
       
   365  * xmlXPtrNewRangePoints:
       
   366  * @param start the starting point
       
   367  * @param end the ending point
       
   368  *
       
   369  * Create a new xmlXPathObjectPtr of type range using 2 Points
       
   370  *
       
   371  * Returns the newly created object.
       
   372  */
       
   373 XMLPUBFUNEXPORT xmlXPathObjectPtr
       
   374 xmlXPtrNewRangePoints(xmlXPathObjectPtr start, xmlXPathObjectPtr end) {
       
   375     xmlXPathObjectPtr ret;
       
   376 
       
   377     if (start == NULL)
       
   378         return(NULL);
       
   379     if (end == NULL)
       
   380         return(NULL);
       
   381     if (start->type != XPATH_POINT)
       
   382         return(NULL);
       
   383     if (end->type != XPATH_POINT)
       
   384         return(NULL);
       
   385 
       
   386     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
       
   387     if (ret == NULL) {
       
   388         xmlXPtrErrMemory("allocating range");
       
   389         return(NULL);
       
   390     }
       
   391     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
       
   392     ret->type = XPATH_RANGE;
       
   393     ret->user = start->user;
       
   394     ret->index = start->index;
       
   395     ret->user2 = end->user;
       
   396     ret->index2 = end->index;
       
   397     xmlXPtrRangeCheckOrder(ret);
       
   398     return(ret);
       
   399 }
       
   400 
       
   401 /**
       
   402  * xmlXPtrNewRangePointNode:
       
   403  * @param start the starting point
       
   404  * @param end the ending node
       
   405  *
       
   406  * Create a new xmlXPathObjectPtr of type range from a point to a node
       
   407  *
       
   408  * Returns the newly created object.
       
   409  */
       
   410 XMLPUBFUNEXPORT xmlXPathObjectPtr
       
   411 xmlXPtrNewRangePointNode(xmlXPathObjectPtr start, xmlNodePtr end) {
       
   412     xmlXPathObjectPtr ret;
       
   413 
       
   414     if (start == NULL)
       
   415         return(NULL);
       
   416     if (end == NULL)
       
   417         return(NULL);
       
   418     if (start->type != XPATH_POINT)
       
   419         return(NULL);
       
   420 
       
   421     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
       
   422     if (ret == NULL) {
       
   423         xmlXPtrErrMemory("allocating range");
       
   424         return(NULL);
       
   425     }
       
   426     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
       
   427     ret->type = XPATH_RANGE;
       
   428     ret->user = start->user;
       
   429     ret->index = start->index;
       
   430     ret->user2 = end;
       
   431     ret->index2 = -1;
       
   432     xmlXPtrRangeCheckOrder(ret);
       
   433     return(ret);
       
   434 }
       
   435 
       
   436 /**
       
   437  * xmlXPtrNewRangeNodePoint:
       
   438  * @param start the starting node
       
   439  * @param end the ending point
       
   440  *
       
   441  * Create a new xmlXPathObjectPtr of type range from a node to a point
       
   442  *
       
   443  * Returns the newly created object.
       
   444  */
       
   445 XMLPUBFUNEXPORT xmlXPathObjectPtr
       
   446 xmlXPtrNewRangeNodePoint(xmlNodePtr start, xmlXPathObjectPtr end) {
       
   447     xmlXPathObjectPtr ret;
       
   448 
       
   449     if (start == NULL)
       
   450         return(NULL);
       
   451     if (end == NULL)
       
   452         return(NULL);
       
   453     if (start->type != XPATH_POINT)
       
   454         return(NULL);
       
   455     if (end->type != XPATH_POINT)
       
   456         return(NULL);
       
   457 
       
   458     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
       
   459     if (ret == NULL) {
       
   460         xmlXPtrErrMemory("allocating range");
       
   461         return(NULL);
       
   462     }
       
   463     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
       
   464     ret->type = XPATH_RANGE;
       
   465     ret->user = start;
       
   466     ret->index = -1;
       
   467     ret->user2 = end->user;
       
   468     ret->index2 = end->index;
       
   469     xmlXPtrRangeCheckOrder(ret);
       
   470     return(ret);
       
   471 }
       
   472 
       
   473 /**
       
   474  * xmlXPtrNewRangeNodes:
       
   475  * @param start the starting node
       
   476  * @param end the ending node
       
   477  *
       
   478  * Create a new xmlXPathObjectPtr of type range using 2 nodes
       
   479  *
       
   480  * Returns the newly created object.
       
   481  */
       
   482 XMLPUBFUNEXPORT xmlXPathObjectPtr
       
   483 xmlXPtrNewRangeNodes(xmlNodePtr start, xmlNodePtr end) {
       
   484     xmlXPathObjectPtr ret;
       
   485 
       
   486     if (start == NULL)
       
   487         return(NULL);
       
   488     if (end == NULL)
       
   489         return(NULL);
       
   490 
       
   491     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
       
   492     if (ret == NULL) {
       
   493         xmlXPtrErrMemory("allocating range");
       
   494         return(NULL);
       
   495     }
       
   496     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
       
   497     ret->type = XPATH_RANGE;
       
   498     ret->user = start;
       
   499     ret->index = -1;
       
   500     ret->user2 = end;
       
   501     ret->index2 = -1;
       
   502     xmlXPtrRangeCheckOrder(ret);
       
   503     return(ret);
       
   504 }
       
   505 
       
   506 /**
       
   507  * xmlXPtrNewCollapsedRange:
       
   508  * @param start the starting and ending node
       
   509  *
       
   510  * Create a new xmlXPathObjectPtr of type range using a single nodes
       
   511  *
       
   512  * Returns the newly created object.
       
   513  */
       
   514 XMLPUBFUNEXPORT xmlXPathObjectPtr
       
   515 xmlXPtrNewCollapsedRange(xmlNodePtr start)
       
   516 {
       
   517     xmlXPathObjectPtr ret;
       
   518 
       
   519     if (start == NULL)
       
   520         return(NULL);
       
   521 
       
   522     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
       
   523     if (!ret) {
       
   524         xmlXPtrErrMemory("allocating range");
       
   525         return(NULL);
       
   526     }
       
   527     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
       
   528     ret->type = XPATH_RANGE;
       
   529     ret->user = start;
       
   530     ret->index = -1;
       
   531     ret->user2 = NULL;
       
   532     ret->index2 = -1;
       
   533     return(ret);
       
   534 }
       
   535 
       
   536 /**
       
   537  * xmlXPtrNewRangeNodeObject:
       
   538  * @param start the starting node
       
   539  * @param end the ending object
       
   540  *
       
   541  * Create a new xmlXPathObjectPtr of type range from a not to an object
       
   542  *
       
   543  * Returns the newly created object.
       
   544  */
       
   545 XMLPUBFUNEXPORT xmlXPathObjectPtr
       
   546 xmlXPtrNewRangeNodeObject(xmlNodePtr start, xmlXPathObjectPtr end)
       
   547 {
       
   548     xmlXPathObjectPtr ret;
       
   549 
       
   550     if (!start || !end)
       
   551         return(NULL);
       
   552 
       
   553     switch (end->type) {
       
   554         case XPATH_POINT:
       
   555         case XPATH_RANGE:
       
   556             break;
       
   557         case XPATH_NODESET:
       
   558             /*
       
   559              * Empty set ...
       
   560              */
       
   561             if (end->nodesetval->nodeNr <= 0)
       
   562                 return(NULL);
       
   563             break;
       
   564         default:
       
   565             TODO
       
   566             return(NULL);
       
   567     }
       
   568 
       
   569     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
       
   570     if (ret == NULL) {
       
   571         xmlXPtrErrMemory("allocating range");
       
   572         return(NULL);
       
   573     }
       
   574     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
       
   575     ret->type = XPATH_RANGE;
       
   576     ret->user = start;
       
   577     ret->index = -1;
       
   578     switch (end->type) {
       
   579         case XPATH_POINT:
       
   580             ret->user2 = end->user;
       
   581             ret->index2 = end->index;
       
   582             break;
       
   583         case XPATH_RANGE:
       
   584             ret->user2 = end->user2;
       
   585             ret->index2 = end->index2;
       
   586             break;
       
   587         case XPATH_NODESET: {
       
   588             ret->user2 = end->nodesetval->nodeTab[end->nodesetval->nodeNr - 1];
       
   589             ret->index2 = -1;
       
   590             break;
       
   591         }
       
   592         default:
       
   593             STRANGE
       
   594             return(NULL);
       
   595     }
       
   596     xmlXPtrRangeCheckOrder(ret);
       
   597     return(ret);
       
   598 }
       
   599 
       
   600 #define XML_RANGESET_DEFAULT    10
       
   601 
       
   602 /**
       
   603  * xmlXPtrLocationSetCreate:
       
   604  * @param val an initial xmlXPathObjectPtr, or NULL
       
   605  *
       
   606  * Create a new xmlLocationSetPtr of type double and of value val
       
   607  *
       
   608  * Returns the newly created object.
       
   609  */
       
   610 XMLPUBFUNEXPORT xmlLocationSetPtr
       
   611 xmlXPtrLocationSetCreate(xmlXPathObjectPtr val) {
       
   612     xmlLocationSetPtr ret;
       
   613 
       
   614     ret = (xmlLocationSetPtr) xmlMalloc(sizeof(xmlLocationSet));
       
   615     if (ret == NULL) {
       
   616         xmlXPtrErrMemory("allocating locationset");
       
   617         return(NULL);
       
   618     }
       
   619     memset(ret, 0 , (size_t) sizeof(xmlLocationSet));
       
   620     if (val != NULL) {
       
   621         ret->locTab = (xmlXPathObjectPtr *) xmlMalloc(XML_RANGESET_DEFAULT *
       
   622                                              sizeof(xmlXPathObjectPtr));
       
   623         if (ret->locTab == NULL) {
       
   624             xmlXPtrErrMemory("allocating locationset");
       
   625             xmlFree(ret);
       
   626             return(NULL);
       
   627         }
       
   628         memset(ret->locTab, 0 ,
       
   629                XML_RANGESET_DEFAULT * (size_t) sizeof(xmlXPathObjectPtr));
       
   630         ret->locMax = XML_RANGESET_DEFAULT;
       
   631         ret->locTab[ret->locNr++] = val;
       
   632     }
       
   633     return(ret);
       
   634 }
       
   635 
       
   636 /**
       
   637  * xmlXPtrLocationSetAdd:
       
   638  * @param cur the initial range set
       
   639  * @param val a new xmlXPathObjectPtr
       
   640  *
       
   641  * add a new xmlXPathObjectPtr to an existing LocationSet
       
   642  * If the location already exist in the set val is freed.
       
   643  */
       
   644 XMLPUBFUNEXPORT void
       
   645 xmlXPtrLocationSetAdd(xmlLocationSetPtr cur, xmlXPathObjectPtr val) {
       
   646     int i;
       
   647 
       
   648     if (val == NULL) return;
       
   649 
       
   650     /*
       
   651      * check against doublons
       
   652      */
       
   653     for (i = 0;i < cur->locNr;i++) {
       
   654         if (xmlXPtrRangesEqual(cur->locTab[i], val)) {
       
   655             xmlXPathFreeObject(val);
       
   656             return;
       
   657         }
       
   658     }
       
   659 
       
   660     /*
       
   661      * grow the locTab if needed
       
   662      */
       
   663     if (cur->locMax == 0) {
       
   664         cur->locTab = (xmlXPathObjectPtr *) xmlMalloc(XML_RANGESET_DEFAULT *
       
   665                                              sizeof(xmlXPathObjectPtr));
       
   666         if (cur->locTab == NULL) {
       
   667             xmlXPtrErrMemory("adding location to set");
       
   668             return;
       
   669         }
       
   670         memset(cur->locTab, 0 ,
       
   671                XML_RANGESET_DEFAULT * (size_t) sizeof(xmlXPathObjectPtr));
       
   672         cur->locMax = XML_RANGESET_DEFAULT;
       
   673     } else if (cur->locNr == cur->locMax) {
       
   674         xmlXPathObjectPtr *temp;
       
   675 
       
   676         cur->locMax *= 2;
       
   677         temp = (xmlXPathObjectPtr *) xmlRealloc(cur->locTab, cur->locMax *
       
   678                                       sizeof(xmlXPathObjectPtr));
       
   679         if (temp == NULL) {
       
   680             xmlXPtrErrMemory("adding location to set");
       
   681             return;
       
   682         }
       
   683         cur->locTab = temp;
       
   684     }
       
   685     cur->locTab[cur->locNr++] = val;
       
   686 }
       
   687 
       
   688 /**
       
   689  * xmlXPtrLocationSetMerge:
       
   690  * @param val1 the first LocationSet
       
   691  * @param val2 the second LocationSet
       
   692  *
       
   693  * Merges two rangesets, all ranges from val2 are added to val1
       
   694  *
       
   695  * Returns val1 once extended or NULL in case of error.
       
   696  */
       
   697 XMLPUBFUNEXPORT xmlLocationSetPtr
       
   698 xmlXPtrLocationSetMerge(xmlLocationSetPtr val1, xmlLocationSetPtr val2) {
       
   699     int i;
       
   700 
       
   701     if (val1 == NULL) return(NULL);
       
   702     if (val2 == NULL) return(val1);
       
   703 
       
   704     /*
       
   705      * !!!!! this can be optimized a lot, knowing that both
       
   706      *       val1 and val2 already have unicity of their values.
       
   707      */
       
   708 
       
   709     for (i = 0;i < val2->locNr;i++)
       
   710         xmlXPtrLocationSetAdd(val1, val2->locTab[i]);
       
   711 
       
   712     return(val1);
       
   713 }
       
   714 
       
   715 /**
       
   716  * xmlXPtrLocationSetDel:
       
   717  * @param cur the initial range set
       
   718  * @param val an xmlXPathObjectPtr
       
   719  *
       
   720  * Removes an xmlXPathObjectPtr from an existing LocationSet
       
   721  */
       
   722 XMLPUBFUNEXPORT void
       
   723 xmlXPtrLocationSetDel(xmlLocationSetPtr cur, xmlXPathObjectPtr val) {
       
   724     int i;
       
   725 
       
   726     if (cur == NULL) return;
       
   727     if (val == NULL) return;
       
   728 
       
   729     /*
       
   730      * check against doublons
       
   731      */
       
   732     for (i = 0;i < cur->locNr;i++)
       
   733         if (cur->locTab[i] == val) break;
       
   734 
       
   735     if (i >= cur->locNr) {
       
   736 #ifdef DEBUG
       
   737         xmlGenericError(xmlGenericErrorContext,
       
   738                 "xmlXPtrLocationSetDel: Range wasn't found in RangeList\n");
       
   739 #endif
       
   740         return;
       
   741     }
       
   742     cur->locNr--;
       
   743     for (;i < cur->locNr;i++)
       
   744         cur->locTab[i] = cur->locTab[i + 1];
       
   745     cur->locTab[cur->locNr] = NULL;
       
   746 }
       
   747 
       
   748 /**
       
   749  * xmlXPtrLocationSetRemove:
       
   750  * @param cur the initial range set
       
   751  * @param val the index to remove
       
   752  *
       
   753  * Removes an entry from an existing LocationSet list.
       
   754  */
       
   755 XMLPUBFUNEXPORT void
       
   756 xmlXPtrLocationSetRemove(xmlLocationSetPtr cur, int val) {
       
   757     if (cur == NULL) return;
       
   758     if (val >= cur->locNr) return;
       
   759     cur->locNr--;
       
   760     for (;val < cur->locNr;val++)
       
   761         cur->locTab[val] = cur->locTab[val + 1];
       
   762     cur->locTab[cur->locNr] = NULL;
       
   763 }
       
   764 
       
   765 /**
       
   766  * xmlXPtrFreeLocationSet:
       
   767  * @param obj the xmlLocationSetPtr to free
       
   768  *
       
   769  * Free the LocationSet compound (not the actual ranges !).
       
   770  */
       
   771 XMLPUBFUNEXPORT void
       
   772 xmlXPtrFreeLocationSet(xmlLocationSetPtr obj) {
       
   773     int i;
       
   774 
       
   775     if (obj == NULL) return;
       
   776     if (obj->locTab != NULL) {
       
   777         for (i = 0;i < obj->locNr; i++) {
       
   778             xmlXPathFreeObject(obj->locTab[i]);
       
   779         }
       
   780         xmlFree(obj->locTab);
       
   781     }
       
   782     xmlFree(obj);
       
   783 }
       
   784 
       
   785 /**
       
   786  * xmlXPtrNewLocationSetNodes:
       
   787  * @param start the start NodePtr value
       
   788  * @param end the end NodePtr value or NULL
       
   789  *
       
   790  * Create a new xmlXPathObjectPtr of type LocationSet and initialize
       
   791  * it with the single range made of the two nodes start and end
       
   792  *
       
   793  * Returns the newly created object.
       
   794  */
       
   795 XMLPUBFUNEXPORT xmlXPathObjectPtr
       
   796 xmlXPtrNewLocationSetNodes(xmlNodePtr start, xmlNodePtr end) {
       
   797     xmlXPathObjectPtr ret;
       
   798 
       
   799     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
       
   800     if (ret == NULL) {
       
   801         xmlXPtrErrMemory("allocating locationset");
       
   802         return(NULL);
       
   803     }
       
   804     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
       
   805     ret->type = XPATH_LOCATIONSET;
       
   806     if (end == NULL)
       
   807         ret->user = xmlXPtrLocationSetCreate(xmlXPtrNewCollapsedRange(start));
       
   808     else
       
   809         ret->user = xmlXPtrLocationSetCreate(xmlXPtrNewRangeNodes(start,end));
       
   810     return(ret);
       
   811 }
       
   812 
       
   813 /**
       
   814  * xmlXPtrNewLocationSetNodeSet:
       
   815  * @param set a node set
       
   816  *
       
   817  * Create a new xmlXPathObjectPtr of type LocationSet and initialize
       
   818  * it with all the nodes from set
       
   819  *
       
   820  * Returns the newly created object.
       
   821  */
       
   822 XMLPUBFUNEXPORT xmlXPathObjectPtr
       
   823 xmlXPtrNewLocationSetNodeSet(xmlNodeSetPtr set) {
       
   824     xmlXPathObjectPtr ret;
       
   825 
       
   826     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
       
   827     if (ret == NULL) {
       
   828         xmlXPtrErrMemory("allocating locationset");
       
   829         return(NULL);
       
   830     }
       
   831     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
       
   832     ret->type = XPATH_LOCATIONSET;
       
   833     if (set != NULL) {
       
   834         int i;
       
   835         xmlLocationSetPtr newset;
       
   836 
       
   837         newset = xmlXPtrLocationSetCreate(NULL);
       
   838         if (newset == NULL)
       
   839             return(ret);
       
   840 
       
   841         for (i = 0;i < set->nodeNr;i++)
       
   842             xmlXPtrLocationSetAdd(newset,
       
   843                         xmlXPtrNewCollapsedRange(set->nodeTab[i]));
       
   844 
       
   845         ret->user = (void *) newset;
       
   846     }
       
   847     return(ret);
       
   848 }
       
   849 
       
   850 /**
       
   851  * xmlXPtrWrapLocationSet:
       
   852  * @param val the LocationSet value
       
   853  *
       
   854  * Wrap the LocationSet val in a new xmlXPathObjectPtr
       
   855  *
       
   856  * Returns the newly created object.
       
   857  */
       
   858 XMLPUBFUNEXPORT xmlXPathObjectPtr
       
   859 xmlXPtrWrapLocationSet(xmlLocationSetPtr val) {
       
   860     xmlXPathObjectPtr ret;
       
   861 
       
   862     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
       
   863     if (ret == NULL) {
       
   864         xmlXPtrErrMemory("allocating locationset");
       
   865         return(NULL);
       
   866     }
       
   867     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
       
   868     ret->type = XPATH_LOCATIONSET;
       
   869     ret->user = (void *) val;
       
   870     return(ret);
       
   871 }
       
   872 
       
   873 /************************************************************************
       
   874  *                                                                      *
       
   875  *                      The parser                                      *
       
   876  *                                                                      *
       
   877  ************************************************************************/
       
   878 
       
   879 static void xmlXPtrEvalChildSeq(xmlXPathParserContextPtr ctxt, xmlChar *name);
       
   880 
       
   881 /*
       
   882  * Macros for accessing the content. Those should be used only by the parser,
       
   883  * and not exported.
       
   884  *
       
   885  * Dirty macros, i.e. one need to make assumption on the context to use them
       
   886  *
       
   887  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
       
   888  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
       
   889  *           in ISO-Latin or UTF-8.
       
   890  *           This should be used internally by the parser
       
   891  *           only to compare to ASCII values otherwise it would break when
       
   892  *           running with UTF-8 encoding.
       
   893  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
       
   894  *           to compare on ASCII based substring.
       
   895  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
       
   896  *           strings within the parser.
       
   897  *   CURRENT Returns the current char value, with the full decoding of
       
   898  *           UTF-8 if we are using this mode. It returns an int.
       
   899  *   NEXT    Skip to the next character, this does the proper decoding
       
   900  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
       
   901  *           It returns the pointer to the current xmlChar.
       
   902  */
       
   903 
       
   904 #define CUR (*ctxt->cur)
       
   905 #define SKIP(val) ctxt->cur += (val)
       
   906 #define NXT(val) ctxt->cur[(val)]
       
   907 #define CUR_PTR ctxt->cur
       
   908 
       
   909 #define SKIP_BLANKS                                                     \
       
   910     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
       
   911 
       
   912 #define CURRENT (*ctxt->cur)
       
   913 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
       
   914 
       
   915 /*
       
   916  * xmlXPtrGetChildNo:
       
   917  * @param ctxt the XPointer Parser context
       
   918  * @param index the child number
       
   919  *
       
   920  * Move the current node of the nodeset on the stack to the
       
   921  * given child if found
       
   922  */
       
   923 static void
       
   924 xmlXPtrGetChildNo(xmlXPathParserContextPtr ctxt, int indx) {
       
   925     xmlNodePtr cur = NULL;
       
   926     xmlXPathObjectPtr obj;
       
   927     xmlNodeSetPtr oldset;
       
   928 
       
   929     CHECK_TYPE(XPATH_NODESET);
       
   930     obj = valuePop(ctxt);
       
   931     oldset = obj->nodesetval;
       
   932     if ((indx <= 0) || (oldset == NULL) || (oldset->nodeNr != 1)) {
       
   933         xmlXPathFreeObject(obj);
       
   934         valuePush(ctxt, xmlXPathNewNodeSet(NULL));
       
   935         return;
       
   936     }
       
   937     cur = xmlXPtrGetNthChild(oldset->nodeTab[0], indx);
       
   938     if (cur == NULL) {
       
   939         xmlXPathFreeObject(obj);
       
   940         valuePush(ctxt, xmlXPathNewNodeSet(NULL));
       
   941         return;
       
   942     }
       
   943     oldset->nodeTab[0] = cur;
       
   944     valuePush(ctxt, obj);
       
   945 }
       
   946 
       
   947 /**
       
   948  * xmlXPtrEvalXPtrPart:
       
   949  * @param ctxt the XPointer Parser context
       
   950  * @param name the preparsed Scheme for the XPtrPart
       
   951  *
       
   952  * XPtrPart ::= 'xpointer' '(' XPtrExpr ')'
       
   953  *            | Scheme '(' SchemeSpecificExpr ')'
       
   954  *
       
   955  * Scheme   ::=  NCName - 'xpointer' [VC: Non-XPointer schemes]
       
   956  *
       
   957  * SchemeSpecificExpr ::= StringWithBalancedParens
       
   958  *
       
   959  * StringWithBalancedParens ::=
       
   960  *              [^()]* ('(' StringWithBalancedParens ')' [^()]*)*
       
   961  *              [VC: Parenthesis escaping]
       
   962  *
       
   963  * XPtrExpr ::= Expr [VC: Parenthesis escaping]
       
   964  *
       
   965  * VC: Parenthesis escaping:
       
   966  *   The end of an XPointer part is signaled by the right parenthesis ")"
       
   967  *   character that is balanced with the left parenthesis "(" character
       
   968  *   that began the part. Any unbalanced parenthesis character inside the
       
   969  *   expression, even within literals, must be escaped with a circumflex (^)
       
   970  *   character preceding it. If the expression contains any literal
       
   971  *   occurrences of the circumflex, each must be escaped with an additional
       
   972  *   circumflex (that is, ^^). If the unescaped parentheses in the expression
       
   973  *   are not balanced, a syntax error results.
       
   974  *
       
   975  * Parse and evaluate an XPtrPart. Basically it generates the unescaped
       
   976  * string and if the scheme is 'xpointer' it will call the XPath interpreter.
       
   977  *
       
   978  * 
       
   979  */
       
   980 
       
   981 static void
       
   982 xmlXPtrEvalXPtrPart(xmlXPathParserContextPtr ctxt, xmlChar *name) {
       
   983     xmlChar *buffer, *cur;
       
   984     int len;
       
   985     int level;
       
   986 
       
   987     if (name == NULL)
       
   988     name = xmlXPathParseName(ctxt);
       
   989     if (name == NULL)
       
   990         XP_ERROR(XPATH_EXPR_ERROR);
       
   991 
       
   992     if (CUR != '(')
       
   993         XP_ERROR(XPATH_EXPR_ERROR);
       
   994     NEXT;
       
   995     level = 1;
       
   996 
       
   997     len = xmlStrlen(ctxt->cur);
       
   998     len++;
       
   999     buffer = (xmlChar *) xmlMallocAtomic(len * sizeof (xmlChar));
       
  1000     if (buffer == NULL) {
       
  1001         xmlXPtrErrMemory("allocating buffer");
       
  1002         xmlFree( name );
       
  1003         return;
       
  1004     }
       
  1005 
       
  1006     cur = buffer;
       
  1007     while (CUR != 0) {
       
  1008         if (CUR == ')') {
       
  1009             level--;
       
  1010             if (level == 0) {
       
  1011                 NEXT;
       
  1012                 break;
       
  1013             }
       
  1014             *cur++ = CUR;
       
  1015         } else if (CUR == '(') {
       
  1016             level++;
       
  1017             *cur++ = CUR;
       
  1018         } else if (CUR == '^') {
       
  1019             NEXT;
       
  1020             if ((CUR == ')') || (CUR == '(') || (CUR == '^')) {
       
  1021                 *cur++ = CUR;
       
  1022             } else {
       
  1023                 *cur++ = '^';
       
  1024                 *cur++ = CUR;
       
  1025             }
       
  1026         } else {
       
  1027             *cur++ = CUR;
       
  1028         }
       
  1029         NEXT;
       
  1030     }
       
  1031     *cur = 0;
       
  1032 
       
  1033     if ((level != 0) && (CUR == 0)) {
       
  1034         xmlFree(buffer);
       
  1035         XP_ERROR(XPTR_SYNTAX_ERROR);
       
  1036     }
       
  1037 
       
  1038     if (xmlStrEqual(name, (xmlChar *) "xpointer")) {
       
  1039         const xmlChar *left = CUR_PTR;
       
  1040 
       
  1041         CUR_PTR = buffer;
       
  1042         /*
       
  1043          * To evaluate an xpointer scheme element (4.3) we need:
       
  1044          *   context initialized to the root
       
  1045          *   context position initalized to 1
       
  1046          *   context size initialized to 1
       
  1047          */
       
  1048         ctxt->context->node = (xmlNodePtr)ctxt->context->doc;
       
  1049         ctxt->context->proximityPosition = 1;
       
  1050         ctxt->context->contextSize = 1;
       
  1051         xmlXPathEvalExpr(ctxt);
       
  1052         CUR_PTR=left;
       
  1053     } else if (xmlStrEqual(name, (xmlChar *) "element")) {
       
  1054         const xmlChar *left = CUR_PTR;
       
  1055         xmlChar *name2;
       
  1056 
       
  1057         CUR_PTR = buffer;
       
  1058         if (buffer[0] == '/') {
       
  1059             xmlXPathRoot(ctxt);
       
  1060             xmlXPtrEvalChildSeq(ctxt, NULL);
       
  1061         } else {
       
  1062             name2 = xmlXPathParseName(ctxt);
       
  1063             if (name2 == NULL) {
       
  1064                 CUR_PTR = left;
       
  1065                 xmlFree(buffer);
       
  1066                 XP_ERROR(XPATH_EXPR_ERROR);
       
  1067             }
       
  1068             xmlXPtrEvalChildSeq(ctxt, name2);
       
  1069         }
       
  1070         CUR_PTR = left;
       
  1071 #ifdef XPTR_XMLNS_SCHEME
       
  1072     } else if (xmlStrEqual(name, (xmlChar *) "xmlns")) {
       
  1073         const xmlChar *left = CUR_PTR;
       
  1074         xmlChar *prefix;
       
  1075         xmlChar *URI;
       
  1076         xmlURIPtr value;
       
  1077 
       
  1078         CUR_PTR = buffer;
       
  1079         prefix = xmlXPathParseNCName(ctxt);
       
  1080         if (prefix == NULL) {
       
  1081             xmlFree(buffer);
       
  1082             xmlFree(name);
       
  1083             XP_ERROR(XPTR_SYNTAX_ERROR);
       
  1084         }
       
  1085         SKIP_BLANKS;
       
  1086         if (CUR != '=') {
       
  1087             xmlFree(prefix);
       
  1088             xmlFree(buffer);
       
  1089             xmlFree(name);
       
  1090             XP_ERROR(XPTR_SYNTAX_ERROR);
       
  1091         }
       
  1092         NEXT;
       
  1093         SKIP_BLANKS;
       
  1094         /* @@ check escaping in the XPointer WD */
       
  1095 
       
  1096         value = xmlParseURI((const char *)ctxt->cur);
       
  1097         if (value == NULL) {
       
  1098             xmlFree(prefix);
       
  1099             xmlFree(buffer);
       
  1100             xmlFree(name);
       
  1101             XP_ERROR(XPTR_SYNTAX_ERROR);
       
  1102         }
       
  1103         URI = xmlSaveUri(value);
       
  1104         xmlFreeURI(value);
       
  1105         if (URI == NULL) {
       
  1106             xmlFree(prefix);
       
  1107             xmlFree(buffer);
       
  1108             xmlFree(name);
       
  1109             XP_ERROR(XPATH_MEMORY_ERROR);
       
  1110         }
       
  1111 
       
  1112         xmlXPathRegisterNs(ctxt->context, prefix, URI);
       
  1113         CUR_PTR = left;
       
  1114         xmlFree(URI);
       
  1115         xmlFree(prefix);
       
  1116 #endif /* XPTR_XMLNS_SCHEME */
       
  1117     } else {
       
  1118         xmlXPtrErr(ctxt, XML_XPTR_UNKNOWN_SCHEME,
       
  1119                    "unsupported scheme '%s'\n", name);
       
  1120     }
       
  1121     xmlFree(buffer);
       
  1122     xmlFree(name);
       
  1123 }
       
  1124 
       
  1125 /**
       
  1126  * xmlXPtrEvalFullXPtr:
       
  1127  * @param ctxt the XPointer Parser context
       
  1128  * @param name the preparsed Scheme for the first XPtrPart
       
  1129  *
       
  1130  * FullXPtr ::= XPtrPart (S? XPtrPart)*
       
  1131  *
       
  1132  * As the specs says:
       
  1133  * -----------
       
  1134  * When multiple XPtrParts are provided, they must be evaluated in
       
  1135  * left-to-right order. If evaluation of one part fails, the nexti
       
  1136  * is evaluated. The following conditions cause XPointer part failure:
       
  1137  *
       
  1138  * - An unknown scheme
       
  1139  * - A scheme that does not locate any sub-resource present in the resource
       
  1140  * - A scheme that is not applicable to the media type of the resource
       
  1141  *
       
  1142  * The XPointer application must consume a failed XPointer part and
       
  1143  * attempt to evaluate the next one, if any. The result of the first
       
  1144  * XPointer part whose evaluation succeeds is taken to be the fragment
       
  1145  * located by the XPointer as a whole. If all the parts fail, the result
       
  1146  * for the XPointer as a whole is a sub-resource error.
       
  1147  * -----------
       
  1148  *
       
  1149  * Parse and evaluate a Full XPtr i.e. possibly a cascade of XPath based
       
  1150  * expressions or other schemes.
       
  1151  */
       
  1152 static void
       
  1153 xmlXPtrEvalFullXPtr(xmlXPathParserContextPtr ctxt, xmlChar *name) {
       
  1154     if (name == NULL)
       
  1155     name = xmlXPathParseName(ctxt);
       
  1156     if (name == NULL)
       
  1157         XP_ERROR(XPATH_EXPR_ERROR);
       
  1158     while (name != NULL) {
       
  1159         xmlXPtrEvalXPtrPart(ctxt, name);
       
  1160 
       
  1161         /* in case of syntax error, break here */
       
  1162         if (ctxt->error != XPATH_EXPRESSION_OK)
       
  1163             return;
       
  1164 
       
  1165         /*
       
  1166          * If the returned value is a non-empty nodeset
       
  1167          * or location set, return here.
       
  1168          */
       
  1169         if (ctxt->value != NULL) {
       
  1170             xmlXPathObjectPtr obj = ctxt->value;
       
  1171 
       
  1172             switch (obj->type) {
       
  1173                 case XPATH_LOCATIONSET: {
       
  1174                     xmlLocationSetPtr loc = ctxt->value->user;
       
  1175                     if ((loc != NULL) && (loc->locNr > 0))
       
  1176                         return;
       
  1177                     break;
       
  1178                 }
       
  1179                 case XPATH_NODESET: {
       
  1180                     xmlNodeSetPtr loc = ctxt->value->nodesetval;
       
  1181                     if ((loc != NULL) && (loc->nodeNr > 0))
       
  1182                         return;
       
  1183                     break;
       
  1184                 }
       
  1185                 default:
       
  1186                     break;
       
  1187             }
       
  1188 
       
  1189             /*
       
  1190              * Evaluating to improper values is equivalent to
       
  1191              * a sub-resource error, clean-up the stack
       
  1192              */
       
  1193             do {
       
  1194                 obj = valuePop(ctxt);
       
  1195                 if (obj != NULL) {
       
  1196                     xmlXPathFreeObject(obj);
       
  1197                 }
       
  1198             } while (obj != NULL);
       
  1199         }
       
  1200 
       
  1201         /*
       
  1202          * Is there another XPointer part.
       
  1203          */
       
  1204         SKIP_BLANKS;
       
  1205         name = xmlXPathParseName(ctxt);
       
  1206     }
       
  1207 }
       
  1208 
       
  1209 /**
       
  1210  * xmlXPtrEvalChildSeq:
       
  1211  * @param ctxt the XPointer Parser context
       
  1212  * @param name a possible ID name of the child sequence
       
  1213  *
       
  1214  *  ChildSeq ::= '/1' ('/' [0-9]*)*
       
  1215  *             | Name ('/' [0-9]*)+
       
  1216  *
       
  1217  * Parse and evaluate a Child Sequence. This routine also handle the
       
  1218  * case of a Bare Name used to get a document ID.
       
  1219  */
       
  1220 static void
       
  1221 xmlXPtrEvalChildSeq(xmlXPathParserContextPtr ctxt, xmlChar *name) {
       
  1222     /*
       
  1223      * XPointer don't allow by syntax to address in mutirooted trees
       
  1224      * this might prove useful in some cases, warn about it.
       
  1225      */
       
  1226     if ((name == NULL) && (CUR == '/') && (NXT(1) != '1')) {
       
  1227         xmlXPtrErr(ctxt, XML_XPTR_CHILDSEQ_START,
       
  1228                    "warning: ChildSeq not starting by /1\n", NULL);
       
  1229     }
       
  1230 
       
  1231     if (name != NULL) {
       
  1232         valuePush(ctxt, xmlXPathNewString(name));
       
  1233         xmlFree(name);
       
  1234         xmlXPathIdFunction(ctxt, 1);
       
  1235         CHECK_ERROR;
       
  1236     }
       
  1237 
       
  1238     while (CUR == '/') {
       
  1239         int child = 0;
       
  1240         NEXT;
       
  1241 
       
  1242         while ((CUR >= '0') && (CUR <= '9')) {
       
  1243             child = child * 10 + (CUR - '0');
       
  1244             NEXT;
       
  1245         }
       
  1246         xmlXPtrGetChildNo(ctxt, child);
       
  1247     }
       
  1248 }
       
  1249 
       
  1250 
       
  1251 /**
       
  1252  * xmlXPtrEvalXPointer:
       
  1253  * @param ctxt the XPointer Parser context
       
  1254  *
       
  1255  *  XPointer ::= Name
       
  1256  *             | ChildSeq
       
  1257  *             | FullXPtr
       
  1258  *
       
  1259  * Parse and evaluate an XPointer
       
  1260  */
       
  1261 static void
       
  1262 xmlXPtrEvalXPointer(xmlXPathParserContextPtr ctxt) {
       
  1263     if (ctxt->valueTab == NULL) {
       
  1264         /* Allocate the value stack */
       
  1265         ctxt->valueTab = (xmlXPathObjectPtr *)
       
  1266                          xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
       
  1267         if (ctxt->valueTab == NULL) {
       
  1268             xmlXPtrErrMemory("allocating evaluation context");
       
  1269             return;
       
  1270         }
       
  1271         ctxt->valueNr = 0;
       
  1272         ctxt->valueMax = 10;
       
  1273         ctxt->value = NULL;
       
  1274     }
       
  1275     SKIP_BLANKS;
       
  1276     if (CUR == '/') {
       
  1277         xmlXPathRoot(ctxt);
       
  1278         xmlXPtrEvalChildSeq(ctxt, NULL);
       
  1279     } else {
       
  1280         xmlChar *name;
       
  1281 
       
  1282         name = xmlXPathParseName(ctxt);
       
  1283         if (name == NULL)
       
  1284             XP_ERROR(XPATH_EXPR_ERROR);
       
  1285         if (CUR == '(') {
       
  1286             xmlXPtrEvalFullXPtr(ctxt, name);
       
  1287             /* Short evaluation */
       
  1288             return;
       
  1289         } else {
       
  1290             /* this handle both Bare Names and Child Sequences */
       
  1291             xmlXPtrEvalChildSeq(ctxt, name);
       
  1292         }
       
  1293     }
       
  1294     SKIP_BLANKS;
       
  1295     if (CUR != 0)
       
  1296         XP_ERROR(XPATH_EXPR_ERROR);
       
  1297 }
       
  1298 
       
  1299 
       
  1300 /************************************************************************
       
  1301  *                                                                      *
       
  1302  *                      General routines                                *
       
  1303  *                                                                      *
       
  1304  ************************************************************************/
       
  1305 
       
  1306 void xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs);
       
  1307 void xmlXPtrStartPointFunction(xmlXPathParserContextPtr ctxt, int nargs);
       
  1308 void xmlXPtrEndPointFunction(xmlXPathParserContextPtr ctxt, int nargs);
       
  1309 void xmlXPtrHereFunction(xmlXPathParserContextPtr ctxt, int nargs);
       
  1310 void xmlXPtrOriginFunction(xmlXPathParserContextPtr ctxt, int nargs);
       
  1311 void xmlXPtrRangeInsideFunction(xmlXPathParserContextPtr ctxt, int nargs);
       
  1312 void xmlXPtrRangeFunction(xmlXPathParserContextPtr ctxt, int nargs);
       
  1313 
       
  1314 /**
       
  1315  * xmlXPtrNewContext:
       
  1316  * @param doc the XML document
       
  1317  * @param here the node that directly contains the XPointer being evaluated or NULL
       
  1318  * @param origin the element from which a user or program initiated traversal of
       
  1319  *           the link, or NULL.
       
  1320  *
       
  1321  * Create a new XPointer context
       
  1322  *
       
  1323  * Returns the xmlXPathContext just allocated.
       
  1324  */
       
  1325 XMLPUBFUNEXPORT xmlXPathContextPtr
       
  1326 xmlXPtrNewContext(xmlDocPtr doc, xmlNodePtr here, xmlNodePtr origin) {
       
  1327     xmlXPathContextPtr ret;
       
  1328 
       
  1329     ret = xmlXPathNewContext(doc);
       
  1330     if (ret == NULL)
       
  1331         return(ret);
       
  1332     ret->xptr = 1;
       
  1333     ret->here = here;
       
  1334     ret->origin = origin;
       
  1335 
       
  1336     xmlXPathRegisterFunc(ret, (xmlChar *)"range-to",
       
  1337                          xmlXPtrRangeToFunction);
       
  1338     xmlXPathRegisterFunc(ret, (xmlChar *)"range",
       
  1339                          xmlXPtrRangeFunction);
       
  1340     xmlXPathRegisterFunc(ret, (xmlChar *)"range-inside",
       
  1341                          xmlXPtrRangeInsideFunction);
       
  1342     xmlXPathRegisterFunc(ret, (xmlChar *)"string-range",
       
  1343                          xmlXPtrStringRangeFunction);
       
  1344     xmlXPathRegisterFunc(ret, (xmlChar *)"start-point",
       
  1345                          xmlXPtrStartPointFunction);
       
  1346     xmlXPathRegisterFunc(ret, (xmlChar *)"end-point",
       
  1347                          xmlXPtrEndPointFunction);
       
  1348     xmlXPathRegisterFunc(ret, (xmlChar *)"here",
       
  1349                          xmlXPtrHereFunction);
       
  1350     xmlXPathRegisterFunc(ret, (xmlChar *)" origin",
       
  1351                          xmlXPtrOriginFunction);
       
  1352 
       
  1353     return(ret);
       
  1354 }
       
  1355 
       
  1356 /**
       
  1357  * xmlXPtrEval:
       
  1358  * @param str the XPointer expression
       
  1359  * @param ctx the XPointer context
       
  1360  *
       
  1361  * Evaluate the XPath Location Path in the given context.
       
  1362  *
       
  1363  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
       
  1364  *         the caller has to free the object.
       
  1365  */
       
  1366 XMLPUBFUNEXPORT xmlXPathObjectPtr
       
  1367 xmlXPtrEval(const xmlChar *str, xmlXPathContextPtr ctx) {
       
  1368     xmlXPathParserContextPtr ctxt;
       
  1369     xmlXPathObjectPtr res = NULL, tmp;
       
  1370     xmlXPathObjectPtr init = NULL;
       
  1371     int stack = 0;
       
  1372 
       
  1373     xmlXPathInit();
       
  1374 
       
  1375     if ((ctx == NULL) || (str == NULL))
       
  1376         return(NULL);
       
  1377 
       
  1378     ctxt = xmlXPathNewParserContext(str, ctx);
       
  1379     if ( ctxt == NULL)
       
  1380         return(NULL);
       
  1381     ctxt->xptr = 1;
       
  1382     xmlXPtrEvalXPointer(ctxt);
       
  1383 
       
  1384     if ((ctxt->value != NULL) &&
       
  1385         (ctxt->value->type != XPATH_NODESET) &&
       
  1386         (ctxt->value->type != XPATH_LOCATIONSET)) {
       
  1387         xmlXPtrErr(ctxt, XML_XPTR_EVAL_FAILED,
       
  1388                 "xmlXPtrEval: evaluation failed to return a node set\n",
       
  1389                    NULL);
       
  1390     } else {
       
  1391         res = valuePop(ctxt);
       
  1392     }
       
  1393 
       
  1394     do {
       
  1395         tmp = valuePop(ctxt);
       
  1396         if (tmp != NULL) {
       
  1397             if (tmp != init) {
       
  1398                 if (tmp->type == XPATH_NODESET) {
       
  1399                     /*
       
  1400                      * Evaluation may push a root nodeset which is unused
       
  1401                      */
       
  1402                     xmlNodeSetPtr set;
       
  1403                     set = tmp->nodesetval;
       
  1404                     if ((set->nodeNr != 1) ||
       
  1405                         (set->nodeTab[0] != (xmlNodePtr) ctx->doc))
       
  1406                         stack++;
       
  1407                 } else
       
  1408                     stack++;
       
  1409             }
       
  1410             xmlXPathFreeObject(tmp);
       
  1411         }
       
  1412     } while (tmp != NULL);
       
  1413     if (stack != 0) {
       
  1414         xmlXPtrErr(ctxt, XML_XPTR_EXTRA_OBJECTS,
       
  1415                    "xmlXPtrEval: object(s) left on the eval stack\n",
       
  1416                    NULL);
       
  1417     }
       
  1418     if (ctxt->error != XPATH_EXPRESSION_OK) {
       
  1419         xmlXPathFreeObject(res);
       
  1420         res = NULL;
       
  1421     }
       
  1422 
       
  1423     xmlXPathFreeParserContext(ctxt);
       
  1424     return(res);
       
  1425 }
       
  1426 
       
  1427 /**
       
  1428  * xmlXPtrBuildRangeNodeList:
       
  1429  * @param range a range object
       
  1430  *
       
  1431  * Build a node list tree copy of the range
       
  1432  *
       
  1433  * Returns an xmlNodePtr list or NULL.
       
  1434  *         the caller has to free the node tree.
       
  1435  */
       
  1436 static xmlNodePtr
       
  1437 xmlXPtrBuildRangeNodeList(xmlXPathObjectPtr range) {
       
  1438     /* pointers to generated nodes */
       
  1439     xmlNodePtr list = NULL, last = NULL, parent = NULL, tmp;
       
  1440     /* pointers to traversal nodes */
       
  1441     xmlNodePtr start, cur, end;
       
  1442     int index1, index2;
       
  1443 
       
  1444     if (range == NULL)
       
  1445         return(NULL);
       
  1446     if (range->type != XPATH_RANGE)
       
  1447         return(NULL);
       
  1448     start = (xmlNodePtr) range->user;
       
  1449 
       
  1450     if (start == NULL)
       
  1451         return(NULL);
       
  1452     end = range->user2;
       
  1453     if (end == NULL)
       
  1454         return(xmlCopyNode(start, 1));
       
  1455 
       
  1456     cur = start;
       
  1457     index1 = range->index;
       
  1458     index2 = range->index2;
       
  1459     while (cur != NULL) {
       
  1460         if (cur == end) {
       
  1461             if (cur->type == XML_TEXT_NODE) {
       
  1462                 const xmlChar *content = cur->content;
       
  1463                 int len;
       
  1464 
       
  1465                 if (content == NULL) {
       
  1466                     tmp = xmlNewTextLen(NULL, 0);
       
  1467                 } else {
       
  1468                     len = index2;
       
  1469                     if ((cur == start) && (index1 > 1)) {
       
  1470                         content += (index1 - 1);
       
  1471                         len -= (index1 - 1);
       
  1472                         index1 = 0;
       
  1473                     } else {
       
  1474                         len = index2;
       
  1475                     }
       
  1476                     tmp = xmlNewTextLen(content, len);
       
  1477                 }
       
  1478                 /* single sub text node selection */
       
  1479                 if (list == NULL)
       
  1480                     return(tmp);
       
  1481                 /* prune and return full set */
       
  1482                 if (last != NULL)
       
  1483                     xmlAddNextSibling(last, tmp);
       
  1484                 else
       
  1485                     xmlAddChild(parent, tmp);
       
  1486                 return(list);
       
  1487             } else {
       
  1488                 tmp = xmlCopyNode(cur, 0);
       
  1489                 if (list == NULL)
       
  1490                     list = tmp;
       
  1491                 else {
       
  1492                     if (last != NULL)
       
  1493                         xmlAddNextSibling(last, tmp);
       
  1494                     else
       
  1495                         xmlAddChild(parent, tmp);
       
  1496                 }
       
  1497                 last = NULL;
       
  1498                 parent = tmp;
       
  1499 
       
  1500                 if (index2 > 1) {
       
  1501                     end = xmlXPtrGetNthChild(cur, index2 - 1);
       
  1502                     index2 = 0;
       
  1503                 }
       
  1504                 if ((cur == start) && (index1 > 1)) {
       
  1505                     cur = xmlXPtrGetNthChild(cur, index1 - 1);
       
  1506                     index1 = 0;
       
  1507                 } else {
       
  1508                     cur = cur->children;
       
  1509                 }
       
  1510                 /*
       
  1511                  * Now gather the remaining nodes from cur to end
       
  1512                  */
       
  1513                 continue; /* while */
       
  1514             }
       
  1515         } else if ((cur == start) &&
       
  1516                    (list == NULL) /* looks superfluous but ... */ ) {
       
  1517             if ((cur->type == XML_TEXT_NODE) ||
       
  1518                 (cur->type == XML_CDATA_SECTION_NODE)) {
       
  1519                 const xmlChar *content = cur->content;
       
  1520 
       
  1521                 if (content == NULL) {
       
  1522                     tmp = xmlNewTextLen(NULL, 0);
       
  1523                 } else {
       
  1524                     if (index1 > 1) {
       
  1525                         content += (index1 - 1);
       
  1526                     }
       
  1527                     tmp = xmlNewText(content);
       
  1528                 }
       
  1529                 last = list = tmp;
       
  1530             } else {
       
  1531                 if ((cur == start) && (index1 > 1)) {
       
  1532                     tmp = xmlCopyNode(cur, 0);
       
  1533                     list = tmp;
       
  1534                     parent = tmp;
       
  1535                     last = NULL;
       
  1536                     cur = xmlXPtrGetNthChild(cur, index1 - 1);
       
  1537                     index1 = 0;
       
  1538                     /*
       
  1539                      * Now gather the remaining nodes from cur to end
       
  1540                      */
       
  1541                     continue; /* while */
       
  1542                 }
       
  1543                 tmp = xmlCopyNode(cur, 1);
       
  1544                 list = tmp;
       
  1545                 parent = NULL;
       
  1546                 last = tmp;
       
  1547             }
       
  1548         } else {
       
  1549             tmp = NULL;
       
  1550             switch (cur->type) {
       
  1551                 case XML_DTD_NODE:
       
  1552                 case XML_ELEMENT_DECL:
       
  1553                 case XML_ATTRIBUTE_DECL:
       
  1554                 case XML_ENTITY_NODE:
       
  1555                     /* Do not copy DTD informations */
       
  1556                     break;
       
  1557                 case XML_ENTITY_DECL:
       
  1558                     TODO /* handle crossing entities -> stack needed */
       
  1559                     break;
       
  1560                 case XML_XINCLUDE_START:
       
  1561                 case XML_XINCLUDE_END:
       
  1562                     /* don't consider it part of the tree content */
       
  1563                     break;
       
  1564                 case XML_ATTRIBUTE_NODE:
       
  1565                     /* Humm, should not happen ! */
       
  1566                     STRANGE
       
  1567                     break;
       
  1568                 default:
       
  1569                     tmp = xmlCopyNode(cur, 1);
       
  1570                     break;
       
  1571             }
       
  1572             if (tmp != NULL) {
       
  1573                 if ((list == NULL) || ((last == NULL) && (parent == NULL)))  {
       
  1574                     STRANGE
       
  1575                     return(NULL);
       
  1576                 }
       
  1577                 if (last != NULL)
       
  1578                     xmlAddNextSibling(last, tmp);
       
  1579                 else {
       
  1580                     xmlAddChild(parent, tmp);
       
  1581                     last = tmp;
       
  1582                 }
       
  1583             }
       
  1584         }
       
  1585         /*
       
  1586          * Skip to next node in document order
       
  1587          */
       
  1588         if ((list == NULL) || ((last == NULL) && (parent == NULL)))  {
       
  1589             STRANGE
       
  1590             return(NULL);
       
  1591         }
       
  1592         cur = xmlXPtrAdvanceNode(cur, NULL);
       
  1593     }
       
  1594     return(list);
       
  1595 }
       
  1596 
       
  1597 /**
       
  1598  * xmlXPtrBuildNodeList:
       
  1599  * @param obj the XPointer result from the evaluation.
       
  1600  *
       
  1601  * Build a node list tree copy of the XPointer result.
       
  1602  * This will drop Attributes and Namespace declarations.
       
  1603  *
       
  1604  * Returns an xmlNodePtr list or NULL.
       
  1605  *         the caller has to free the node tree.
       
  1606  */
       
  1607 XMLPUBFUNEXPORT xmlNodePtr
       
  1608 xmlXPtrBuildNodeList(xmlXPathObjectPtr obj) {
       
  1609     xmlNodePtr list = NULL, last = NULL;
       
  1610     int i;
       
  1611 
       
  1612     if (obj == NULL)
       
  1613         return(NULL);
       
  1614     switch (obj->type) {
       
  1615         case XPATH_NODESET: {
       
  1616             xmlNodeSetPtr set = obj->nodesetval;
       
  1617             if (set == NULL)
       
  1618                 return(NULL);
       
  1619             for (i = 0;i < set->nodeNr;i++) {
       
  1620                 if (set->nodeTab[i] == NULL)
       
  1621                     continue;
       
  1622                 switch (set->nodeTab[i]->type) {
       
  1623                     case XML_TEXT_NODE:
       
  1624                     case XML_CDATA_SECTION_NODE:
       
  1625                     case XML_ELEMENT_NODE:
       
  1626                     case XML_ENTITY_REF_NODE:
       
  1627                     case XML_ENTITY_NODE:
       
  1628                     case XML_PI_NODE:
       
  1629                     case XML_COMMENT_NODE:
       
  1630                     case XML_DOCUMENT_NODE:
       
  1631                     case XML_HTML_DOCUMENT_NODE:
       
  1632 #ifdef LIBXML_DOCB_ENABLED
       
  1633                     case XML_DOCB_DOCUMENT_NODE:
       
  1634 #endif
       
  1635                     case XML_XINCLUDE_START:
       
  1636                     case XML_XINCLUDE_END:
       
  1637                         break;
       
  1638                     case XML_ATTRIBUTE_NODE:
       
  1639                     case XML_NAMESPACE_DECL:
       
  1640                     case XML_DOCUMENT_TYPE_NODE:
       
  1641                     case XML_DOCUMENT_FRAG_NODE:
       
  1642                     case XML_NOTATION_NODE:
       
  1643                     case XML_DTD_NODE:
       
  1644                     case XML_ELEMENT_DECL:
       
  1645                     case XML_ATTRIBUTE_DECL:
       
  1646                     case XML_ENTITY_DECL:
       
  1647                         continue; /* for */
       
  1648                 }
       
  1649                 if (last == NULL)
       
  1650                     list = last = xmlCopyNode(set->nodeTab[i], 1);
       
  1651                 else {
       
  1652                     xmlAddNextSibling(last, xmlCopyNode(set->nodeTab[i], 1));
       
  1653                     if (last->next != NULL)
       
  1654                         last = last->next;
       
  1655                 }
       
  1656             }
       
  1657             break;
       
  1658         }
       
  1659         case XPATH_LOCATIONSET: {
       
  1660             xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user;
       
  1661             if (set == NULL)
       
  1662                 return(NULL);
       
  1663             for (i = 0;i < set->locNr;i++) {
       
  1664                 if (last == NULL)
       
  1665                     list = last = xmlXPtrBuildNodeList(set->locTab[i]);
       
  1666                 else
       
  1667                     xmlAddNextSibling(last,
       
  1668                             xmlXPtrBuildNodeList(set->locTab[i]));
       
  1669                 if (last != NULL) {
       
  1670                     while (last->next != NULL)
       
  1671                         last = last->next;
       
  1672                 }
       
  1673             }
       
  1674             break;
       
  1675         }
       
  1676         case XPATH_RANGE:
       
  1677             return(xmlXPtrBuildRangeNodeList(obj));
       
  1678         case XPATH_POINT:
       
  1679             return(xmlCopyNode(obj->user, 0));
       
  1680         default:
       
  1681             break;
       
  1682     }
       
  1683     return(list);
       
  1684 }
       
  1685 
       
  1686 /************************************************************************
       
  1687  *                                                                      *
       
  1688  *                      XPointer functions                              *
       
  1689  *                                                                      *
       
  1690  ************************************************************************/
       
  1691 
       
  1692 /**
       
  1693  * xmlXPtrNbLocChildren:
       
  1694  * @param node an xmlNodePtr
       
  1695  *
       
  1696  * Count the number of location children of node or the length of the
       
  1697  * string value in case of text/PI/Comments nodes
       
  1698  *
       
  1699  * Returns the number of location children
       
  1700  */
       
  1701 static int
       
  1702 xmlXPtrNbLocChildren(xmlNodePtr node) {
       
  1703     int ret = 0;
       
  1704     if (node == NULL)
       
  1705         return(-1);
       
  1706     switch (node->type) {
       
  1707         case XML_HTML_DOCUMENT_NODE:
       
  1708         case XML_DOCUMENT_NODE:
       
  1709         case XML_ELEMENT_NODE:
       
  1710             node = node->children;
       
  1711             while (node != NULL) {
       
  1712                 if (node->type == XML_ELEMENT_NODE)
       
  1713                     ret++;
       
  1714                 node = node->next;
       
  1715             }
       
  1716             break;
       
  1717         case XML_ATTRIBUTE_NODE:
       
  1718             return(-1);
       
  1719 
       
  1720         case XML_PI_NODE:
       
  1721         case XML_COMMENT_NODE:
       
  1722         case XML_TEXT_NODE:
       
  1723         case XML_CDATA_SECTION_NODE:
       
  1724         case XML_ENTITY_REF_NODE:
       
  1725             ret = xmlStrlen(node->content);
       
  1726             break;
       
  1727         default:
       
  1728             return(-1);
       
  1729     }
       
  1730     return(ret);
       
  1731 }
       
  1732 
       
  1733 /**
       
  1734  * xmlXPtrHereFunction:
       
  1735  * @param ctxt the XPointer Parser context
       
  1736  * @param nargs the number of args
       
  1737  *
       
  1738  * Function implementing here() operation
       
  1739  * as described in 5.4.3
       
  1740  */
       
  1741 void
       
  1742 xmlXPtrHereFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  1743     CHECK_ARITY(0);
       
  1744 
       
  1745     if (ctxt->context->here == NULL)
       
  1746         XP_ERROR(XPTR_SYNTAX_ERROR);
       
  1747 
       
  1748     valuePush(ctxt, xmlXPtrNewLocationSetNodes(ctxt->context->here, NULL));
       
  1749 }
       
  1750 
       
  1751 /**
       
  1752  * xmlXPtrOriginFunction:
       
  1753  * @param ctxt the XPointer Parser context
       
  1754  * @param nargs the number of args
       
  1755  *
       
  1756  * Function implementing origin() operation
       
  1757  * as described in 5.4.3
       
  1758  */
       
  1759 void
       
  1760 xmlXPtrOriginFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  1761     CHECK_ARITY(0);
       
  1762 
       
  1763     if (ctxt->context->origin == NULL)
       
  1764         XP_ERROR(XPTR_SYNTAX_ERROR);
       
  1765 
       
  1766     valuePush(ctxt, xmlXPtrNewLocationSetNodes(ctxt->context->origin, NULL));
       
  1767 }
       
  1768 
       
  1769 /**
       
  1770  * xmlXPtrStartPointFunction:
       
  1771  * @param ctxt the XPointer Parser context
       
  1772  * @param nargs the number of args
       
  1773  *
       
  1774  * Function implementing start-point() operation
       
  1775  * as described in 5.4.3
       
  1776  * ----------------
       
  1777  * location-set start-point(location-set)
       
  1778  *
       
  1779  * For each location x in the argument location-set, start-point adds a
       
  1780  * location of type point to the result location-set. That point represents
       
  1781  * the start point of location x and is determined by the following rules:
       
  1782  *
       
  1783  * - If x is of type point, the start point is x.
       
  1784  * - If x is of type range, the start point is the start point of x.
       
  1785  * - If x is of type root, element, text, comment, or processing instruction,
       
  1786  * - the container node of the start point is x and the index is 0.
       
  1787  * - If x is of type attribute or namespace, the function must signal a
       
  1788  *   syntax error.
       
  1789  * ----------------
       
  1790  *
       
  1791  */
       
  1792 void
       
  1793 xmlXPtrStartPointFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  1794     xmlXPathObjectPtr tmp, obj, point;
       
  1795     xmlLocationSetPtr newset = NULL;
       
  1796     xmlLocationSetPtr oldset = NULL;
       
  1797 
       
  1798     CHECK_ARITY(1);
       
  1799     if ((ctxt->value == NULL) ||
       
  1800         ((ctxt->value->type != XPATH_LOCATIONSET) &&
       
  1801          (ctxt->value->type != XPATH_NODESET)))
       
  1802         XP_ERROR(XPATH_INVALID_TYPE)
       
  1803 
       
  1804     obj = valuePop(ctxt);
       
  1805     if (obj->type == XPATH_NODESET) {
       
  1806         /*
       
  1807          * First convert to a location set
       
  1808          */
       
  1809         tmp = xmlXPtrNewLocationSetNodeSet(obj->nodesetval);
       
  1810         xmlXPathFreeObject(obj);
       
  1811         obj = tmp;
       
  1812     }
       
  1813 
       
  1814     newset = xmlXPtrLocationSetCreate(NULL);
       
  1815     if (newset == NULL) {
       
  1816         xmlXPathFreeObject(obj);
       
  1817         XP_ERROR(XPATH_MEMORY_ERROR);
       
  1818     }
       
  1819     oldset = (xmlLocationSetPtr) obj->user;
       
  1820     if (oldset != NULL) {
       
  1821         int i;
       
  1822 
       
  1823         for (i = 0; i < oldset->locNr; i++) {
       
  1824             tmp = oldset->locTab[i];
       
  1825             if (tmp == NULL)
       
  1826                 continue;
       
  1827             point = NULL;
       
  1828             switch (tmp->type) {
       
  1829                 case XPATH_POINT:
       
  1830                     point = xmlXPtrNewPoint(tmp->user, tmp->index);
       
  1831                     break;
       
  1832                 case XPATH_RANGE: {
       
  1833                     xmlNodePtr node = tmp->user;
       
  1834                     if (node != NULL) {
       
  1835                         if (node->type == XML_ATTRIBUTE_NODE) {
       
  1836                             
       
  1837                             xmlXPathFreeObject(obj);
       
  1838                             xmlXPtrFreeLocationSet(newset);
       
  1839                             XP_ERROR(XPTR_SYNTAX_ERROR);
       
  1840                         }
       
  1841                         point = xmlXPtrNewPoint(node, tmp->index);
       
  1842                     }
       
  1843                     break;
       
  1844                 }
       
  1845                 default:
       
  1846                     /*** Should we raise an error ?
       
  1847                     xmlXPathFreeObject(obj);
       
  1848                     xmlXPathFreeObject(newset);
       
  1849                     XP_ERROR(XPATH_INVALID_TYPE)
       
  1850                     ***/
       
  1851                     break;
       
  1852             }
       
  1853             if (point != NULL)
       
  1854                 xmlXPtrLocationSetAdd(newset, point);
       
  1855         }
       
  1856     }
       
  1857     xmlXPathFreeObject(obj);
       
  1858     valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
       
  1859 }
       
  1860 
       
  1861 /**
       
  1862  * xmlXPtrEndPointFunction:
       
  1863  * @param ctxt the XPointer Parser context
       
  1864  * @param nargs the number of args
       
  1865  *
       
  1866  * Function implementing end-point() operation
       
  1867  * as described in 5.4.3
       
  1868  * ----------------------------
       
  1869  * location-set end-point(location-set)
       
  1870  *
       
  1871  * For each location x in the argument location-set, end-point adds a
       
  1872  * location of type point to the result location-set. That point represents
       
  1873  * the end point of location x and is determined by the following rules:
       
  1874  *
       
  1875  * - If x is of type point, the resulting point is x.
       
  1876  * - If x is of type range, the resulting point is the end point of x.
       
  1877  * - If x is of type root or element, the container node of the resulting
       
  1878  *   point is x and the index is the number of location children of x.
       
  1879  * - If x is of type text, comment, or processing instruction, the container
       
  1880  *   node of the resulting point is x and the index is the length of the
       
  1881  *   string-value of x.
       
  1882  * - If x is of type attribute or namespace, the function must signal a
       
  1883  *   syntax error.
       
  1884  * ----------------------------
       
  1885  */
       
  1886 void
       
  1887 xmlXPtrEndPointFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  1888     xmlXPathObjectPtr tmp, obj, point;
       
  1889     xmlLocationSetPtr newset = NULL;
       
  1890     xmlLocationSetPtr oldset = NULL;
       
  1891 
       
  1892     CHECK_ARITY(1);
       
  1893     if ((ctxt->value == NULL) ||
       
  1894         ((ctxt->value->type != XPATH_LOCATIONSET) &&
       
  1895          (ctxt->value->type != XPATH_NODESET)))
       
  1896         XP_ERROR(XPATH_INVALID_TYPE)
       
  1897 
       
  1898     obj = valuePop(ctxt);
       
  1899     if (obj->type == XPATH_NODESET) {
       
  1900         /*
       
  1901          * First convert to a location set
       
  1902          */
       
  1903         tmp = xmlXPtrNewLocationSetNodeSet(obj->nodesetval);
       
  1904         xmlXPathFreeObject(obj);
       
  1905         obj = tmp;
       
  1906     }
       
  1907 
       
  1908     newset = xmlXPtrLocationSetCreate(NULL);
       
  1909     oldset = (xmlLocationSetPtr) obj->user;
       
  1910     if (oldset != NULL) {
       
  1911         int i;
       
  1912 
       
  1913         for (i = 0; i < oldset->locNr; i++) {
       
  1914             tmp = oldset->locTab[i];
       
  1915             if (tmp == NULL)
       
  1916                 continue;
       
  1917             point = NULL;
       
  1918             switch (tmp->type) {
       
  1919                 case XPATH_POINT:
       
  1920                     point = xmlXPtrNewPoint(tmp->user, tmp->index);
       
  1921                     break;
       
  1922                 case XPATH_RANGE: {
       
  1923                     xmlNodePtr node = tmp->user2;
       
  1924                     if (node != NULL) {
       
  1925                         if (node->type == XML_ATTRIBUTE_NODE) {
       
  1926                             
       
  1927                             xmlXPathFreeObject(obj);
       
  1928                             xmlXPtrFreeLocationSet(newset);
       
  1929                             XP_ERROR(XPTR_SYNTAX_ERROR);
       
  1930                         }
       
  1931                         point = xmlXPtrNewPoint(node, tmp->index2);
       
  1932                     } else if (tmp->user == NULL) {
       
  1933                         point = xmlXPtrNewPoint(node,
       
  1934                                        xmlXPtrNbLocChildren(node));
       
  1935                     }
       
  1936                     break;
       
  1937                 }
       
  1938                 default:
       
  1939                     /*** Should we raise an error ?
       
  1940                     xmlXPathFreeObject(obj);
       
  1941                     xmlXPathFreeObject(newset);
       
  1942                     XP_ERROR(XPATH_INVALID_TYPE)
       
  1943                     ***/
       
  1944                     break;
       
  1945             }
       
  1946             if (point != NULL)
       
  1947                 xmlXPtrLocationSetAdd(newset, point);
       
  1948         }
       
  1949     }
       
  1950     xmlXPathFreeObject(obj);
       
  1951     valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
       
  1952 }
       
  1953 
       
  1954 
       
  1955 /**
       
  1956  * xmlXPtrCoveringRange:
       
  1957  * @param ctxt the XPointer Parser context
       
  1958  * @param loc the location for which the covering range must be computed
       
  1959  *
       
  1960  * A covering range is a range that wholly encompasses a location
       
  1961  * Section 5.3.3. Covering Ranges for All Location Types
       
  1962  *        http://www.w3.org/TR/xptr#N2267
       
  1963  *
       
  1964  * Returns a new location or NULL in case of error
       
  1965  */
       
  1966 static xmlXPathObjectPtr
       
  1967 xmlXPtrCoveringRange(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr loc) {
       
  1968     if (loc == NULL)
       
  1969         return(NULL);
       
  1970     if ((ctxt == NULL) || (ctxt->context == NULL) ||
       
  1971         (ctxt->context->doc == NULL))
       
  1972         return(NULL);
       
  1973     switch (loc->type) {
       
  1974         case XPATH_POINT:
       
  1975             return(xmlXPtrNewRange(loc->user, loc->index,
       
  1976                                    loc->user, loc->index));
       
  1977         case XPATH_RANGE:
       
  1978             if (loc->user2 != NULL) {
       
  1979                 return(xmlXPtrNewRange(loc->user, loc->index,
       
  1980                                       loc->user2, loc->index2));
       
  1981             } else {
       
  1982                 xmlNodePtr node = (xmlNodePtr) loc->user;
       
  1983                 if (node == (xmlNodePtr) ctxt->context->doc) {
       
  1984                     return(xmlXPtrNewRange(node, 0, node,
       
  1985                                            xmlXPtrGetArity(node)));
       
  1986                 } else {
       
  1987                     switch (node->type) {
       
  1988                         case XML_ATTRIBUTE_NODE:
       
  1989                         /* !!! our model is slightly different than XPath */
       
  1990                             return(xmlXPtrNewRange(node, 0, node,
       
  1991                                                    xmlXPtrGetArity(node)));
       
  1992                         case XML_ELEMENT_NODE:
       
  1993                         case XML_TEXT_NODE:
       
  1994                         case XML_CDATA_SECTION_NODE:
       
  1995                         case XML_ENTITY_REF_NODE:
       
  1996                         case XML_PI_NODE:
       
  1997                         case XML_COMMENT_NODE:
       
  1998                         case XML_DOCUMENT_NODE:
       
  1999                         case XML_NOTATION_NODE:
       
  2000                         case XML_HTML_DOCUMENT_NODE: {
       
  2001                             int indx = xmlXPtrGetIndex(node);
       
  2002 
       
  2003                             node = node->parent;
       
  2004                             return(xmlXPtrNewRange(node, indx - 1,
       
  2005                                                    node, indx + 1));
       
  2006                         }
       
  2007                         default:
       
  2008                             return(NULL);
       
  2009                     }
       
  2010                 }
       
  2011             }
       
  2012         default:
       
  2013             TODO /* missed one case ??? */
       
  2014     }
       
  2015     return(NULL);
       
  2016 }
       
  2017 
       
  2018 /**
       
  2019  * xmlXPtrRangeFunction:
       
  2020  * @param ctxt the XPointer Parser context
       
  2021  * @param nargs the number of args
       
  2022  *
       
  2023  * Function implementing the range() function 5.4.3
       
  2024  *  location-set range(location-set )
       
  2025  *
       
  2026  *  The range function returns ranges covering the locations in
       
  2027  *  the argument location-set. For each location x in the argument
       
  2028  *  location-set, a range location representing the covering range of
       
  2029  *  x is added to the result location-set.
       
  2030  */
       
  2031 void
       
  2032 xmlXPtrRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  2033     int i;
       
  2034     xmlXPathObjectPtr set;
       
  2035     xmlLocationSetPtr oldset;
       
  2036     xmlLocationSetPtr newset;
       
  2037 
       
  2038     CHECK_ARITY(1);
       
  2039     if ((ctxt->value == NULL) ||
       
  2040         ((ctxt->value->type != XPATH_LOCATIONSET) &&
       
  2041          (ctxt->value->type != XPATH_NODESET)))
       
  2042         XP_ERROR(XPATH_INVALID_TYPE)
       
  2043 
       
  2044     set = valuePop(ctxt);
       
  2045     if (set->type == XPATH_NODESET) {
       
  2046         xmlXPathObjectPtr tmp;
       
  2047 
       
  2048         /*
       
  2049          * First convert to a location set
       
  2050          */
       
  2051         tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval);
       
  2052         xmlXPathFreeObject(set);
       
  2053         set = tmp;
       
  2054     }
       
  2055     oldset = (xmlLocationSetPtr) set->user;
       
  2056 
       
  2057     /*
       
  2058      * The loop is to compute the covering range for each item and add it
       
  2059      */
       
  2060     newset = xmlXPtrLocationSetCreate(NULL);
       
  2061     for (i = 0;i < oldset->locNr;i++) {
       
  2062         xmlXPtrLocationSetAdd(newset,
       
  2063                 xmlXPtrCoveringRange(ctxt, oldset->locTab[i]));
       
  2064     }
       
  2065 
       
  2066     /*
       
  2067      * Save the new value and cleanup
       
  2068      */
       
  2069     valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
       
  2070     xmlXPathFreeObject(set);
       
  2071 }
       
  2072 
       
  2073 /**
       
  2074  * xmlXPtrInsideRange:
       
  2075  * @param ctxt the XPointer Parser context
       
  2076  * @param loc the location for which the inside range must be computed
       
  2077  *
       
  2078  * A inside range is a range described in the range-inside() description
       
  2079  *
       
  2080  * Returns a new location or NULL in case of error
       
  2081  */
       
  2082 static xmlXPathObjectPtr
       
  2083 xmlXPtrInsideRange(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr loc) {
       
  2084     if (loc == NULL)
       
  2085         return(NULL);
       
  2086     if ((ctxt == NULL) || (ctxt->context == NULL) ||
       
  2087         (ctxt->context->doc == NULL))
       
  2088         return(NULL);
       
  2089     switch (loc->type) {
       
  2090         case XPATH_POINT: {
       
  2091             xmlNodePtr node = (xmlNodePtr) loc->user;
       
  2092             switch (node->type) {
       
  2093                 case XML_PI_NODE:
       
  2094                 case XML_COMMENT_NODE:
       
  2095                 case XML_TEXT_NODE:
       
  2096                 case XML_CDATA_SECTION_NODE: {
       
  2097                     if (node->content == NULL) {
       
  2098                         return(xmlXPtrNewRange(node, 0, node, 0));
       
  2099                     } else {
       
  2100                         return(xmlXPtrNewRange(node, 0, node,
       
  2101                                                xmlStrlen(node->content)));
       
  2102                     }
       
  2103                 }
       
  2104                 case XML_ATTRIBUTE_NODE:
       
  2105                 case XML_ELEMENT_NODE:
       
  2106                 case XML_ENTITY_REF_NODE:
       
  2107                 case XML_DOCUMENT_NODE:
       
  2108                 case XML_NOTATION_NODE:
       
  2109                 case XML_HTML_DOCUMENT_NODE: {
       
  2110                     return(xmlXPtrNewRange(node, 0, node,
       
  2111                                            xmlXPtrGetArity(node)));
       
  2112                 }
       
  2113                 default:
       
  2114                     break;
       
  2115             }
       
  2116             return(NULL);
       
  2117         }
       
  2118         case XPATH_RANGE: {
       
  2119             xmlNodePtr node = (xmlNodePtr) loc->user;
       
  2120             if (loc->user2 != NULL) {
       
  2121                 return(xmlXPtrNewRange(node, loc->index,
       
  2122                                        loc->user2, loc->index2));
       
  2123             } else {
       
  2124                 switch (node->type) {
       
  2125                     case XML_PI_NODE:
       
  2126                     case XML_COMMENT_NODE:
       
  2127                     case XML_TEXT_NODE:
       
  2128                     case XML_CDATA_SECTION_NODE: {
       
  2129                         if (node->content == NULL) {
       
  2130                             return(xmlXPtrNewRange(node, 0, node, 0));
       
  2131                         } else {
       
  2132                             return(xmlXPtrNewRange(node, 0, node,
       
  2133                                                    xmlStrlen(node->content)));
       
  2134                         }
       
  2135                     }
       
  2136                     case XML_ATTRIBUTE_NODE:
       
  2137                     case XML_ELEMENT_NODE:
       
  2138                     case XML_ENTITY_REF_NODE:
       
  2139                     case XML_DOCUMENT_NODE:
       
  2140                     case XML_NOTATION_NODE:
       
  2141                     case XML_HTML_DOCUMENT_NODE: {
       
  2142                         return(xmlXPtrNewRange(node, 0, node,
       
  2143                                                xmlXPtrGetArity(node)));
       
  2144                     }
       
  2145                     default:
       
  2146                         break;
       
  2147                 }
       
  2148                 return(NULL);
       
  2149             }
       
  2150         }
       
  2151         default:
       
  2152             TODO /* missed one case ??? */
       
  2153     }
       
  2154     return(NULL);
       
  2155 }
       
  2156 
       
  2157 /**
       
  2158  * xmlXPtrRangeInsideFunction:
       
  2159  * @param ctxt the XPointer Parser context
       
  2160  * @param nargs the number of args
       
  2161  *
       
  2162  * Function implementing the range-inside() function 5.4.3
       
  2163  *  location-set range-inside(location-set )
       
  2164  *
       
  2165  *  The range-inside function returns ranges covering the contents of
       
  2166  *  the locations in the argument location-set. For each location x in
       
  2167  *  the argument location-set, a range location is added to the result
       
  2168  *  location-set. If x is a range location, then x is added to the
       
  2169  *  result location-set. If x is not a range location, then x is used
       
  2170  *  as the container location of the start and end points of the range
       
  2171  *  location to be added; the index of the start point of the range is
       
  2172  *  zero; if the end point is a character point then its index is the
       
  2173  *  length of the string-value of x, and otherwise is the number of
       
  2174  *  location children of x.
       
  2175  *
       
  2176  */
       
  2177 void
       
  2178 xmlXPtrRangeInsideFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  2179     int i;
       
  2180     xmlXPathObjectPtr set;
       
  2181     xmlLocationSetPtr oldset;
       
  2182     xmlLocationSetPtr newset;
       
  2183 
       
  2184     CHECK_ARITY(1);
       
  2185     if ((ctxt->value == NULL) ||
       
  2186         ((ctxt->value->type != XPATH_LOCATIONSET) &&
       
  2187          (ctxt->value->type != XPATH_NODESET)))
       
  2188         XP_ERROR(XPATH_INVALID_TYPE)
       
  2189 
       
  2190     set = valuePop(ctxt);
       
  2191     if (set->type == XPATH_NODESET) {
       
  2192         xmlXPathObjectPtr tmp;
       
  2193 
       
  2194         /*
       
  2195          * First convert to a location set
       
  2196          */
       
  2197         tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval);
       
  2198         xmlXPathFreeObject(set);
       
  2199         set = tmp;
       
  2200     }
       
  2201     oldset = (xmlLocationSetPtr) set->user;
       
  2202 
       
  2203     /*
       
  2204      * The loop is to compute the covering range for each item and add it
       
  2205      */
       
  2206     newset = xmlXPtrLocationSetCreate(NULL);
       
  2207     for (i = 0;i < oldset->locNr;i++) {
       
  2208         xmlXPtrLocationSetAdd(newset,
       
  2209                 xmlXPtrInsideRange(ctxt, oldset->locTab[i]));
       
  2210     }
       
  2211 
       
  2212     /*
       
  2213      * Save the new value and cleanup
       
  2214      */
       
  2215     valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
       
  2216     xmlXPathFreeObject(set);
       
  2217 }
       
  2218 
       
  2219 /**
       
  2220  * xmlXPtrRangeToFunction:
       
  2221  * @param ctxt the XPointer Parser context
       
  2222  * @param nargs the number of args
       
  2223  *
       
  2224  * Implement the range-to() XPointer function
       
  2225  */
       
  2226 XMLPUBFUNEXPORT void
       
  2227 xmlXPtrRangeToFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  2228     xmlXPathObjectPtr range;
       
  2229     const xmlChar *cur;
       
  2230     xmlXPathObjectPtr res, obj;
       
  2231     xmlXPathObjectPtr tmp;
       
  2232     xmlLocationSetPtr newset = NULL;
       
  2233     xmlNodeSetPtr oldset;
       
  2234     int i;
       
  2235 
       
  2236     CHECK_ARITY(1);
       
  2237     /*
       
  2238      * Save the expression pointer since we will have to evaluate
       
  2239      * it multiple times. Initialize the new set.
       
  2240      */
       
  2241     CHECK_TYPE(XPATH_NODESET);
       
  2242     obj = valuePop(ctxt);
       
  2243     oldset = obj->nodesetval;
       
  2244     ctxt->context->node = NULL;
       
  2245 
       
  2246     cur = ctxt->cur;
       
  2247     newset = xmlXPtrLocationSetCreate(NULL);
       
  2248 
       
  2249     for (i = 0; i < oldset->nodeNr; i++) {
       
  2250         ctxt->cur = cur;
       
  2251 
       
  2252         /*
       
  2253          * Run the evaluation with a node list made of a single item
       
  2254          * in the nodeset.
       
  2255          */
       
  2256         ctxt->context->node = oldset->nodeTab[i];
       
  2257         tmp = xmlXPathNewNodeSet(ctxt->context->node);
       
  2258         valuePush(ctxt, tmp);
       
  2259 
       
  2260         xmlXPathEvalExpr(ctxt);
       
  2261         CHECK_ERROR;
       
  2262 
       
  2263         /*
       
  2264          * The result of the evaluation need to be tested to
       
  2265          * decided whether the filter succeeded or not
       
  2266          */
       
  2267         res = valuePop(ctxt);
       
  2268         range = xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], res);
       
  2269         if (range != NULL) {
       
  2270             xmlXPtrLocationSetAdd(newset, range);
       
  2271         }
       
  2272 
       
  2273         /*
       
  2274          * Cleanup
       
  2275          */
       
  2276         if (res != NULL)
       
  2277             xmlXPathFreeObject(res);
       
  2278         if (ctxt->value == tmp) {
       
  2279             res = valuePop(ctxt);
       
  2280             xmlXPathFreeObject(res);
       
  2281         }
       
  2282 
       
  2283         ctxt->context->node = NULL;
       
  2284     }
       
  2285 
       
  2286     /*
       
  2287      * The result is used as the new evaluation set.
       
  2288      */
       
  2289     xmlXPathFreeObject(obj);
       
  2290     ctxt->context->node = NULL;
       
  2291     ctxt->context->contextSize = -1;
       
  2292     ctxt->context->proximityPosition = -1;
       
  2293     valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
       
  2294 }
       
  2295 
       
  2296 /**
       
  2297  * xmlXPtrAdvanceNode:
       
  2298  * @param cur the node
       
  2299  * @param level incremented/decremented to show level in tree
       
  2300  *
       
  2301  * Advance to the next element or text node in document order
       
  2302  * 
       
  2303  *
       
  2304  * Returns -1 in case of failure, 0 otherwise
       
  2305  */
       
  2306 xmlNodePtr
       
  2307 xmlXPtrAdvanceNode(xmlNodePtr cur, int *level) {
       
  2308 next:
       
  2309     if (cur == NULL)
       
  2310         return(NULL);
       
  2311     if (cur->children != NULL) {
       
  2312         cur = cur->children ;
       
  2313         if (level != NULL)
       
  2314             (*level)++;
       
  2315         goto found;
       
  2316     }
       
  2317 skip:           /* This label should only be needed if something is wrong! */
       
  2318     if (cur->next != NULL) {
       
  2319         cur = cur->next;
       
  2320         goto found;
       
  2321     }
       
  2322     do {
       
  2323         cur = cur->parent;
       
  2324         if (level != NULL)
       
  2325             (*level)--;
       
  2326         if (cur == NULL) return(NULL);
       
  2327         if (cur->next != NULL) {
       
  2328             cur = cur->next;
       
  2329             goto found;
       
  2330         }
       
  2331     } while (cur != NULL);
       
  2332 
       
  2333 found:
       
  2334     if ((cur->type != XML_ELEMENT_NODE) &&
       
  2335         (cur->type != XML_TEXT_NODE) &&
       
  2336         (cur->type != XML_DOCUMENT_NODE) &&
       
  2337         (cur->type != XML_HTML_DOCUMENT_NODE) &&
       
  2338         (cur->type != XML_CDATA_SECTION_NODE)) {
       
  2339             if (cur->type == XML_ENTITY_REF_NODE) {     /* Shouldn't happen */
       
  2340                 TODO
       
  2341                 goto skip;
       
  2342             }
       
  2343             goto next;
       
  2344         }
       
  2345     return(cur);
       
  2346 }
       
  2347 
       
  2348 /**
       
  2349  * xmlXPtrAdvanceChar:
       
  2350  * @param node the node
       
  2351  * @param indx the indx
       
  2352  * @param bytes the number of bytes
       
  2353  *
       
  2354  * Advance a point of the associated number of bytes (not UTF8 chars)
       
  2355  *
       
  2356  * Returns -1 in case of failure, 0 otherwise
       
  2357  */
       
  2358 static int
       
  2359 xmlXPtrAdvanceChar(xmlNodePtr *node, int *indx, int bytes) {
       
  2360     xmlNodePtr cur;
       
  2361     int pos;
       
  2362     int len;
       
  2363 
       
  2364     if ((node == NULL) || (indx == NULL))
       
  2365         return(-1);
       
  2366     cur = *node;
       
  2367     if (cur == NULL)
       
  2368         return(-1);
       
  2369     pos = *indx;
       
  2370 
       
  2371     while (bytes >= 0) {
       
  2372         /*
       
  2373          * First position to the beginning of the first text node
       
  2374          * corresponding to this point
       
  2375          */
       
  2376         while ((cur != NULL) &&
       
  2377                ((cur->type == XML_ELEMENT_NODE) ||
       
  2378                 (cur->type == XML_DOCUMENT_NODE) ||
       
  2379                 (cur->type == XML_HTML_DOCUMENT_NODE))) {
       
  2380             if (pos > 0) {
       
  2381                 cur = xmlXPtrGetNthChild(cur, pos);
       
  2382                 pos = 0;
       
  2383             } else {
       
  2384                 cur = xmlXPtrAdvanceNode(cur, NULL);
       
  2385                 pos = 0;
       
  2386             }
       
  2387         }
       
  2388 
       
  2389         if (cur == NULL) {
       
  2390             *node = NULL;
       
  2391             *indx = 0;
       
  2392             return(-1);
       
  2393         }
       
  2394 
       
  2395         /*
       
  2396          * if there is no move needed return the current value.
       
  2397          */
       
  2398         if (pos == 0) pos = 1;
       
  2399         if (bytes == 0) {
       
  2400             *node = cur;
       
  2401             *indx = pos;
       
  2402             return(0);
       
  2403         }
       
  2404         /*
       
  2405          * We should have a text (or cdata) node ...
       
  2406          */
       
  2407         len = 0;
       
  2408         if ((cur->type != XML_ELEMENT_NODE) &&
       
  2409             (cur->content != NULL)) {
       
  2410             len = xmlStrlen(cur->content);
       
  2411         }
       
  2412         if (pos > len) {
       
  2413             /* Strange, the indx in the text node is greater than it's len */
       
  2414             STRANGE
       
  2415             pos = len;
       
  2416         }
       
  2417         if (pos + bytes >= len) {
       
  2418             bytes -= (len - pos);
       
  2419             cur = xmlXPtrAdvanceNode(cur, NULL);
       
  2420             cur = 0;
       
  2421         } else if (pos + bytes < len) {
       
  2422             pos += bytes;
       
  2423             *node = cur;
       
  2424             *indx = pos;
       
  2425             return(0);
       
  2426         }
       
  2427     }
       
  2428     return(-1);
       
  2429 }
       
  2430 
       
  2431 /**
       
  2432  * xmlXPtrMatchString:
       
  2433  * @param string the string to search
       
  2434  * @param start the start textnode
       
  2435  * @param startindex the start index
       
  2436  * @param end the end textnode IN/OUT
       
  2437  * @param endindex the end index IN/OUT
       
  2438  *
       
  2439  * Check whether the document contains string at the position
       
  2440  * (start, startindex) and limited by the (end, endindex) point
       
  2441  *
       
  2442  * Returns -1 in case of failure, 0 if not found, 1 if found in which case
       
  2443  *            (start, startindex) will indicate the position of the beginning
       
  2444  *            of the range and (end, endindex) will indicate the end
       
  2445  *            of the range
       
  2446  */
       
  2447 static int
       
  2448 xmlXPtrMatchString(const xmlChar *string, xmlNodePtr start, int startindex,
       
  2449                     xmlNodePtr *end, int *endindex) {
       
  2450     xmlNodePtr cur;
       
  2451     int pos; /* 0 based */
       
  2452     int len; /* in bytes */
       
  2453     int stringlen; /* in bytes */
       
  2454     int match;
       
  2455 
       
  2456     if (string == NULL)
       
  2457         return(-1);
       
  2458     if (start == NULL)
       
  2459         return(-1);
       
  2460     if ((end == NULL) || (endindex == NULL))
       
  2461         return(-1);
       
  2462     cur = start;
       
  2463     if (cur == NULL)
       
  2464         return(-1);
       
  2465     pos = startindex - 1;
       
  2466     stringlen = xmlStrlen(string);
       
  2467 
       
  2468     while (stringlen > 0) {
       
  2469         if ((cur == *end) && (pos + stringlen > *endindex))
       
  2470             return(0);
       
  2471 
       
  2472         if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
       
  2473             len = xmlStrlen(cur->content);
       
  2474             if (len >= pos + stringlen) {
       
  2475                 match = (!xmlStrncmp(&cur->content[pos], string, stringlen));
       
  2476                 if (match) {
       
  2477 #ifdef DEBUG_RANGES
       
  2478                     xmlGenericError(xmlGenericErrorContext,
       
  2479                             "found range %d bytes at index %d of ->",
       
  2480                             stringlen, pos + 1);
       
  2481                     xmlDebugDumpString(stdout, cur->content);
       
  2482                     xmlGenericError(xmlGenericErrorContext, "\n");
       
  2483 #endif
       
  2484                     *end = cur;
       
  2485                     *endindex = pos + stringlen;
       
  2486                     return(1);
       
  2487                 } else {
       
  2488                     return(0);
       
  2489                 }
       
  2490             } else {
       
  2491                 int sub = len - pos;
       
  2492                 match = (!xmlStrncmp(&cur->content[pos], string, sub));
       
  2493                 if (match) {
       
  2494 #ifdef DEBUG_RANGES
       
  2495                     xmlGenericError(xmlGenericErrorContext,
       
  2496                             "found subrange %d bytes at index %d of ->",
       
  2497                             sub, pos + 1);
       
  2498                     xmlDebugDumpString(stdout, cur->content);
       
  2499                     xmlGenericError(xmlGenericErrorContext, "\n");
       
  2500 #endif
       
  2501                     string = &string[sub];
       
  2502                     stringlen -= sub;
       
  2503                 } else {
       
  2504                     return(0);
       
  2505                 }
       
  2506             }
       
  2507         }
       
  2508         cur = xmlXPtrAdvanceNode(cur, NULL);
       
  2509         if (cur == NULL)
       
  2510             return(0);
       
  2511         pos = 0;
       
  2512     }
       
  2513     return(1);
       
  2514 }
       
  2515 
       
  2516 /**
       
  2517  * xmlXPtrSearchString:
       
  2518  * @param string the string to search
       
  2519  * @param start the start textnode IN/OUT
       
  2520  * @param startindex the start index IN/OUT
       
  2521  * @param end the end textnode
       
  2522  * @param endindex the end index
       
  2523  *
       
  2524  * Search the next occurrence of string within the document content
       
  2525  * until the (end, endindex) point is reached
       
  2526  *
       
  2527  * Returns -1 in case of failure, 0 if not found, 1 if found in which case
       
  2528  *            (start, startindex) will indicate the position of the beginning
       
  2529  *            of the range and (end, endindex) will indicate the end
       
  2530  *            of the range
       
  2531  */
       
  2532 static int
       
  2533 xmlXPtrSearchString(const xmlChar *string, xmlNodePtr *start, int *startindex,
       
  2534                     xmlNodePtr *end, int *endindex) {
       
  2535     xmlNodePtr cur;
       
  2536     const xmlChar *str;
       
  2537     int pos; /* 0 based */
       
  2538     int len; /* in bytes */
       
  2539     xmlChar first;
       
  2540 
       
  2541     if (string == NULL)
       
  2542         return(-1);
       
  2543     if ((start == NULL) || (startindex == NULL))
       
  2544         return(-1);
       
  2545     if ((end == NULL) || (endindex == NULL))
       
  2546         return(-1);
       
  2547     cur = *start;
       
  2548     if (cur == NULL)
       
  2549         return(-1);
       
  2550     pos = *startindex - 1;
       
  2551     first = string[0];
       
  2552 
       
  2553     while (cur != NULL) {
       
  2554         if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
       
  2555             len = xmlStrlen(cur->content);
       
  2556             while (pos <= len) {
       
  2557                 if (first != 0) {
       
  2558                     str = xmlStrchr(&cur->content[pos], first);
       
  2559                     if (str != NULL) {
       
  2560                         pos = (str - (xmlChar *)(cur->content));
       
  2561 #ifdef DEBUG_RANGES
       
  2562                         xmlGenericError(xmlGenericErrorContext,
       
  2563                                 "found '%c' at index %d of ->",
       
  2564                                 first, pos + 1);
       
  2565                         xmlDebugDumpString(stdout, cur->content);
       
  2566                         xmlGenericError(xmlGenericErrorContext, "\n");
       
  2567 #endif
       
  2568                         if (xmlXPtrMatchString(string, cur, pos + 1,
       
  2569                                                end, endindex)) {
       
  2570                             *start = cur;
       
  2571                             *startindex = pos + 1;
       
  2572                             return(1);
       
  2573                         }
       
  2574                         pos++;
       
  2575                     } else {
       
  2576                         pos = len + 1;
       
  2577                     }
       
  2578                 } else {
       
  2579                     /*
       
  2580                      * An empty string is considered to match before each
       
  2581                      * character of the string-value and after the final
       
  2582                      * character.
       
  2583                      */
       
  2584 #ifdef DEBUG_RANGES
       
  2585                     xmlGenericError(xmlGenericErrorContext,
       
  2586                             "found '' at index %d of ->",
       
  2587                             pos + 1);
       
  2588                     xmlDebugDumpString(stdout, cur->content);
       
  2589                     xmlGenericError(xmlGenericErrorContext, "\n");
       
  2590 #endif
       
  2591                     *start = cur;
       
  2592                     *startindex = pos + 1;
       
  2593                     *end = cur;
       
  2594                     *endindex = pos + 1;
       
  2595                     return(1);
       
  2596                 }
       
  2597             }
       
  2598         }
       
  2599         if ((cur == *end) && (pos >= *endindex))
       
  2600             return(0);
       
  2601         cur = xmlXPtrAdvanceNode(cur, NULL);
       
  2602         if (cur == NULL)
       
  2603             return(0);
       
  2604         pos = 1;
       
  2605     }
       
  2606     return(0);
       
  2607 }
       
  2608 
       
  2609 /**
       
  2610  * xmlXPtrGetLastChar:
       
  2611  * @param node the node
       
  2612  * @param index the index
       
  2613  *
       
  2614  * Computes the point coordinates of the last char of this point
       
  2615  *
       
  2616  * Returns -1 in case of failure, 0 otherwise
       
  2617  */
       
  2618 static int
       
  2619 xmlXPtrGetLastChar(xmlNodePtr *node, int *indx) {
       
  2620     xmlNodePtr cur;
       
  2621     int pos, len = 0;
       
  2622 
       
  2623     if ((node == NULL) || (indx == NULL))
       
  2624         return(-1);
       
  2625     cur = *node;
       
  2626     pos = *indx;
       
  2627 
       
  2628     if (cur == NULL)
       
  2629         return(-1);
       
  2630 
       
  2631     if ((cur->type == XML_ELEMENT_NODE) ||
       
  2632         (cur->type == XML_DOCUMENT_NODE) ||
       
  2633         (cur->type == XML_HTML_DOCUMENT_NODE)) {
       
  2634         if (pos > 0) {
       
  2635             cur = xmlXPtrGetNthChild(cur, pos);
       
  2636             pos = 0;
       
  2637         }
       
  2638     }
       
  2639     while (cur != NULL) {
       
  2640         if (cur->last != NULL)
       
  2641             cur = cur->last;
       
  2642         else if ((cur->type != XML_ELEMENT_NODE) &&
       
  2643                  (cur->content != NULL)) {
       
  2644             len = xmlStrlen(cur->content);
       
  2645             break;
       
  2646         } else {
       
  2647             return(-1);
       
  2648         }
       
  2649     }
       
  2650     if (cur == NULL)
       
  2651         return(-1);
       
  2652     *node = cur;
       
  2653     *indx = len;
       
  2654     return(0);
       
  2655 }
       
  2656 
       
  2657 /**
       
  2658  * xmlXPtrGetStartPoint:
       
  2659  * @param obj an range
       
  2660  * @param node the resulting node
       
  2661  * @param indx the resulting index
       
  2662  *
       
  2663  * read the object and return the start point coordinates.
       
  2664  *
       
  2665  * Returns -1 in case of failure, 0 otherwise
       
  2666  */
       
  2667 static int
       
  2668 xmlXPtrGetStartPoint(xmlXPathObjectPtr obj, xmlNodePtr *node, int *indx) {
       
  2669     if ((obj == NULL) || (node == NULL) || (indx == NULL))
       
  2670         return(-1);
       
  2671 
       
  2672     switch (obj->type) {
       
  2673         case XPATH_POINT:
       
  2674             *node = obj->user;
       
  2675             if (obj->index <= 0)
       
  2676                 *indx = 0;
       
  2677             else
       
  2678                 *indx = obj->index;
       
  2679             return(0);
       
  2680         case XPATH_RANGE:
       
  2681             *node = obj->user;
       
  2682             if (obj->index <= 0)
       
  2683                 *indx = 0;
       
  2684             else
       
  2685                 *indx = obj->index;
       
  2686             return(0);
       
  2687         default:
       
  2688             break;
       
  2689     }
       
  2690     return(-1);
       
  2691 }
       
  2692 
       
  2693 /**
       
  2694  * xmlXPtrGetEndPoint:
       
  2695  * @param obj an range
       
  2696  * @param node the resulting node
       
  2697  * @param indx the resulting indx
       
  2698  *
       
  2699  * read the object and return the end point coordinates.
       
  2700  *
       
  2701  * Returns -1 in case of failure, 0 otherwise
       
  2702  */
       
  2703 static int
       
  2704 xmlXPtrGetEndPoint(xmlXPathObjectPtr obj, xmlNodePtr *node, int *indx) {
       
  2705     if ((obj == NULL) || (node == NULL) || (indx == NULL))
       
  2706         return(-1);
       
  2707 
       
  2708     switch (obj->type) {
       
  2709         case XPATH_POINT:
       
  2710             *node = obj->user;
       
  2711             if (obj->index <= 0)
       
  2712                 *indx = 0;
       
  2713             else
       
  2714                 *indx = obj->index;
       
  2715             return(0);
       
  2716         case XPATH_RANGE:
       
  2717             *node = obj->user;
       
  2718             if (obj->index <= 0)
       
  2719                 *indx = 0;
       
  2720             else
       
  2721                 *indx = obj->index;
       
  2722             return(0);
       
  2723         default:
       
  2724             break;
       
  2725     }
       
  2726     return(-1);
       
  2727 }
       
  2728 
       
  2729 /**
       
  2730  * xmlXPtrStringRangeFunction:
       
  2731  * @param ctxt the XPointer Parser context
       
  2732  * @param nargs the number of args
       
  2733  *
       
  2734  * Function implementing the string-range() function
       
  2735  * range as described in 5.4.2
       
  2736  *
       
  2737  * ------------------------------
       
  2738  * [Definition: For each location in the location-set argument,
       
  2739  * string-range returns a set of string ranges, a set of substrings in a
       
  2740  * string. Specifically, the string-value of the location is searched for
       
  2741  * substrings that match the string argument, and the resulting location-set
       
  2742  * will contain a range location for each non-overlapping match.]
       
  2743  * An empty string is considered to match before each character of the
       
  2744  * string-value and after the final character. Whitespace in a string
       
  2745  * is matched literally, with no normalization except that provided by
       
  2746  * XML for line ends. The third argument gives the position of the first
       
  2747  * character to be in the resulting range, relative to the start of the
       
  2748  * match. The default value is 1, which makes the range start immediately
       
  2749  * before the first character of the matched string. The fourth argument
       
  2750  * gives the number of characters in the range; the default is that the
       
  2751  * range extends to the end of the matched string.
       
  2752  *
       
  2753  * Element boundaries, as well as entire embedded nodes such as processing
       
  2754  * instructions and comments, are ignored as defined in [XPath].
       
  2755  *
       
  2756  * If the string in the second argument is not found in the string-value
       
  2757  * of the location, or if a value in the third or fourth argument indicates
       
  2758  * a string that is beyond the beginning or end of the document, the
       
  2759  * expression fails.
       
  2760  *
       
  2761  * The points of the range-locations in the returned location-set will
       
  2762  * all be character points.
       
  2763  * ------------------------------
       
  2764  */
       
  2765 void
       
  2766 xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
       
  2767     int i, startindex, fendindex;
       
  2768     int endindex = 0;
       
  2769     xmlNodePtr start, end, fend;
       
  2770     xmlXPathObjectPtr set;
       
  2771     xmlLocationSetPtr oldset;
       
  2772     xmlLocationSetPtr newset;
       
  2773     xmlXPathObjectPtr string;
       
  2774     xmlXPathObjectPtr position = NULL;
       
  2775     xmlXPathObjectPtr number = NULL;
       
  2776     int found, pos = 0, num = 0;
       
  2777 
       
  2778     /*
       
  2779      * Grab the arguments
       
  2780      */
       
  2781     if ((nargs < 2) || (nargs > 4))
       
  2782         XP_ERROR(XPATH_INVALID_ARITY);
       
  2783 
       
  2784     if (nargs >= 4) {
       
  2785         CHECK_TYPE(XPATH_NUMBER);
       
  2786         number = valuePop(ctxt);
       
  2787         if (number != NULL)
       
  2788             num = (int) number->floatval;
       
  2789     }
       
  2790     if (nargs >= 3) {
       
  2791         CHECK_TYPE(XPATH_NUMBER);
       
  2792         position = valuePop(ctxt);
       
  2793         if (position != NULL)
       
  2794             pos = (int) position->floatval;
       
  2795     }
       
  2796     CHECK_TYPE(XPATH_STRING);
       
  2797     string = valuePop(ctxt);
       
  2798     if ((ctxt->value == NULL) ||
       
  2799         ((ctxt->value->type != XPATH_LOCATIONSET) &&
       
  2800          (ctxt->value->type != XPATH_NODESET)))
       
  2801         XP_ERROR(XPATH_INVALID_TYPE)
       
  2802 
       
  2803     set = valuePop(ctxt);
       
  2804     newset = xmlXPtrLocationSetCreate(NULL);
       
  2805     if (set->nodesetval == NULL) {
       
  2806         goto error;
       
  2807     }
       
  2808     if (set->type == XPATH_NODESET) {
       
  2809         xmlXPathObjectPtr tmp;
       
  2810 
       
  2811         /*
       
  2812          * First convert to a location set
       
  2813          */
       
  2814         tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval);
       
  2815         xmlXPathFreeObject(set);
       
  2816         set = tmp;
       
  2817     }
       
  2818     oldset = (xmlLocationSetPtr) set->user;
       
  2819 
       
  2820     /*
       
  2821      * The loop is to search for each element in the location set
       
  2822      * the list of location set corresponding to that search
       
  2823      */
       
  2824     for (i = 0;i < oldset->locNr;i++) {
       
  2825 #ifdef DEBUG_RANGES
       
  2826         xmlXPathDebugDumpObject(stdout, oldset->locTab[i], 0);
       
  2827 #endif
       
  2828 
       
  2829         xmlXPtrGetStartPoint(oldset->locTab[i], &start, &startindex);
       
  2830         xmlXPtrGetEndPoint(oldset->locTab[i], &end, &endindex);
       
  2831         xmlXPtrAdvanceChar(&start, &startindex, 0);
       
  2832         xmlXPtrGetLastChar(&end, &endindex);
       
  2833 
       
  2834 #ifdef DEBUG_RANGES
       
  2835         xmlGenericError(xmlGenericErrorContext,
       
  2836                 "from index %d of ->", startindex);
       
  2837         xmlDebugDumpString(stdout, start->content);
       
  2838         xmlGenericError(xmlGenericErrorContext, "\n");
       
  2839         xmlGenericError(xmlGenericErrorContext,
       
  2840                 "to index %d of ->", endindex);
       
  2841         xmlDebugDumpString(stdout, end->content);
       
  2842         xmlGenericError(xmlGenericErrorContext, "\n");
       
  2843 #endif
       
  2844         do {
       
  2845             fend = end;
       
  2846             fendindex = endindex;
       
  2847             found = xmlXPtrSearchString(string->stringval, &start, &startindex,
       
  2848                                         &fend, &fendindex);
       
  2849             if (found == 1) {
       
  2850                 if (position == NULL) {
       
  2851                     xmlXPtrLocationSetAdd(newset,
       
  2852                          xmlXPtrNewRange(start, startindex, fend, fendindex));
       
  2853                 } else if (xmlXPtrAdvanceChar(&start, &startindex,
       
  2854                                               pos - 1) == 0) {
       
  2855                     if ((number != NULL) && (num > 0)) {
       
  2856                         int rindx;
       
  2857                         xmlNodePtr rend;
       
  2858                         rend = start;
       
  2859                         rindx = startindex - 1;
       
  2860                         if (xmlXPtrAdvanceChar(&rend, &rindx,
       
  2861                                                num) == 0) {
       
  2862                             xmlXPtrLocationSetAdd(newset,
       
  2863                                         xmlXPtrNewRange(start, startindex,
       
  2864                                                         rend, rindx));
       
  2865                         }
       
  2866                     } else if ((number != NULL) && (num <= 0)) {
       
  2867                         xmlXPtrLocationSetAdd(newset,
       
  2868                                     xmlXPtrNewRange(start, startindex,
       
  2869                                                     start, startindex));
       
  2870                     } else {
       
  2871                         xmlXPtrLocationSetAdd(newset,
       
  2872                                     xmlXPtrNewRange(start, startindex,
       
  2873                                                     fend, fendindex));
       
  2874                     }
       
  2875                 }
       
  2876                 start = fend;
       
  2877                 startindex = fendindex;
       
  2878                 if (string->stringval[0] == 0)
       
  2879                     startindex++;
       
  2880             }
       
  2881         } while (found == 1);
       
  2882     }
       
  2883 
       
  2884     /*
       
  2885      * Save the new value and cleanup
       
  2886      */
       
  2887 error:
       
  2888     valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
       
  2889     xmlXPathFreeObject(set);
       
  2890     xmlXPathFreeObject(string);
       
  2891     if (position) xmlXPathFreeObject(position);
       
  2892     if (number) xmlXPathFreeObject(number);
       
  2893 }
       
  2894 
       
  2895 /**
       
  2896  * xmlXPtrEvalRangePredicate:
       
  2897  * @param ctxt the XPointer Parser context
       
  2898  *
       
  2899  *  [8]   Predicate ::=   '[' PredicateExpr ']'
       
  2900  *  [9]   PredicateExpr ::=   Expr
       
  2901  *
       
  2902  * Evaluate a predicate as in xmlXPathEvalPredicate() but for
       
  2903  * a Location Set instead of a node set
       
  2904  */
       
  2905 XMLPUBFUNEXPORT void
       
  2906 xmlXPtrEvalRangePredicate(xmlXPathParserContextPtr ctxt) {
       
  2907     const xmlChar *cur;
       
  2908     xmlXPathObjectPtr res;
       
  2909     xmlXPathObjectPtr obj, tmp;
       
  2910     xmlLocationSetPtr newset = NULL;
       
  2911     xmlLocationSetPtr oldset;
       
  2912     int i;
       
  2913 
       
  2914     SKIP_BLANKS;
       
  2915     if (CUR != '[') {
       
  2916         XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
       
  2917     }
       
  2918     NEXT;
       
  2919     SKIP_BLANKS;
       
  2920 
       
  2921     /*
       
  2922      * Extract the old set, and then evaluate the result of the
       
  2923      * expression for all the element in the set. use it to grow
       
  2924      * up a new set.
       
  2925      */
       
  2926     CHECK_TYPE(XPATH_LOCATIONSET);
       
  2927     obj = valuePop(ctxt);
       
  2928     oldset = obj->user;
       
  2929     ctxt->context->node = NULL;
       
  2930 
       
  2931     if ((oldset == NULL) || (oldset->locNr == 0)) {
       
  2932         ctxt->context->contextSize = 0;
       
  2933         ctxt->context->proximityPosition = 0;
       
  2934         xmlXPathEvalExpr(ctxt);
       
  2935         res = valuePop(ctxt);
       
  2936         if (res != NULL)
       
  2937             xmlXPathFreeObject(res);
       
  2938         valuePush(ctxt, obj);
       
  2939         CHECK_ERROR;
       
  2940     } else {
       
  2941         /*
       
  2942          * Save the expression pointer since we will have to evaluate
       
  2943          * it multiple times. Initialize the new set.
       
  2944          */
       
  2945         cur = ctxt->cur;
       
  2946         newset = xmlXPtrLocationSetCreate(NULL);
       
  2947 
       
  2948         for (i = 0; i < oldset->locNr; i++) {
       
  2949             ctxt->cur = cur;
       
  2950 
       
  2951             /*
       
  2952              * Run the evaluation with a node list made of a single item
       
  2953              * in the nodeset.
       
  2954              */
       
  2955             ctxt->context->node = oldset->locTab[i]->user;
       
  2956             tmp = xmlXPathNewNodeSet(ctxt->context->node);
       
  2957             valuePush(ctxt, tmp);
       
  2958             ctxt->context->contextSize = oldset->locNr;
       
  2959             ctxt->context->proximityPosition = i + 1;
       
  2960 
       
  2961             xmlXPathEvalExpr(ctxt);
       
  2962             CHECK_ERROR;
       
  2963 
       
  2964             /*
       
  2965              * The result of the evaluation need to be tested to
       
  2966              * decided whether the filter succeeded or not
       
  2967              */
       
  2968             res = valuePop(ctxt);
       
  2969             if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
       
  2970                 xmlXPtrLocationSetAdd(newset,
       
  2971                         xmlXPathObjectCopy(oldset->locTab[i]));
       
  2972             }
       
  2973 
       
  2974             /*
       
  2975              * Cleanup
       
  2976              */
       
  2977             if (res != NULL)
       
  2978                 xmlXPathFreeObject(res);
       
  2979             if (ctxt->value == tmp) {
       
  2980                 res = valuePop(ctxt);
       
  2981                 xmlXPathFreeObject(res);
       
  2982             }
       
  2983 
       
  2984             ctxt->context->node = NULL;
       
  2985         }
       
  2986 
       
  2987         /*
       
  2988          * The result is used as the new evaluation set.
       
  2989          */
       
  2990         xmlXPathFreeObject(obj);
       
  2991         ctxt->context->node = NULL;
       
  2992         ctxt->context->contextSize = -1;
       
  2993         ctxt->context->proximityPosition = -1;
       
  2994         valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
       
  2995     }
       
  2996     if (CUR != ']') {
       
  2997         XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
       
  2998     }
       
  2999 
       
  3000     NEXT;
       
  3001     SKIP_BLANKS;
       
  3002 }
       
  3003 
       
  3004 #else
       
  3005 #endif
       
  3006