Coverage Report

Created: 2025-08-04 07:15

/src/libxml2-2.9.7/xpath.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * xpath.c: XML Path Language implementation
3
 *          XPath is a language for addressing parts of an XML document,
4
 *          designed to be used by both XSLT and XPointer
5
 *f
6
 * Reference: W3C Recommendation 16 November 1999
7
 *     http://www.w3.org/TR/1999/REC-xpath-19991116
8
 * Public reference:
9
 *     http://www.w3.org/TR/xpath
10
 *
11
 * See Copyright for the status of this software
12
 *
13
 * Author: daniel@veillard.com
14
 *
15
 */
16
17
/* To avoid EBCDIC trouble when parsing on zOS */
18
#if defined(__MVS__)
19
#pragma convert("ISO8859-1")
20
#endif
21
22
#define IN_LIBXML
23
#include "libxml.h"
24
25
#include <limits.h>
26
#include <string.h>
27
#include <stddef.h>
28
29
#ifdef HAVE_SYS_TYPES_H
30
#include <sys/types.h>
31
#endif
32
#ifdef HAVE_MATH_H
33
#include <math.h>
34
#endif
35
#ifdef HAVE_FLOAT_H
36
#include <float.h>
37
#endif
38
#ifdef HAVE_CTYPE_H
39
#include <ctype.h>
40
#endif
41
#ifdef HAVE_SIGNAL_H
42
#include <signal.h>
43
#endif
44
45
#include <libxml/xmlmemory.h>
46
#include <libxml/tree.h>
47
#include <libxml/valid.h>
48
#include <libxml/xpath.h>
49
#include <libxml/xpathInternals.h>
50
#include <libxml/parserInternals.h>
51
#include <libxml/hash.h>
52
#ifdef LIBXML_XPTR_ENABLED
53
#include <libxml/xpointer.h>
54
#endif
55
#ifdef LIBXML_DEBUG_ENABLED
56
#include <libxml/debugXML.h>
57
#endif
58
#include <libxml/xmlerror.h>
59
#include <libxml/threads.h>
60
#include <libxml/globals.h>
61
#ifdef LIBXML_PATTERN_ENABLED
62
#include <libxml/pattern.h>
63
#endif
64
65
#include "buf.h"
66
67
#ifdef LIBXML_PATTERN_ENABLED
68
#define XPATH_STREAMING
69
#endif
70
71
#define TODO                \
72
0
    xmlGenericError(xmlGenericErrorContext,       \
73
0
      "Unimplemented block at %s:%d\n",       \
74
0
            __FILE__, __LINE__);
75
76
/**
77
 * WITH_TIM_SORT:
78
 *
79
 * Use the Timsort algorithm provided in timsort.h to sort
80
 * nodeset as this is a great improvement over the old Shell sort
81
 * used in xmlXPathNodeSetSort()
82
 */
83
#define WITH_TIM_SORT
84
85
/*
86
* XP_OPTIMIZED_NON_ELEM_COMPARISON:
87
* If defined, this will use xmlXPathCmpNodesExt() instead of
88
* xmlXPathCmpNodes(). The new function is optimized comparison of
89
* non-element nodes; actually it will speed up comparison only if
90
* xmlXPathOrderDocElems() was called in order to index the elements of
91
* a tree in document order; Libxslt does such an indexing, thus it will
92
* benefit from this optimization.
93
*/
94
#define XP_OPTIMIZED_NON_ELEM_COMPARISON
95
96
/*
97
* XP_OPTIMIZED_FILTER_FIRST:
98
* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
99
* in a way, that it stop evaluation at the first node.
100
*/
101
#define XP_OPTIMIZED_FILTER_FIRST
102
103
/*
104
* XP_DEBUG_OBJ_USAGE:
105
* Internal flag to enable tracking of how much XPath objects have been
106
* created.
107
*/
108
/* #define XP_DEBUG_OBJ_USAGE */
109
110
/*
111
 * XPATH_MAX_STEPS:
112
 * when compiling an XPath expression we arbitrary limit the maximum
113
 * number of step operation in the compiled expression. 1000000 is
114
 * an insanely large value which should never be reached under normal
115
 * circumstances
116
 */
117
0
#define XPATH_MAX_STEPS 1000000
118
119
/*
120
 * XPATH_MAX_STACK_DEPTH:
121
 * when evaluating an XPath expression we arbitrary limit the maximum
122
 * number of object allowed to be pushed on the stack. 1000000 is
123
 * an insanely large value which should never be reached under normal
124
 * circumstances
125
 */
126
0
#define XPATH_MAX_STACK_DEPTH 1000000
127
128
/*
129
 * XPATH_MAX_NODESET_LENGTH:
130
 * when evaluating an XPath expression nodesets are created and we
131
 * arbitrary limit the maximum length of those node set. 10000000 is
132
 * an insanely large value which should never be reached under normal
133
 * circumstances, one would first need to construct an in memory tree
134
 * with more than 10 millions nodes.
135
 */
136
0
#define XPATH_MAX_NODESET_LENGTH 10000000
137
138
/*
139
 * TODO:
140
 * There are a few spots where some tests are done which depend upon ascii
141
 * data.  These should be enhanced for full UTF8 support (see particularly
142
 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
143
 */
144
145
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
146
/**
147
 * xmlXPathCmpNodesExt:
148
 * @node1:  the first node
149
 * @node2:  the second node
150
 *
151
 * Compare two nodes w.r.t document order.
152
 * This one is optimized for handling of non-element nodes.
153
 *
154
 * Returns -2 in case of error 1 if first point < second point, 0 if
155
 *         it's the same node, -1 otherwise
156
 */
157
static int
158
0
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
159
0
    int depth1, depth2;
160
0
    int misc = 0, precedence1 = 0, precedence2 = 0;
161
0
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
162
0
    xmlNodePtr cur, root;
163
0
    ptrdiff_t l1, l2;
164
165
0
    if ((node1 == NULL) || (node2 == NULL))
166
0
  return(-2);
167
168
0
    if (node1 == node2)
169
0
  return(0);
170
171
    /*
172
     * a couple of optimizations which will avoid computations in most cases
173
     */
174
0
    switch (node1->type) {
175
0
  case XML_ELEMENT_NODE:
176
0
      if (node2->type == XML_ELEMENT_NODE) {
177
0
    if ((0 > (ptrdiff_t) node1->content) &&
178
0
        (0 > (ptrdiff_t) node2->content) &&
179
0
        (node1->doc == node2->doc))
180
0
    {
181
0
        l1 = -((ptrdiff_t) node1->content);
182
0
        l2 = -((ptrdiff_t) node2->content);
183
0
        if (l1 < l2)
184
0
      return(1);
185
0
        if (l1 > l2)
186
0
      return(-1);
187
0
    } else
188
0
        goto turtle_comparison;
189
0
      }
190
0
      break;
191
0
  case XML_ATTRIBUTE_NODE:
192
0
      precedence1 = 1; /* element is owner */
193
0
      miscNode1 = node1;
194
0
      node1 = node1->parent;
195
0
      misc = 1;
196
0
      break;
197
0
  case XML_TEXT_NODE:
198
0
  case XML_CDATA_SECTION_NODE:
199
0
  case XML_COMMENT_NODE:
200
0
  case XML_PI_NODE: {
201
0
      miscNode1 = node1;
202
      /*
203
      * Find nearest element node.
204
      */
205
0
      if (node1->prev != NULL) {
206
0
    do {
207
0
        node1 = node1->prev;
208
0
        if (node1->type == XML_ELEMENT_NODE) {
209
0
      precedence1 = 3; /* element in prev-sibl axis */
210
0
      break;
211
0
        }
212
0
        if (node1->prev == NULL) {
213
0
      precedence1 = 2; /* element is parent */
214
      /*
215
      * URGENT TODO: Are there any cases, where the
216
      * parent of such a node is not an element node?
217
      */
218
0
      node1 = node1->parent;
219
0
      break;
220
0
        }
221
0
    } while (1);
222
0
      } else {
223
0
    precedence1 = 2; /* element is parent */
224
0
    node1 = node1->parent;
225
0
      }
226
0
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
227
0
    (0 <= (ptrdiff_t) node1->content)) {
228
    /*
229
    * Fallback for whatever case.
230
    */
231
0
    node1 = miscNode1;
232
0
    precedence1 = 0;
233
0
      } else
234
0
    misc = 1;
235
0
  }
236
0
      break;
237
0
  case XML_NAMESPACE_DECL:
238
      /*
239
      * TODO: why do we return 1 for namespace nodes?
240
      */
241
0
      return(1);
242
0
  default:
243
0
      break;
244
0
    }
245
0
    switch (node2->type) {
246
0
  case XML_ELEMENT_NODE:
247
0
      break;
248
0
  case XML_ATTRIBUTE_NODE:
249
0
      precedence2 = 1; /* element is owner */
250
0
      miscNode2 = node2;
251
0
      node2 = node2->parent;
252
0
      misc = 1;
253
0
      break;
254
0
  case XML_TEXT_NODE:
255
0
  case XML_CDATA_SECTION_NODE:
256
0
  case XML_COMMENT_NODE:
257
0
  case XML_PI_NODE: {
258
0
      miscNode2 = node2;
259
0
      if (node2->prev != NULL) {
260
0
    do {
261
0
        node2 = node2->prev;
262
0
        if (node2->type == XML_ELEMENT_NODE) {
263
0
      precedence2 = 3; /* element in prev-sibl axis */
264
0
      break;
265
0
        }
266
0
        if (node2->prev == NULL) {
267
0
      precedence2 = 2; /* element is parent */
268
0
      node2 = node2->parent;
269
0
      break;
270
0
        }
271
0
    } while (1);
272
0
      } else {
273
0
    precedence2 = 2; /* element is parent */
274
0
    node2 = node2->parent;
275
0
      }
276
0
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
277
0
    (0 <= (ptrdiff_t) node2->content))
278
0
      {
279
0
    node2 = miscNode2;
280
0
    precedence2 = 0;
281
0
      } else
282
0
    misc = 1;
283
0
  }
284
0
      break;
285
0
  case XML_NAMESPACE_DECL:
286
0
      return(1);
287
0
  default:
288
0
      break;
289
0
    }
290
0
    if (misc) {
291
0
  if (node1 == node2) {
292
0
      if (precedence1 == precedence2) {
293
    /*
294
    * The ugly case; but normally there aren't many
295
    * adjacent non-element nodes around.
296
    */
297
0
    cur = miscNode2->prev;
298
0
    while (cur != NULL) {
299
0
        if (cur == miscNode1)
300
0
      return(1);
301
0
        if (cur->type == XML_ELEMENT_NODE)
302
0
      return(-1);
303
0
        cur = cur->prev;
304
0
    }
305
0
    return (-1);
306
0
      } else {
307
    /*
308
    * Evaluate based on higher precedence wrt to the element.
309
    * TODO: This assumes attributes are sorted before content.
310
    *   Is this 100% correct?
311
    */
312
0
    if (precedence1 < precedence2)
313
0
        return(1);
314
0
    else
315
0
        return(-1);
316
0
      }
317
0
  }
318
  /*
319
  * Special case: One of the helper-elements is contained by the other.
320
  * <foo>
321
  *   <node2>
322
  *     <node1>Text-1(precedence1 == 2)</node1>
323
  *   </node2>
324
  *   Text-6(precedence2 == 3)
325
  * </foo>
326
  */
327
0
  if ((precedence2 == 3) && (precedence1 > 1)) {
328
0
      cur = node1->parent;
329
0
      while (cur) {
330
0
    if (cur == node2)
331
0
        return(1);
332
0
    cur = cur->parent;
333
0
      }
334
0
  }
335
0
  if ((precedence1 == 3) && (precedence2 > 1)) {
336
0
      cur = node2->parent;
337
0
      while (cur) {
338
0
    if (cur == node1)
339
0
        return(-1);
340
0
    cur = cur->parent;
341
0
      }
342
0
  }
343
0
    }
344
345
    /*
346
     * Speedup using document order if availble.
347
     */
348
0
    if ((node1->type == XML_ELEMENT_NODE) &&
349
0
  (node2->type == XML_ELEMENT_NODE) &&
350
0
  (0 > (ptrdiff_t) node1->content) &&
351
0
  (0 > (ptrdiff_t) node2->content) &&
352
0
  (node1->doc == node2->doc)) {
353
354
0
  l1 = -((ptrdiff_t) node1->content);
355
0
  l2 = -((ptrdiff_t) node2->content);
356
0
  if (l1 < l2)
357
0
      return(1);
358
0
  if (l1 > l2)
359
0
      return(-1);
360
0
    }
361
362
0
turtle_comparison:
363
364
0
    if (node1 == node2->prev)
365
0
  return(1);
366
0
    if (node1 == node2->next)
367
0
  return(-1);
368
    /*
369
     * compute depth to root
370
     */
371
0
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
372
0
  if (cur->parent == node1)
373
0
      return(1);
374
0
  depth2++;
375
0
    }
376
0
    root = cur;
377
0
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
378
0
  if (cur->parent == node2)
379
0
      return(-1);
380
0
  depth1++;
381
0
    }
382
    /*
383
     * Distinct document (or distinct entities :-( ) case.
384
     */
385
0
    if (root != cur) {
386
0
  return(-2);
387
0
    }
388
    /*
389
     * get the nearest common ancestor.
390
     */
391
0
    while (depth1 > depth2) {
392
0
  depth1--;
393
0
  node1 = node1->parent;
394
0
    }
395
0
    while (depth2 > depth1) {
396
0
  depth2--;
397
0
  node2 = node2->parent;
398
0
    }
399
0
    while (node1->parent != node2->parent) {
400
0
  node1 = node1->parent;
401
0
  node2 = node2->parent;
402
  /* should not happen but just in case ... */
403
0
  if ((node1 == NULL) || (node2 == NULL))
404
0
      return(-2);
405
0
    }
406
    /*
407
     * Find who's first.
408
     */
409
0
    if (node1 == node2->prev)
410
0
  return(1);
411
0
    if (node1 == node2->next)
412
0
  return(-1);
413
    /*
414
     * Speedup using document order if availble.
415
     */
416
0
    if ((node1->type == XML_ELEMENT_NODE) &&
417
0
  (node2->type == XML_ELEMENT_NODE) &&
418
0
  (0 > (ptrdiff_t) node1->content) &&
419
0
  (0 > (ptrdiff_t) node2->content) &&
420
0
  (node1->doc == node2->doc)) {
421
422
0
  l1 = -((ptrdiff_t) node1->content);
423
0
  l2 = -((ptrdiff_t) node2->content);
424
0
  if (l1 < l2)
425
0
      return(1);
426
0
  if (l1 > l2)
427
0
      return(-1);
428
0
    }
429
430
0
    for (cur = node1->next;cur != NULL;cur = cur->next)
431
0
  if (cur == node2)
432
0
      return(1);
433
0
    return(-1); /* assume there is no sibling list corruption */
434
0
}
435
#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
436
437
/*
438
 * Wrapper for the Timsort argorithm from timsort.h
439
 */
440
#ifdef WITH_TIM_SORT
441
#define SORT_NAME libxml_domnode
442
0
#define SORT_TYPE xmlNodePtr
443
/**
444
 * wrap_cmp:
445
 * @x: a node
446
 * @y: another node
447
 *
448
 * Comparison function for the Timsort implementation
449
 *
450
 * Returns -2 in case of error -1 if first point < second point, 0 if
451
 *         it's the same node, +1 otherwise
452
 */
453
static
454
int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
455
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
456
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
457
0
    {
458
0
        int res = xmlXPathCmpNodesExt(x, y);
459
0
        return res == -2 ? res : -res;
460
0
    }
461
#else
462
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
463
    {
464
        int res = xmlXPathCmpNodes(x, y);
465
        return res == -2 ? res : -res;
466
    }
467
#endif
468
0
#define SORT_CMP(x, y)  (wrap_cmp(x, y))
469
#include "timsort.h"
470
#endif /* WITH_TIM_SORT */
471
472
#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
473
474
/************************************************************************
475
 *                  *
476
 *      Floating point stuff        *
477
 *                  *
478
 ************************************************************************/
479
480
#ifndef TRIO_REPLACE_STDIO
481
#define TRIO_PUBLIC static
482
#endif
483
#include "trionan.c"
484
485
/*
486
 * The lack of portability of this section of the libc is annoying !
487
 */
488
double xmlXPathNAN = 0;
489
double xmlXPathPINF = 1;
490
double xmlXPathNINF = -1;
491
static double xmlXPathNZERO = 0; /* not exported from headers */
492
static int xmlXPathInitialized = 0;
493
494
/**
495
 * xmlXPathInit:
496
 *
497
 * Initialize the XPath environment
498
 */
499
void
500
14
xmlXPathInit(void) {
501
14
    if (xmlXPathInitialized) return;
502
503
14
    xmlXPathPINF = trio_pinf();
504
14
    xmlXPathNINF = trio_ninf();
505
14
    xmlXPathNAN = trio_nan();
506
14
    xmlXPathNZERO = trio_nzero();
507
508
14
    xmlXPathInitialized = 1;
509
14
}
510
511
/**
512
 * xmlXPathIsNaN:
513
 * @val:  a double value
514
 *
515
 * Provides a portable isnan() function to detect whether a double
516
 * is a NotaNumber. Based on trio code
517
 * http://sourceforge.net/projects/ctrio/
518
 *
519
 * Returns 1 if the value is a NaN, 0 otherwise
520
 */
521
int
522
0
xmlXPathIsNaN(double val) {
523
0
    return(trio_isnan(val));
524
0
}
525
526
/**
527
 * xmlXPathIsInf:
528
 * @val:  a double value
529
 *
530
 * Provides a portable isinf() function to detect whether a double
531
 * is a +Infinite or -Infinite. Based on trio code
532
 * http://sourceforge.net/projects/ctrio/
533
 *
534
 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
535
 */
536
int
537
0
xmlXPathIsInf(double val) {
538
0
    return(trio_isinf(val));
539
0
}
540
541
#endif /* SCHEMAS or XPATH */
542
#ifdef LIBXML_XPATH_ENABLED
543
/**
544
 * xmlXPathGetSign:
545
 * @val:  a double value
546
 *
547
 * Provides a portable function to detect the sign of a double
548
 * Modified from trio code
549
 * http://sourceforge.net/projects/ctrio/
550
 *
551
 * Returns 1 if the value is Negative, 0 if positive
552
 */
553
static int
554
0
xmlXPathGetSign(double val) {
555
0
    return(trio_signbit(val));
556
0
}
557
558
559
/*
560
 * TODO: when compatibility allows remove all "fake node libxslt" strings
561
 *       the test should just be name[0] = ' '
562
 */
563
#ifdef DEBUG_XPATH_EXPRESSION
564
#define DEBUG_STEP
565
#define DEBUG_EXPR
566
#define DEBUG_EVAL_COUNTS
567
#endif
568
569
static xmlNs xmlXPathXMLNamespaceStruct = {
570
    NULL,
571
    XML_NAMESPACE_DECL,
572
    XML_XML_NAMESPACE,
573
    BAD_CAST "xml",
574
    NULL,
575
    NULL
576
};
577
static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
578
#ifndef LIBXML_THREAD_ENABLED
579
/*
580
 * Optimizer is disabled only when threaded apps are detected while
581
 * the library ain't compiled for thread safety.
582
 */
583
static int xmlXPathDisableOptimizer = 0;
584
#endif
585
586
/************************************************************************
587
 *                  *
588
 *      Error handling routines       *
589
 *                  *
590
 ************************************************************************/
591
592
/**
593
 * XP_ERRORNULL:
594
 * @X:  the error code
595
 *
596
 * Macro to raise an XPath error and return NULL.
597
 */
598
#define XP_ERRORNULL(X)             \
599
0
    { xmlXPathErr(ctxt, X); return(NULL); }
600
601
/*
602
 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
603
 */
604
static const char *xmlXPathErrorMessages[] = {
605
    "Ok\n",
606
    "Number encoding\n",
607
    "Unfinished literal\n",
608
    "Start of literal\n",
609
    "Expected $ for variable reference\n",
610
    "Undefined variable\n",
611
    "Invalid predicate\n",
612
    "Invalid expression\n",
613
    "Missing closing curly brace\n",
614
    "Unregistered function\n",
615
    "Invalid operand\n",
616
    "Invalid type\n",
617
    "Invalid number of arguments\n",
618
    "Invalid context size\n",
619
    "Invalid context position\n",
620
    "Memory allocation error\n",
621
    "Syntax error\n",
622
    "Resource error\n",
623
    "Sub resource error\n",
624
    "Undefined namespace prefix\n",
625
    "Encoding error\n",
626
    "Char out of XML range\n",
627
    "Invalid or incomplete context\n",
628
    "Stack usage error\n",
629
    "Forbidden variable\n",
630
    "?? Unknown error ??\n" /* Must be last in the list! */
631
};
632
0
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
633
0
       sizeof(xmlXPathErrorMessages[0])) - 1)
634
/**
635
 * xmlXPathErrMemory:
636
 * @ctxt:  an XPath context
637
 * @extra:  extra informations
638
 *
639
 * Handle a redefinition of attribute error
640
 */
641
static void
642
xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
643
0
{
644
0
    if (ctxt != NULL) {
645
0
        if (extra) {
646
0
            xmlChar buf[200];
647
648
0
            xmlStrPrintf(buf, 200,
649
0
                         "Memory allocation failed : %s\n",
650
0
                         extra);
651
0
            ctxt->lastError.message = (char *) xmlStrdup(buf);
652
0
        } else {
653
0
            ctxt->lastError.message = (char *)
654
0
         xmlStrdup(BAD_CAST "Memory allocation failed\n");
655
0
        }
656
0
        ctxt->lastError.domain = XML_FROM_XPATH;
657
0
        ctxt->lastError.code = XML_ERR_NO_MEMORY;
658
0
  if (ctxt->error != NULL)
659
0
      ctxt->error(ctxt->userData, &ctxt->lastError);
660
0
    } else {
661
0
        if (extra)
662
0
            __xmlRaiseError(NULL, NULL, NULL,
663
0
                            NULL, NULL, XML_FROM_XPATH,
664
0
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
665
0
                            extra, NULL, NULL, 0, 0,
666
0
                            "Memory allocation failed : %s\n", extra);
667
0
        else
668
0
            __xmlRaiseError(NULL, NULL, NULL,
669
0
                            NULL, NULL, XML_FROM_XPATH,
670
0
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
671
0
                            NULL, NULL, NULL, 0, 0,
672
0
                            "Memory allocation failed\n");
673
0
    }
674
0
}
675
676
/**
677
 * xmlXPathPErrMemory:
678
 * @ctxt:  an XPath parser context
679
 * @extra:  extra informations
680
 *
681
 * Handle a redefinition of attribute error
682
 */
683
static void
684
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
685
0
{
686
0
    if (ctxt == NULL)
687
0
  xmlXPathErrMemory(NULL, extra);
688
0
    else {
689
0
  ctxt->error = XPATH_MEMORY_ERROR;
690
0
  xmlXPathErrMemory(ctxt->context, extra);
691
0
    }
692
0
}
693
694
/**
695
 * xmlXPathErr:
696
 * @ctxt:  a XPath parser context
697
 * @error:  the error code
698
 *
699
 * Handle an XPath error
700
 */
701
void
702
xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
703
0
{
704
0
    if ((error < 0) || (error > MAXERRNO))
705
0
  error = MAXERRNO;
706
0
    if (ctxt == NULL) {
707
0
  __xmlRaiseError(NULL, NULL, NULL,
708
0
      NULL, NULL, XML_FROM_XPATH,
709
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
710
0
      XML_ERR_ERROR, NULL, 0,
711
0
      NULL, NULL, NULL, 0, 0,
712
0
      "%s", xmlXPathErrorMessages[error]);
713
0
  return;
714
0
    }
715
0
    ctxt->error = error;
716
0
    if (ctxt->context == NULL) {
717
0
  __xmlRaiseError(NULL, NULL, NULL,
718
0
      NULL, NULL, XML_FROM_XPATH,
719
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
720
0
      XML_ERR_ERROR, NULL, 0,
721
0
      (const char *) ctxt->base, NULL, NULL,
722
0
      ctxt->cur - ctxt->base, 0,
723
0
      "%s", xmlXPathErrorMessages[error]);
724
0
  return;
725
0
    }
726
727
    /* cleanup current last error */
728
0
    xmlResetError(&ctxt->context->lastError);
729
730
0
    ctxt->context->lastError.domain = XML_FROM_XPATH;
731
0
    ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
732
0
                           XPATH_EXPRESSION_OK;
733
0
    ctxt->context->lastError.level = XML_ERR_ERROR;
734
0
    ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
735
0
    ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
736
0
    ctxt->context->lastError.node = ctxt->context->debugNode;
737
0
    if (ctxt->context->error != NULL) {
738
0
  ctxt->context->error(ctxt->context->userData,
739
0
                       &ctxt->context->lastError);
740
0
    } else {
741
0
  __xmlRaiseError(NULL, NULL, NULL,
742
0
      NULL, ctxt->context->debugNode, XML_FROM_XPATH,
743
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
744
0
      XML_ERR_ERROR, NULL, 0,
745
0
      (const char *) ctxt->base, NULL, NULL,
746
0
      ctxt->cur - ctxt->base, 0,
747
0
      "%s", xmlXPathErrorMessages[error]);
748
0
    }
749
750
0
}
751
752
/**
753
 * xmlXPatherror:
754
 * @ctxt:  the XPath Parser context
755
 * @file:  the file name
756
 * @line:  the line number
757
 * @no:  the error number
758
 *
759
 * Formats an error message.
760
 */
761
void
762
xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
763
0
              int line ATTRIBUTE_UNUSED, int no) {
764
0
    xmlXPathErr(ctxt, no);
765
0
}
766
767
/************************************************************************
768
 *                  *
769
 *      Utilities         *
770
 *                  *
771
 ************************************************************************/
772
773
/**
774
 * xsltPointerList:
775
 *
776
 * Pointer-list for various purposes.
777
 */
778
typedef struct _xmlPointerList xmlPointerList;
779
typedef xmlPointerList *xmlPointerListPtr;
780
struct _xmlPointerList {
781
    void **items;
782
    int number;
783
    int size;
784
};
785
/*
786
* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
787
* and here, we should make the functions public.
788
*/
789
static int
790
xmlPointerListAddSize(xmlPointerListPtr list,
791
           void *item,
792
           int initialSize)
793
0
{
794
0
    if (list->items == NULL) {
795
0
  if (initialSize <= 0)
796
0
      initialSize = 1;
797
0
  list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
798
0
  if (list->items == NULL) {
799
0
      xmlXPathErrMemory(NULL,
800
0
    "xmlPointerListCreate: allocating item\n");
801
0
      return(-1);
802
0
  }
803
0
  list->number = 0;
804
0
  list->size = initialSize;
805
0
    } else if (list->size <= list->number) {
806
0
        if (list->size > 50000000) {
807
0
      xmlXPathErrMemory(NULL,
808
0
    "xmlPointerListAddSize: re-allocating item\n");
809
0
            return(-1);
810
0
        }
811
0
  list->size *= 2;
812
0
  list->items = (void **) xmlRealloc(list->items,
813
0
      list->size * sizeof(void *));
814
0
  if (list->items == NULL) {
815
0
      xmlXPathErrMemory(NULL,
816
0
    "xmlPointerListAddSize: re-allocating item\n");
817
0
      list->size = 0;
818
0
      return(-1);
819
0
  }
820
0
    }
821
0
    list->items[list->number++] = item;
822
0
    return(0);
823
0
}
824
825
/**
826
 * xsltPointerListCreate:
827
 *
828
 * Creates an xsltPointerList structure.
829
 *
830
 * Returns a xsltPointerList structure or NULL in case of an error.
831
 */
832
static xmlPointerListPtr
833
xmlPointerListCreate(int initialSize)
834
0
{
835
0
    xmlPointerListPtr ret;
836
837
0
    ret = xmlMalloc(sizeof(xmlPointerList));
838
0
    if (ret == NULL) {
839
0
  xmlXPathErrMemory(NULL,
840
0
      "xmlPointerListCreate: allocating item\n");
841
0
  return (NULL);
842
0
    }
843
0
    memset(ret, 0, sizeof(xmlPointerList));
844
0
    if (initialSize > 0) {
845
0
  xmlPointerListAddSize(ret, NULL, initialSize);
846
0
  ret->number = 0;
847
0
    }
848
0
    return (ret);
849
0
}
850
851
/**
852
 * xsltPointerListFree:
853
 *
854
 * Frees the xsltPointerList structure. This does not free
855
 * the content of the list.
856
 */
857
static void
858
xmlPointerListFree(xmlPointerListPtr list)
859
0
{
860
0
    if (list == NULL)
861
0
  return;
862
0
    if (list->items != NULL)
863
0
  xmlFree(list->items);
864
0
    xmlFree(list);
865
0
}
866
867
/************************************************************************
868
 *                  *
869
 *      Parser Types          *
870
 *                  *
871
 ************************************************************************/
872
873
/*
874
 * Types are private:
875
 */
876
877
typedef enum {
878
    XPATH_OP_END=0,
879
    XPATH_OP_AND,
880
    XPATH_OP_OR,
881
    XPATH_OP_EQUAL,
882
    XPATH_OP_CMP,
883
    XPATH_OP_PLUS,
884
    XPATH_OP_MULT,
885
    XPATH_OP_UNION,
886
    XPATH_OP_ROOT,
887
    XPATH_OP_NODE,
888
    XPATH_OP_RESET, /* 10 */
889
    XPATH_OP_COLLECT,
890
    XPATH_OP_VALUE, /* 12 */
891
    XPATH_OP_VARIABLE,
892
    XPATH_OP_FUNCTION,
893
    XPATH_OP_ARG,
894
    XPATH_OP_PREDICATE,
895
    XPATH_OP_FILTER, /* 17 */
896
    XPATH_OP_SORT /* 18 */
897
#ifdef LIBXML_XPTR_ENABLED
898
    ,XPATH_OP_RANGETO
899
#endif
900
} xmlXPathOp;
901
902
typedef enum {
903
    AXIS_ANCESTOR = 1,
904
    AXIS_ANCESTOR_OR_SELF,
905
    AXIS_ATTRIBUTE,
906
    AXIS_CHILD,
907
    AXIS_DESCENDANT,
908
    AXIS_DESCENDANT_OR_SELF,
909
    AXIS_FOLLOWING,
910
    AXIS_FOLLOWING_SIBLING,
911
    AXIS_NAMESPACE,
912
    AXIS_PARENT,
913
    AXIS_PRECEDING,
914
    AXIS_PRECEDING_SIBLING,
915
    AXIS_SELF
916
} xmlXPathAxisVal;
917
918
typedef enum {
919
    NODE_TEST_NONE = 0,
920
    NODE_TEST_TYPE = 1,
921
    NODE_TEST_PI = 2,
922
    NODE_TEST_ALL = 3,
923
    NODE_TEST_NS = 4,
924
    NODE_TEST_NAME = 5
925
} xmlXPathTestVal;
926
927
typedef enum {
928
    NODE_TYPE_NODE = 0,
929
    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
930
    NODE_TYPE_TEXT = XML_TEXT_NODE,
931
    NODE_TYPE_PI = XML_PI_NODE
932
} xmlXPathTypeVal;
933
934
typedef struct _xmlXPathStepOp xmlXPathStepOp;
935
typedef xmlXPathStepOp *xmlXPathStepOpPtr;
936
struct _xmlXPathStepOp {
937
    xmlXPathOp op;    /* The identifier of the operation */
938
    int ch1;      /* First child */
939
    int ch2;      /* Second child */
940
    int value;
941
    int value2;
942
    int value3;
943
    void *value4;
944
    void *value5;
945
    xmlXPathFunction cache;
946
    void *cacheURI;
947
};
948
949
struct _xmlXPathCompExpr {
950
    int nbStep;     /* Number of steps in this expression */
951
    int maxStep;    /* Maximum number of steps allocated */
952
    xmlXPathStepOp *steps;  /* ops for computation of this expression */
953
    int last;     /* index of last step in expression */
954
    xmlChar *expr;    /* the expression being computed */
955
    xmlDictPtr dict;    /* the dictionary to use if any */
956
#ifdef DEBUG_EVAL_COUNTS
957
    int nb;
958
    xmlChar *string;
959
#endif
960
#ifdef XPATH_STREAMING
961
    xmlPatternPtr stream;
962
#endif
963
};
964
965
/************************************************************************
966
 *                  *
967
 *      Forward declarations        *
968
 *                  *
969
 ************************************************************************/
970
static void
971
xmlXPathFreeValueTree(xmlNodeSetPtr obj);
972
static void
973
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
974
static int
975
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
976
                        xmlXPathStepOpPtr op, xmlNodePtr *first);
977
static int
978
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
979
          xmlXPathStepOpPtr op,
980
          int isPredicate);
981
982
/************************************************************************
983
 *                  *
984
 *      Parser Type functions       *
985
 *                  *
986
 ************************************************************************/
987
988
/**
989
 * xmlXPathNewCompExpr:
990
 *
991
 * Create a new Xpath component
992
 *
993
 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
994
 */
995
static xmlXPathCompExprPtr
996
0
xmlXPathNewCompExpr(void) {
997
0
    xmlXPathCompExprPtr cur;
998
999
0
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1000
0
    if (cur == NULL) {
1001
0
        xmlXPathErrMemory(NULL, "allocating component\n");
1002
0
  return(NULL);
1003
0
    }
1004
0
    memset(cur, 0, sizeof(xmlXPathCompExpr));
1005
0
    cur->maxStep = 10;
1006
0
    cur->nbStep = 0;
1007
0
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1008
0
                                     sizeof(xmlXPathStepOp));
1009
0
    if (cur->steps == NULL) {
1010
0
        xmlXPathErrMemory(NULL, "allocating steps\n");
1011
0
  xmlFree(cur);
1012
0
  return(NULL);
1013
0
    }
1014
0
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1015
0
    cur->last = -1;
1016
#ifdef DEBUG_EVAL_COUNTS
1017
    cur->nb = 0;
1018
#endif
1019
0
    return(cur);
1020
0
}
1021
1022
/**
1023
 * xmlXPathFreeCompExpr:
1024
 * @comp:  an XPATH comp
1025
 *
1026
 * Free up the memory allocated by @comp
1027
 */
1028
void
1029
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1030
0
{
1031
0
    xmlXPathStepOpPtr op;
1032
0
    int i;
1033
1034
0
    if (comp == NULL)
1035
0
        return;
1036
0
    if (comp->dict == NULL) {
1037
0
  for (i = 0; i < comp->nbStep; i++) {
1038
0
      op = &comp->steps[i];
1039
0
      if (op->value4 != NULL) {
1040
0
    if (op->op == XPATH_OP_VALUE)
1041
0
        xmlXPathFreeObject(op->value4);
1042
0
    else
1043
0
        xmlFree(op->value4);
1044
0
      }
1045
0
      if (op->value5 != NULL)
1046
0
    xmlFree(op->value5);
1047
0
  }
1048
0
    } else {
1049
0
  for (i = 0; i < comp->nbStep; i++) {
1050
0
      op = &comp->steps[i];
1051
0
      if (op->value4 != NULL) {
1052
0
    if (op->op == XPATH_OP_VALUE)
1053
0
        xmlXPathFreeObject(op->value4);
1054
0
      }
1055
0
  }
1056
0
        xmlDictFree(comp->dict);
1057
0
    }
1058
0
    if (comp->steps != NULL) {
1059
0
        xmlFree(comp->steps);
1060
0
    }
1061
#ifdef DEBUG_EVAL_COUNTS
1062
    if (comp->string != NULL) {
1063
        xmlFree(comp->string);
1064
    }
1065
#endif
1066
0
#ifdef XPATH_STREAMING
1067
0
    if (comp->stream != NULL) {
1068
0
        xmlFreePatternList(comp->stream);
1069
0
    }
1070
0
#endif
1071
0
    if (comp->expr != NULL) {
1072
0
        xmlFree(comp->expr);
1073
0
    }
1074
1075
0
    xmlFree(comp);
1076
0
}
1077
1078
/**
1079
 * xmlXPathCompExprAdd:
1080
 * @comp:  the compiled expression
1081
 * @ch1: first child index
1082
 * @ch2: second child index
1083
 * @op:  an op
1084
 * @value:  the first int value
1085
 * @value2:  the second int value
1086
 * @value3:  the third int value
1087
 * @value4:  the first string value
1088
 * @value5:  the second string value
1089
 *
1090
 * Add a step to an XPath Compiled Expression
1091
 *
1092
 * Returns -1 in case of failure, the index otherwise
1093
 */
1094
static int
1095
xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
1096
   xmlXPathOp op, int value,
1097
0
   int value2, int value3, void *value4, void *value5) {
1098
0
    if (comp->nbStep >= comp->maxStep) {
1099
0
  xmlXPathStepOp *real;
1100
1101
0
        if (comp->maxStep >= XPATH_MAX_STEPS) {
1102
0
      xmlXPathErrMemory(NULL, "adding step\n");
1103
0
      return(-1);
1104
0
        }
1105
0
  comp->maxStep *= 2;
1106
0
  real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1107
0
                          comp->maxStep * sizeof(xmlXPathStepOp));
1108
0
  if (real == NULL) {
1109
0
      comp->maxStep /= 2;
1110
0
      xmlXPathErrMemory(NULL, "adding step\n");
1111
0
      return(-1);
1112
0
  }
1113
0
  comp->steps = real;
1114
0
    }
1115
0
    comp->last = comp->nbStep;
1116
0
    comp->steps[comp->nbStep].ch1 = ch1;
1117
0
    comp->steps[comp->nbStep].ch2 = ch2;
1118
0
    comp->steps[comp->nbStep].op = op;
1119
0
    comp->steps[comp->nbStep].value = value;
1120
0
    comp->steps[comp->nbStep].value2 = value2;
1121
0
    comp->steps[comp->nbStep].value3 = value3;
1122
0
    if ((comp->dict != NULL) &&
1123
0
        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1124
0
   (op == XPATH_OP_COLLECT))) {
1125
0
        if (value4 != NULL) {
1126
0
      comp->steps[comp->nbStep].value4 = (xmlChar *)
1127
0
          (void *)xmlDictLookup(comp->dict, value4, -1);
1128
0
      xmlFree(value4);
1129
0
  } else
1130
0
      comp->steps[comp->nbStep].value4 = NULL;
1131
0
        if (value5 != NULL) {
1132
0
      comp->steps[comp->nbStep].value5 = (xmlChar *)
1133
0
          (void *)xmlDictLookup(comp->dict, value5, -1);
1134
0
      xmlFree(value5);
1135
0
  } else
1136
0
      comp->steps[comp->nbStep].value5 = NULL;
1137
0
    } else {
1138
0
  comp->steps[comp->nbStep].value4 = value4;
1139
0
  comp->steps[comp->nbStep].value5 = value5;
1140
0
    }
1141
0
    comp->steps[comp->nbStep].cache = NULL;
1142
0
    return(comp->nbStep++);
1143
0
}
1144
1145
/**
1146
 * xmlXPathCompSwap:
1147
 * @comp:  the compiled expression
1148
 * @op: operation index
1149
 *
1150
 * Swaps 2 operations in the compiled expression
1151
 */
1152
static void
1153
0
xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1154
0
    int tmp;
1155
1156
#ifndef LIBXML_THREAD_ENABLED
1157
    /*
1158
     * Since this manipulates possibly shared variables, this is
1159
     * disabled if one detects that the library is used in a multithreaded
1160
     * application
1161
     */
1162
    if (xmlXPathDisableOptimizer)
1163
  return;
1164
#endif
1165
1166
0
    tmp = op->ch1;
1167
0
    op->ch1 = op->ch2;
1168
0
    op->ch2 = tmp;
1169
0
}
1170
1171
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1172
0
    xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),     \
1173
0
                  (op), (val), (val2), (val3), (val4), (val5))
1174
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1175
0
    xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,   \
1176
0
                  (op), (val), (val2), (val3), (val4), (val5))
1177
1178
0
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1179
0
xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1180
1181
0
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1182
0
xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1183
1184
0
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1185
0
xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),     \
1186
0
      (val), (val2), 0 ,NULL ,NULL)
1187
1188
/************************************************************************
1189
 *                  *
1190
 *    XPath object cache structures       *
1191
 *                  *
1192
 ************************************************************************/
1193
1194
/* #define XP_DEFAULT_CACHE_ON */
1195
1196
0
#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1197
1198
typedef struct _xmlXPathContextCache xmlXPathContextCache;
1199
typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1200
struct _xmlXPathContextCache {
1201
    xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
1202
    xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
1203
    xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
1204
    xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
1205
    xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
1206
    int maxNodeset;
1207
    int maxString;
1208
    int maxBoolean;
1209
    int maxNumber;
1210
    int maxMisc;
1211
#ifdef XP_DEBUG_OBJ_USAGE
1212
    int dbgCachedAll;
1213
    int dbgCachedNodeset;
1214
    int dbgCachedString;
1215
    int dbgCachedBool;
1216
    int dbgCachedNumber;
1217
    int dbgCachedPoint;
1218
    int dbgCachedRange;
1219
    int dbgCachedLocset;
1220
    int dbgCachedUsers;
1221
    int dbgCachedXSLTTree;
1222
    int dbgCachedUndefined;
1223
1224
1225
    int dbgReusedAll;
1226
    int dbgReusedNodeset;
1227
    int dbgReusedString;
1228
    int dbgReusedBool;
1229
    int dbgReusedNumber;
1230
    int dbgReusedPoint;
1231
    int dbgReusedRange;
1232
    int dbgReusedLocset;
1233
    int dbgReusedUsers;
1234
    int dbgReusedXSLTTree;
1235
    int dbgReusedUndefined;
1236
1237
#endif
1238
};
1239
1240
/************************************************************************
1241
 *                  *
1242
 *    Debugging related functions       *
1243
 *                  *
1244
 ************************************************************************/
1245
1246
#define STRANGE             \
1247
0
    xmlGenericError(xmlGenericErrorContext,       \
1248
0
      "Internal error at %s:%d\n",        \
1249
0
            __FILE__, __LINE__);
1250
1251
#ifdef LIBXML_DEBUG_ENABLED
1252
static void
1253
0
xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1254
0
    int i;
1255
0
    char shift[100];
1256
1257
0
    for (i = 0;((i < depth) && (i < 25));i++)
1258
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1259
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1260
0
    if (cur == NULL) {
1261
0
  fprintf(output, "%s", shift);
1262
0
  fprintf(output, "Node is NULL !\n");
1263
0
  return;
1264
1265
0
    }
1266
1267
0
    if ((cur->type == XML_DOCUMENT_NODE) ||
1268
0
       (cur->type == XML_HTML_DOCUMENT_NODE)) {
1269
0
  fprintf(output, "%s", shift);
1270
0
  fprintf(output, " /\n");
1271
0
    } else if (cur->type == XML_ATTRIBUTE_NODE)
1272
0
  xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1273
0
    else
1274
0
  xmlDebugDumpOneNode(output, cur, depth);
1275
0
}
1276
static void
1277
0
xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1278
0
    xmlNodePtr tmp;
1279
0
    int i;
1280
0
    char shift[100];
1281
1282
0
    for (i = 0;((i < depth) && (i < 25));i++)
1283
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1284
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1285
0
    if (cur == NULL) {
1286
0
  fprintf(output, "%s", shift);
1287
0
  fprintf(output, "Node is NULL !\n");
1288
0
  return;
1289
1290
0
    }
1291
1292
0
    while (cur != NULL) {
1293
0
  tmp = cur;
1294
0
  cur = cur->next;
1295
0
  xmlDebugDumpOneNode(output, tmp, depth);
1296
0
    }
1297
0
}
1298
1299
static void
1300
0
xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1301
0
    int i;
1302
0
    char shift[100];
1303
1304
0
    for (i = 0;((i < depth) && (i < 25));i++)
1305
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1306
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1307
1308
0
    if (cur == NULL) {
1309
0
  fprintf(output, "%s", shift);
1310
0
  fprintf(output, "NodeSet is NULL !\n");
1311
0
  return;
1312
1313
0
    }
1314
1315
0
    if (cur != NULL) {
1316
0
  fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1317
0
  for (i = 0;i < cur->nodeNr;i++) {
1318
0
      fprintf(output, "%s", shift);
1319
0
      fprintf(output, "%d", i + 1);
1320
0
      xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1321
0
  }
1322
0
    }
1323
0
}
1324
1325
static void
1326
0
xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1327
0
    int i;
1328
0
    char shift[100];
1329
1330
0
    for (i = 0;((i < depth) && (i < 25));i++)
1331
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1332
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1333
1334
0
    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1335
0
  fprintf(output, "%s", shift);
1336
0
  fprintf(output, "Value Tree is NULL !\n");
1337
0
  return;
1338
1339
0
    }
1340
1341
0
    fprintf(output, "%s", shift);
1342
0
    fprintf(output, "%d", i + 1);
1343
0
    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1344
0
}
1345
#if defined(LIBXML_XPTR_ENABLED)
1346
static void
1347
0
xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1348
0
    int i;
1349
0
    char shift[100];
1350
1351
0
    for (i = 0;((i < depth) && (i < 25));i++)
1352
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1353
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1354
1355
0
    if (cur == NULL) {
1356
0
  fprintf(output, "%s", shift);
1357
0
  fprintf(output, "LocationSet is NULL !\n");
1358
0
  return;
1359
1360
0
    }
1361
1362
0
    for (i = 0;i < cur->locNr;i++) {
1363
0
  fprintf(output, "%s", shift);
1364
0
        fprintf(output, "%d : ", i + 1);
1365
0
  xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1366
0
    }
1367
0
}
1368
#endif /* LIBXML_XPTR_ENABLED */
1369
1370
/**
1371
 * xmlXPathDebugDumpObject:
1372
 * @output:  the FILE * to dump the output
1373
 * @cur:  the object to inspect
1374
 * @depth:  indentation level
1375
 *
1376
 * Dump the content of the object for debugging purposes
1377
 */
1378
void
1379
0
xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1380
0
    int i;
1381
0
    char shift[100];
1382
1383
0
    if (output == NULL) return;
1384
1385
0
    for (i = 0;((i < depth) && (i < 25));i++)
1386
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1387
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1388
1389
1390
0
    fprintf(output, "%s", shift);
1391
1392
0
    if (cur == NULL) {
1393
0
        fprintf(output, "Object is empty (NULL)\n");
1394
0
  return;
1395
0
    }
1396
0
    switch(cur->type) {
1397
0
        case XPATH_UNDEFINED:
1398
0
      fprintf(output, "Object is uninitialized\n");
1399
0
      break;
1400
0
        case XPATH_NODESET:
1401
0
      fprintf(output, "Object is a Node Set :\n");
1402
0
      xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1403
0
      break;
1404
0
  case XPATH_XSLT_TREE:
1405
0
      fprintf(output, "Object is an XSLT value tree :\n");
1406
0
      xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1407
0
      break;
1408
0
        case XPATH_BOOLEAN:
1409
0
      fprintf(output, "Object is a Boolean : ");
1410
0
      if (cur->boolval) fprintf(output, "true\n");
1411
0
      else fprintf(output, "false\n");
1412
0
      break;
1413
0
        case XPATH_NUMBER:
1414
0
      switch (xmlXPathIsInf(cur->floatval)) {
1415
0
      case 1:
1416
0
    fprintf(output, "Object is a number : Infinity\n");
1417
0
    break;
1418
0
      case -1:
1419
0
    fprintf(output, "Object is a number : -Infinity\n");
1420
0
    break;
1421
0
      default:
1422
0
    if (xmlXPathIsNaN(cur->floatval)) {
1423
0
        fprintf(output, "Object is a number : NaN\n");
1424
0
    } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1425
0
        fprintf(output, "Object is a number : 0\n");
1426
0
    } else {
1427
0
        fprintf(output, "Object is a number : %0g\n", cur->floatval);
1428
0
    }
1429
0
      }
1430
0
      break;
1431
0
        case XPATH_STRING:
1432
0
      fprintf(output, "Object is a string : ");
1433
0
      xmlDebugDumpString(output, cur->stringval);
1434
0
      fprintf(output, "\n");
1435
0
      break;
1436
0
  case XPATH_POINT:
1437
0
      fprintf(output, "Object is a point : index %d in node", cur->index);
1438
0
      xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1439
0
      fprintf(output, "\n");
1440
0
      break;
1441
0
  case XPATH_RANGE:
1442
0
      if ((cur->user2 == NULL) ||
1443
0
    ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1444
0
    fprintf(output, "Object is a collapsed range :\n");
1445
0
    fprintf(output, "%s", shift);
1446
0
    if (cur->index >= 0)
1447
0
        fprintf(output, "index %d in ", cur->index);
1448
0
    fprintf(output, "node\n");
1449
0
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1450
0
                    depth + 1);
1451
0
      } else  {
1452
0
    fprintf(output, "Object is a range :\n");
1453
0
    fprintf(output, "%s", shift);
1454
0
    fprintf(output, "From ");
1455
0
    if (cur->index >= 0)
1456
0
        fprintf(output, "index %d in ", cur->index);
1457
0
    fprintf(output, "node\n");
1458
0
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1459
0
                    depth + 1);
1460
0
    fprintf(output, "%s", shift);
1461
0
    fprintf(output, "To ");
1462
0
    if (cur->index2 >= 0)
1463
0
        fprintf(output, "index %d in ", cur->index2);
1464
0
    fprintf(output, "node\n");
1465
0
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1466
0
                    depth + 1);
1467
0
    fprintf(output, "\n");
1468
0
      }
1469
0
      break;
1470
0
  case XPATH_LOCATIONSET:
1471
0
#if defined(LIBXML_XPTR_ENABLED)
1472
0
      fprintf(output, "Object is a Location Set:\n");
1473
0
      xmlXPathDebugDumpLocationSet(output,
1474
0
        (xmlLocationSetPtr) cur->user, depth);
1475
0
#endif
1476
0
      break;
1477
0
  case XPATH_USERS:
1478
0
      fprintf(output, "Object is user defined\n");
1479
0
      break;
1480
0
    }
1481
0
}
1482
1483
static void
1484
xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1485
0
                       xmlXPathStepOpPtr op, int depth) {
1486
0
    int i;
1487
0
    char shift[100];
1488
1489
0
    for (i = 0;((i < depth) && (i < 25));i++)
1490
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1491
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1492
1493
0
    fprintf(output, "%s", shift);
1494
0
    if (op == NULL) {
1495
0
  fprintf(output, "Step is NULL\n");
1496
0
  return;
1497
0
    }
1498
0
    switch (op->op) {
1499
0
        case XPATH_OP_END:
1500
0
      fprintf(output, "END"); break;
1501
0
        case XPATH_OP_AND:
1502
0
      fprintf(output, "AND"); break;
1503
0
        case XPATH_OP_OR:
1504
0
      fprintf(output, "OR"); break;
1505
0
        case XPATH_OP_EQUAL:
1506
0
       if (op->value)
1507
0
     fprintf(output, "EQUAL =");
1508
0
       else
1509
0
     fprintf(output, "EQUAL !=");
1510
0
       break;
1511
0
        case XPATH_OP_CMP:
1512
0
       if (op->value)
1513
0
     fprintf(output, "CMP <");
1514
0
       else
1515
0
     fprintf(output, "CMP >");
1516
0
       if (!op->value2)
1517
0
     fprintf(output, "=");
1518
0
       break;
1519
0
        case XPATH_OP_PLUS:
1520
0
       if (op->value == 0)
1521
0
     fprintf(output, "PLUS -");
1522
0
       else if (op->value == 1)
1523
0
     fprintf(output, "PLUS +");
1524
0
       else if (op->value == 2)
1525
0
     fprintf(output, "PLUS unary -");
1526
0
       else if (op->value == 3)
1527
0
     fprintf(output, "PLUS unary - -");
1528
0
       break;
1529
0
        case XPATH_OP_MULT:
1530
0
       if (op->value == 0)
1531
0
     fprintf(output, "MULT *");
1532
0
       else if (op->value == 1)
1533
0
     fprintf(output, "MULT div");
1534
0
       else
1535
0
     fprintf(output, "MULT mod");
1536
0
       break;
1537
0
        case XPATH_OP_UNION:
1538
0
       fprintf(output, "UNION"); break;
1539
0
        case XPATH_OP_ROOT:
1540
0
       fprintf(output, "ROOT"); break;
1541
0
        case XPATH_OP_NODE:
1542
0
       fprintf(output, "NODE"); break;
1543
0
        case XPATH_OP_RESET:
1544
0
       fprintf(output, "RESET"); break;
1545
0
        case XPATH_OP_SORT:
1546
0
       fprintf(output, "SORT"); break;
1547
0
        case XPATH_OP_COLLECT: {
1548
0
      xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1549
0
      xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1550
0
      xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1551
0
      const xmlChar *prefix = op->value4;
1552
0
      const xmlChar *name = op->value5;
1553
1554
0
      fprintf(output, "COLLECT ");
1555
0
      switch (axis) {
1556
0
    case AXIS_ANCESTOR:
1557
0
        fprintf(output, " 'ancestors' "); break;
1558
0
    case AXIS_ANCESTOR_OR_SELF:
1559
0
        fprintf(output, " 'ancestors-or-self' "); break;
1560
0
    case AXIS_ATTRIBUTE:
1561
0
        fprintf(output, " 'attributes' "); break;
1562
0
    case AXIS_CHILD:
1563
0
        fprintf(output, " 'child' "); break;
1564
0
    case AXIS_DESCENDANT:
1565
0
        fprintf(output, " 'descendant' "); break;
1566
0
    case AXIS_DESCENDANT_OR_SELF:
1567
0
        fprintf(output, " 'descendant-or-self' "); break;
1568
0
    case AXIS_FOLLOWING:
1569
0
        fprintf(output, " 'following' "); break;
1570
0
    case AXIS_FOLLOWING_SIBLING:
1571
0
        fprintf(output, " 'following-siblings' "); break;
1572
0
    case AXIS_NAMESPACE:
1573
0
        fprintf(output, " 'namespace' "); break;
1574
0
    case AXIS_PARENT:
1575
0
        fprintf(output, " 'parent' "); break;
1576
0
    case AXIS_PRECEDING:
1577
0
        fprintf(output, " 'preceding' "); break;
1578
0
    case AXIS_PRECEDING_SIBLING:
1579
0
        fprintf(output, " 'preceding-sibling' "); break;
1580
0
    case AXIS_SELF:
1581
0
        fprintf(output, " 'self' "); break;
1582
0
      }
1583
0
      switch (test) {
1584
0
                case NODE_TEST_NONE:
1585
0
        fprintf(output, "'none' "); break;
1586
0
                case NODE_TEST_TYPE:
1587
0
        fprintf(output, "'type' "); break;
1588
0
                case NODE_TEST_PI:
1589
0
        fprintf(output, "'PI' "); break;
1590
0
                case NODE_TEST_ALL:
1591
0
        fprintf(output, "'all' "); break;
1592
0
                case NODE_TEST_NS:
1593
0
        fprintf(output, "'namespace' "); break;
1594
0
                case NODE_TEST_NAME:
1595
0
        fprintf(output, "'name' "); break;
1596
0
      }
1597
0
      switch (type) {
1598
0
                case NODE_TYPE_NODE:
1599
0
        fprintf(output, "'node' "); break;
1600
0
                case NODE_TYPE_COMMENT:
1601
0
        fprintf(output, "'comment' "); break;
1602
0
                case NODE_TYPE_TEXT:
1603
0
        fprintf(output, "'text' "); break;
1604
0
                case NODE_TYPE_PI:
1605
0
        fprintf(output, "'PI' "); break;
1606
0
      }
1607
0
      if (prefix != NULL)
1608
0
    fprintf(output, "%s:", prefix);
1609
0
      if (name != NULL)
1610
0
    fprintf(output, "%s", (const char *) name);
1611
0
      break;
1612
1613
0
        }
1614
0
  case XPATH_OP_VALUE: {
1615
0
      xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1616
1617
0
      fprintf(output, "ELEM ");
1618
0
      xmlXPathDebugDumpObject(output, object, 0);
1619
0
      goto finish;
1620
0
  }
1621
0
  case XPATH_OP_VARIABLE: {
1622
0
      const xmlChar *prefix = op->value5;
1623
0
      const xmlChar *name = op->value4;
1624
1625
0
      if (prefix != NULL)
1626
0
    fprintf(output, "VARIABLE %s:%s", prefix, name);
1627
0
      else
1628
0
    fprintf(output, "VARIABLE %s", name);
1629
0
      break;
1630
0
  }
1631
0
  case XPATH_OP_FUNCTION: {
1632
0
      int nbargs = op->value;
1633
0
      const xmlChar *prefix = op->value5;
1634
0
      const xmlChar *name = op->value4;
1635
1636
0
      if (prefix != NULL)
1637
0
    fprintf(output, "FUNCTION %s:%s(%d args)",
1638
0
      prefix, name, nbargs);
1639
0
      else
1640
0
    fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1641
0
      break;
1642
0
  }
1643
0
        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1644
0
        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1645
0
        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1646
0
#ifdef LIBXML_XPTR_ENABLED
1647
0
        case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1648
0
#endif
1649
0
  default:
1650
0
        fprintf(output, "UNKNOWN %d\n", op->op); return;
1651
0
    }
1652
0
    fprintf(output, "\n");
1653
0
finish:
1654
0
    if (op->ch1 >= 0)
1655
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1656
0
    if (op->ch2 >= 0)
1657
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1658
0
}
1659
1660
/**
1661
 * xmlXPathDebugDumpCompExpr:
1662
 * @output:  the FILE * for the output
1663
 * @comp:  the precompiled XPath expression
1664
 * @depth:  the indentation level.
1665
 *
1666
 * Dumps the tree of the compiled XPath expression.
1667
 */
1668
void
1669
xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1670
0
                    int depth) {
1671
0
    int i;
1672
0
    char shift[100];
1673
1674
0
    if ((output == NULL) || (comp == NULL)) return;
1675
1676
0
    for (i = 0;((i < depth) && (i < 25));i++)
1677
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1678
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1679
1680
0
    fprintf(output, "%s", shift);
1681
1682
0
#ifdef XPATH_STREAMING
1683
0
    if (comp->stream) {
1684
0
        fprintf(output, "Streaming Expression\n");
1685
0
    } else
1686
0
#endif
1687
0
    {
1688
0
        fprintf(output, "Compiled Expression : %d elements\n",
1689
0
                comp->nbStep);
1690
0
        i = comp->last;
1691
0
        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1692
0
    }
1693
0
}
1694
1695
#ifdef XP_DEBUG_OBJ_USAGE
1696
1697
/*
1698
* XPath object usage related debugging variables.
1699
*/
1700
static int xmlXPathDebugObjCounterUndefined = 0;
1701
static int xmlXPathDebugObjCounterNodeset = 0;
1702
static int xmlXPathDebugObjCounterBool = 0;
1703
static int xmlXPathDebugObjCounterNumber = 0;
1704
static int xmlXPathDebugObjCounterString = 0;
1705
static int xmlXPathDebugObjCounterPoint = 0;
1706
static int xmlXPathDebugObjCounterRange = 0;
1707
static int xmlXPathDebugObjCounterLocset = 0;
1708
static int xmlXPathDebugObjCounterUsers = 0;
1709
static int xmlXPathDebugObjCounterXSLTTree = 0;
1710
static int xmlXPathDebugObjCounterAll = 0;
1711
1712
static int xmlXPathDebugObjTotalUndefined = 0;
1713
static int xmlXPathDebugObjTotalNodeset = 0;
1714
static int xmlXPathDebugObjTotalBool = 0;
1715
static int xmlXPathDebugObjTotalNumber = 0;
1716
static int xmlXPathDebugObjTotalString = 0;
1717
static int xmlXPathDebugObjTotalPoint = 0;
1718
static int xmlXPathDebugObjTotalRange = 0;
1719
static int xmlXPathDebugObjTotalLocset = 0;
1720
static int xmlXPathDebugObjTotalUsers = 0;
1721
static int xmlXPathDebugObjTotalXSLTTree = 0;
1722
static int xmlXPathDebugObjTotalAll = 0;
1723
1724
static int xmlXPathDebugObjMaxUndefined = 0;
1725
static int xmlXPathDebugObjMaxNodeset = 0;
1726
static int xmlXPathDebugObjMaxBool = 0;
1727
static int xmlXPathDebugObjMaxNumber = 0;
1728
static int xmlXPathDebugObjMaxString = 0;
1729
static int xmlXPathDebugObjMaxPoint = 0;
1730
static int xmlXPathDebugObjMaxRange = 0;
1731
static int xmlXPathDebugObjMaxLocset = 0;
1732
static int xmlXPathDebugObjMaxUsers = 0;
1733
static int xmlXPathDebugObjMaxXSLTTree = 0;
1734
static int xmlXPathDebugObjMaxAll = 0;
1735
1736
/* REVISIT TODO: Make this static when committing */
1737
static void
1738
xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1739
{
1740
    if (ctxt != NULL) {
1741
  if (ctxt->cache != NULL) {
1742
      xmlXPathContextCachePtr cache =
1743
    (xmlXPathContextCachePtr) ctxt->cache;
1744
1745
      cache->dbgCachedAll = 0;
1746
      cache->dbgCachedNodeset = 0;
1747
      cache->dbgCachedString = 0;
1748
      cache->dbgCachedBool = 0;
1749
      cache->dbgCachedNumber = 0;
1750
      cache->dbgCachedPoint = 0;
1751
      cache->dbgCachedRange = 0;
1752
      cache->dbgCachedLocset = 0;
1753
      cache->dbgCachedUsers = 0;
1754
      cache->dbgCachedXSLTTree = 0;
1755
      cache->dbgCachedUndefined = 0;
1756
1757
      cache->dbgReusedAll = 0;
1758
      cache->dbgReusedNodeset = 0;
1759
      cache->dbgReusedString = 0;
1760
      cache->dbgReusedBool = 0;
1761
      cache->dbgReusedNumber = 0;
1762
      cache->dbgReusedPoint = 0;
1763
      cache->dbgReusedRange = 0;
1764
      cache->dbgReusedLocset = 0;
1765
      cache->dbgReusedUsers = 0;
1766
      cache->dbgReusedXSLTTree = 0;
1767
      cache->dbgReusedUndefined = 0;
1768
  }
1769
    }
1770
1771
    xmlXPathDebugObjCounterUndefined = 0;
1772
    xmlXPathDebugObjCounterNodeset = 0;
1773
    xmlXPathDebugObjCounterBool = 0;
1774
    xmlXPathDebugObjCounterNumber = 0;
1775
    xmlXPathDebugObjCounterString = 0;
1776
    xmlXPathDebugObjCounterPoint = 0;
1777
    xmlXPathDebugObjCounterRange = 0;
1778
    xmlXPathDebugObjCounterLocset = 0;
1779
    xmlXPathDebugObjCounterUsers = 0;
1780
    xmlXPathDebugObjCounterXSLTTree = 0;
1781
    xmlXPathDebugObjCounterAll = 0;
1782
1783
    xmlXPathDebugObjTotalUndefined = 0;
1784
    xmlXPathDebugObjTotalNodeset = 0;
1785
    xmlXPathDebugObjTotalBool = 0;
1786
    xmlXPathDebugObjTotalNumber = 0;
1787
    xmlXPathDebugObjTotalString = 0;
1788
    xmlXPathDebugObjTotalPoint = 0;
1789
    xmlXPathDebugObjTotalRange = 0;
1790
    xmlXPathDebugObjTotalLocset = 0;
1791
    xmlXPathDebugObjTotalUsers = 0;
1792
    xmlXPathDebugObjTotalXSLTTree = 0;
1793
    xmlXPathDebugObjTotalAll = 0;
1794
1795
    xmlXPathDebugObjMaxUndefined = 0;
1796
    xmlXPathDebugObjMaxNodeset = 0;
1797
    xmlXPathDebugObjMaxBool = 0;
1798
    xmlXPathDebugObjMaxNumber = 0;
1799
    xmlXPathDebugObjMaxString = 0;
1800
    xmlXPathDebugObjMaxPoint = 0;
1801
    xmlXPathDebugObjMaxRange = 0;
1802
    xmlXPathDebugObjMaxLocset = 0;
1803
    xmlXPathDebugObjMaxUsers = 0;
1804
    xmlXPathDebugObjMaxXSLTTree = 0;
1805
    xmlXPathDebugObjMaxAll = 0;
1806
1807
}
1808
1809
static void
1810
xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1811
            xmlXPathObjectType objType)
1812
{
1813
    int isCached = 0;
1814
1815
    if (ctxt != NULL) {
1816
  if (ctxt->cache != NULL) {
1817
      xmlXPathContextCachePtr cache =
1818
    (xmlXPathContextCachePtr) ctxt->cache;
1819
1820
      isCached = 1;
1821
1822
      cache->dbgReusedAll++;
1823
      switch (objType) {
1824
    case XPATH_UNDEFINED:
1825
        cache->dbgReusedUndefined++;
1826
        break;
1827
    case XPATH_NODESET:
1828
        cache->dbgReusedNodeset++;
1829
        break;
1830
    case XPATH_BOOLEAN:
1831
        cache->dbgReusedBool++;
1832
        break;
1833
    case XPATH_NUMBER:
1834
        cache->dbgReusedNumber++;
1835
        break;
1836
    case XPATH_STRING:
1837
        cache->dbgReusedString++;
1838
        break;
1839
    case XPATH_POINT:
1840
        cache->dbgReusedPoint++;
1841
        break;
1842
    case XPATH_RANGE:
1843
        cache->dbgReusedRange++;
1844
        break;
1845
    case XPATH_LOCATIONSET:
1846
        cache->dbgReusedLocset++;
1847
        break;
1848
    case XPATH_USERS:
1849
        cache->dbgReusedUsers++;
1850
        break;
1851
    case XPATH_XSLT_TREE:
1852
        cache->dbgReusedXSLTTree++;
1853
        break;
1854
    default:
1855
        break;
1856
      }
1857
  }
1858
    }
1859
1860
    switch (objType) {
1861
  case XPATH_UNDEFINED:
1862
      if (! isCached)
1863
    xmlXPathDebugObjTotalUndefined++;
1864
      xmlXPathDebugObjCounterUndefined++;
1865
      if (xmlXPathDebugObjCounterUndefined >
1866
    xmlXPathDebugObjMaxUndefined)
1867
    xmlXPathDebugObjMaxUndefined =
1868
        xmlXPathDebugObjCounterUndefined;
1869
      break;
1870
  case XPATH_NODESET:
1871
      if (! isCached)
1872
    xmlXPathDebugObjTotalNodeset++;
1873
      xmlXPathDebugObjCounterNodeset++;
1874
      if (xmlXPathDebugObjCounterNodeset >
1875
    xmlXPathDebugObjMaxNodeset)
1876
    xmlXPathDebugObjMaxNodeset =
1877
        xmlXPathDebugObjCounterNodeset;
1878
      break;
1879
  case XPATH_BOOLEAN:
1880
      if (! isCached)
1881
    xmlXPathDebugObjTotalBool++;
1882
      xmlXPathDebugObjCounterBool++;
1883
      if (xmlXPathDebugObjCounterBool >
1884
    xmlXPathDebugObjMaxBool)
1885
    xmlXPathDebugObjMaxBool =
1886
        xmlXPathDebugObjCounterBool;
1887
      break;
1888
  case XPATH_NUMBER:
1889
      if (! isCached)
1890
    xmlXPathDebugObjTotalNumber++;
1891
      xmlXPathDebugObjCounterNumber++;
1892
      if (xmlXPathDebugObjCounterNumber >
1893
    xmlXPathDebugObjMaxNumber)
1894
    xmlXPathDebugObjMaxNumber =
1895
        xmlXPathDebugObjCounterNumber;
1896
      break;
1897
  case XPATH_STRING:
1898
      if (! isCached)
1899
    xmlXPathDebugObjTotalString++;
1900
      xmlXPathDebugObjCounterString++;
1901
      if (xmlXPathDebugObjCounterString >
1902
    xmlXPathDebugObjMaxString)
1903
    xmlXPathDebugObjMaxString =
1904
        xmlXPathDebugObjCounterString;
1905
      break;
1906
  case XPATH_POINT:
1907
      if (! isCached)
1908
    xmlXPathDebugObjTotalPoint++;
1909
      xmlXPathDebugObjCounterPoint++;
1910
      if (xmlXPathDebugObjCounterPoint >
1911
    xmlXPathDebugObjMaxPoint)
1912
    xmlXPathDebugObjMaxPoint =
1913
        xmlXPathDebugObjCounterPoint;
1914
      break;
1915
  case XPATH_RANGE:
1916
      if (! isCached)
1917
    xmlXPathDebugObjTotalRange++;
1918
      xmlXPathDebugObjCounterRange++;
1919
      if (xmlXPathDebugObjCounterRange >
1920
    xmlXPathDebugObjMaxRange)
1921
    xmlXPathDebugObjMaxRange =
1922
        xmlXPathDebugObjCounterRange;
1923
      break;
1924
  case XPATH_LOCATIONSET:
1925
      if (! isCached)
1926
    xmlXPathDebugObjTotalLocset++;
1927
      xmlXPathDebugObjCounterLocset++;
1928
      if (xmlXPathDebugObjCounterLocset >
1929
    xmlXPathDebugObjMaxLocset)
1930
    xmlXPathDebugObjMaxLocset =
1931
        xmlXPathDebugObjCounterLocset;
1932
      break;
1933
  case XPATH_USERS:
1934
      if (! isCached)
1935
    xmlXPathDebugObjTotalUsers++;
1936
      xmlXPathDebugObjCounterUsers++;
1937
      if (xmlXPathDebugObjCounterUsers >
1938
    xmlXPathDebugObjMaxUsers)
1939
    xmlXPathDebugObjMaxUsers =
1940
        xmlXPathDebugObjCounterUsers;
1941
      break;
1942
  case XPATH_XSLT_TREE:
1943
      if (! isCached)
1944
    xmlXPathDebugObjTotalXSLTTree++;
1945
      xmlXPathDebugObjCounterXSLTTree++;
1946
      if (xmlXPathDebugObjCounterXSLTTree >
1947
    xmlXPathDebugObjMaxXSLTTree)
1948
    xmlXPathDebugObjMaxXSLTTree =
1949
        xmlXPathDebugObjCounterXSLTTree;
1950
      break;
1951
  default:
1952
      break;
1953
    }
1954
    if (! isCached)
1955
  xmlXPathDebugObjTotalAll++;
1956
    xmlXPathDebugObjCounterAll++;
1957
    if (xmlXPathDebugObjCounterAll >
1958
  xmlXPathDebugObjMaxAll)
1959
  xmlXPathDebugObjMaxAll =
1960
      xmlXPathDebugObjCounterAll;
1961
}
1962
1963
static void
1964
xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1965
            xmlXPathObjectType objType)
1966
{
1967
    int isCached = 0;
1968
1969
    if (ctxt != NULL) {
1970
  if (ctxt->cache != NULL) {
1971
      xmlXPathContextCachePtr cache =
1972
    (xmlXPathContextCachePtr) ctxt->cache;
1973
1974
      isCached = 1;
1975
1976
      cache->dbgCachedAll++;
1977
      switch (objType) {
1978
    case XPATH_UNDEFINED:
1979
        cache->dbgCachedUndefined++;
1980
        break;
1981
    case XPATH_NODESET:
1982
        cache->dbgCachedNodeset++;
1983
        break;
1984
    case XPATH_BOOLEAN:
1985
        cache->dbgCachedBool++;
1986
        break;
1987
    case XPATH_NUMBER:
1988
        cache->dbgCachedNumber++;
1989
        break;
1990
    case XPATH_STRING:
1991
        cache->dbgCachedString++;
1992
        break;
1993
    case XPATH_POINT:
1994
        cache->dbgCachedPoint++;
1995
        break;
1996
    case XPATH_RANGE:
1997
        cache->dbgCachedRange++;
1998
        break;
1999
    case XPATH_LOCATIONSET:
2000
        cache->dbgCachedLocset++;
2001
        break;
2002
    case XPATH_USERS:
2003
        cache->dbgCachedUsers++;
2004
        break;
2005
    case XPATH_XSLT_TREE:
2006
        cache->dbgCachedXSLTTree++;
2007
        break;
2008
    default:
2009
        break;
2010
      }
2011
2012
  }
2013
    }
2014
    switch (objType) {
2015
  case XPATH_UNDEFINED:
2016
      xmlXPathDebugObjCounterUndefined--;
2017
      break;
2018
  case XPATH_NODESET:
2019
      xmlXPathDebugObjCounterNodeset--;
2020
      break;
2021
  case XPATH_BOOLEAN:
2022
      xmlXPathDebugObjCounterBool--;
2023
      break;
2024
  case XPATH_NUMBER:
2025
      xmlXPathDebugObjCounterNumber--;
2026
      break;
2027
  case XPATH_STRING:
2028
      xmlXPathDebugObjCounterString--;
2029
      break;
2030
  case XPATH_POINT:
2031
      xmlXPathDebugObjCounterPoint--;
2032
      break;
2033
  case XPATH_RANGE:
2034
      xmlXPathDebugObjCounterRange--;
2035
      break;
2036
  case XPATH_LOCATIONSET:
2037
      xmlXPathDebugObjCounterLocset--;
2038
      break;
2039
  case XPATH_USERS:
2040
      xmlXPathDebugObjCounterUsers--;
2041
      break;
2042
  case XPATH_XSLT_TREE:
2043
      xmlXPathDebugObjCounterXSLTTree--;
2044
      break;
2045
  default:
2046
      break;
2047
    }
2048
    xmlXPathDebugObjCounterAll--;
2049
}
2050
2051
/* REVISIT TODO: Make this static when committing */
2052
static void
2053
xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2054
{
2055
    int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2056
  reqXSLTTree, reqUndefined;
2057
    int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2058
  caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2059
    int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2060
  reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2061
    int leftObjs = xmlXPathDebugObjCounterAll;
2062
2063
    reqAll = xmlXPathDebugObjTotalAll;
2064
    reqNodeset = xmlXPathDebugObjTotalNodeset;
2065
    reqString = xmlXPathDebugObjTotalString;
2066
    reqBool = xmlXPathDebugObjTotalBool;
2067
    reqNumber = xmlXPathDebugObjTotalNumber;
2068
    reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2069
    reqUndefined = xmlXPathDebugObjTotalUndefined;
2070
2071
    printf("# XPath object usage:\n");
2072
2073
    if (ctxt != NULL) {
2074
  if (ctxt->cache != NULL) {
2075
      xmlXPathContextCachePtr cache =
2076
    (xmlXPathContextCachePtr) ctxt->cache;
2077
2078
      reAll = cache->dbgReusedAll;
2079
      reqAll += reAll;
2080
      reNodeset = cache->dbgReusedNodeset;
2081
      reqNodeset += reNodeset;
2082
      reString = cache->dbgReusedString;
2083
      reqString += reString;
2084
      reBool = cache->dbgReusedBool;
2085
      reqBool += reBool;
2086
      reNumber = cache->dbgReusedNumber;
2087
      reqNumber += reNumber;
2088
      reXSLTTree = cache->dbgReusedXSLTTree;
2089
      reqXSLTTree += reXSLTTree;
2090
      reUndefined = cache->dbgReusedUndefined;
2091
      reqUndefined += reUndefined;
2092
2093
      caAll = cache->dbgCachedAll;
2094
      caBool = cache->dbgCachedBool;
2095
      caNodeset = cache->dbgCachedNodeset;
2096
      caString = cache->dbgCachedString;
2097
      caNumber = cache->dbgCachedNumber;
2098
      caXSLTTree = cache->dbgCachedXSLTTree;
2099
      caUndefined = cache->dbgCachedUndefined;
2100
2101
      if (cache->nodesetObjs)
2102
    leftObjs -= cache->nodesetObjs->number;
2103
      if (cache->stringObjs)
2104
    leftObjs -= cache->stringObjs->number;
2105
      if (cache->booleanObjs)
2106
    leftObjs -= cache->booleanObjs->number;
2107
      if (cache->numberObjs)
2108
    leftObjs -= cache->numberObjs->number;
2109
      if (cache->miscObjs)
2110
    leftObjs -= cache->miscObjs->number;
2111
  }
2112
    }
2113
2114
    printf("# all\n");
2115
    printf("#   total  : %d\n", reqAll);
2116
    printf("#   left  : %d\n", leftObjs);
2117
    printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
2118
    printf("#   reused : %d\n", reAll);
2119
    printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
2120
2121
    printf("# node-sets\n");
2122
    printf("#   total  : %d\n", reqNodeset);
2123
    printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
2124
    printf("#   reused : %d\n", reNodeset);
2125
    printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
2126
2127
    printf("# strings\n");
2128
    printf("#   total  : %d\n", reqString);
2129
    printf("#   created: %d\n", xmlXPathDebugObjTotalString);
2130
    printf("#   reused : %d\n", reString);
2131
    printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
2132
2133
    printf("# booleans\n");
2134
    printf("#   total  : %d\n", reqBool);
2135
    printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
2136
    printf("#   reused : %d\n", reBool);
2137
    printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
2138
2139
    printf("# numbers\n");
2140
    printf("#   total  : %d\n", reqNumber);
2141
    printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
2142
    printf("#   reused : %d\n", reNumber);
2143
    printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
2144
2145
    printf("# XSLT result tree fragments\n");
2146
    printf("#   total  : %d\n", reqXSLTTree);
2147
    printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2148
    printf("#   reused : %d\n", reXSLTTree);
2149
    printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
2150
2151
    printf("# undefined\n");
2152
    printf("#   total  : %d\n", reqUndefined);
2153
    printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
2154
    printf("#   reused : %d\n", reUndefined);
2155
    printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
2156
2157
}
2158
2159
#endif /* XP_DEBUG_OBJ_USAGE */
2160
2161
#endif /* LIBXML_DEBUG_ENABLED */
2162
2163
/************************************************************************
2164
 *                  *
2165
 *      XPath object caching        *
2166
 *                  *
2167
 ************************************************************************/
2168
2169
/**
2170
 * xmlXPathNewCache:
2171
 *
2172
 * Create a new object cache
2173
 *
2174
 * Returns the xmlXPathCache just allocated.
2175
 */
2176
static xmlXPathContextCachePtr
2177
xmlXPathNewCache(void)
2178
0
{
2179
0
    xmlXPathContextCachePtr ret;
2180
2181
0
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2182
0
    if (ret == NULL) {
2183
0
        xmlXPathErrMemory(NULL, "creating object cache\n");
2184
0
  return(NULL);
2185
0
    }
2186
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2187
0
    ret->maxNodeset = 100;
2188
0
    ret->maxString = 100;
2189
0
    ret->maxBoolean = 100;
2190
0
    ret->maxNumber = 100;
2191
0
    ret->maxMisc = 100;
2192
0
    return(ret);
2193
0
}
2194
2195
static void
2196
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2197
0
{
2198
0
    int i;
2199
0
    xmlXPathObjectPtr obj;
2200
2201
0
    if (list == NULL)
2202
0
  return;
2203
2204
0
    for (i = 0; i < list->number; i++) {
2205
0
  obj = list->items[i];
2206
  /*
2207
  * Note that it is already assured that we don't need to
2208
  * look out for namespace nodes in the node-set.
2209
  */
2210
0
  if (obj->nodesetval != NULL) {
2211
0
      if (obj->nodesetval->nodeTab != NULL)
2212
0
    xmlFree(obj->nodesetval->nodeTab);
2213
0
      xmlFree(obj->nodesetval);
2214
0
  }
2215
0
  xmlFree(obj);
2216
#ifdef XP_DEBUG_OBJ_USAGE
2217
  xmlXPathDebugObjCounterAll--;
2218
#endif
2219
0
    }
2220
0
    xmlPointerListFree(list);
2221
0
}
2222
2223
static void
2224
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2225
0
{
2226
0
    if (cache == NULL)
2227
0
  return;
2228
0
    if (cache->nodesetObjs)
2229
0
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2230
0
    if (cache->stringObjs)
2231
0
  xmlXPathCacheFreeObjectList(cache->stringObjs);
2232
0
    if (cache->booleanObjs)
2233
0
  xmlXPathCacheFreeObjectList(cache->booleanObjs);
2234
0
    if (cache->numberObjs)
2235
0
  xmlXPathCacheFreeObjectList(cache->numberObjs);
2236
0
    if (cache->miscObjs)
2237
0
  xmlXPathCacheFreeObjectList(cache->miscObjs);
2238
0
    xmlFree(cache);
2239
0
}
2240
2241
/**
2242
 * xmlXPathContextSetCache:
2243
 *
2244
 * @ctxt:  the XPath context
2245
 * @active: enables/disables (creates/frees) the cache
2246
 * @value: a value with semantics dependant on @options
2247
 * @options: options (currently only the value 0 is used)
2248
 *
2249
 * Creates/frees an object cache on the XPath context.
2250
 * If activates XPath objects (xmlXPathObject) will be cached internally
2251
 * to be reused.
2252
 * @options:
2253
 *   0: This will set the XPath object caching:
2254
 *      @value:
2255
 *        This will set the maximum number of XPath objects
2256
 *        to be cached per slot
2257
 *        There are 5 slots for: node-set, string, number, boolean, and
2258
 *        misc objects. Use <0 for the default number (100).
2259
 *   Other values for @options have currently no effect.
2260
 *
2261
 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2262
 */
2263
int
2264
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2265
      int active,
2266
      int value,
2267
      int options)
2268
0
{
2269
0
    if (ctxt == NULL)
2270
0
  return(-1);
2271
0
    if (active) {
2272
0
  xmlXPathContextCachePtr cache;
2273
2274
0
  if (ctxt->cache == NULL) {
2275
0
      ctxt->cache = xmlXPathNewCache();
2276
0
      if (ctxt->cache == NULL)
2277
0
    return(-1);
2278
0
  }
2279
0
  cache = (xmlXPathContextCachePtr) ctxt->cache;
2280
0
  if (options == 0) {
2281
0
      if (value < 0)
2282
0
    value = 100;
2283
0
      cache->maxNodeset = value;
2284
0
      cache->maxString = value;
2285
0
      cache->maxNumber = value;
2286
0
      cache->maxBoolean = value;
2287
0
      cache->maxMisc = value;
2288
0
  }
2289
0
    } else if (ctxt->cache != NULL) {
2290
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2291
0
  ctxt->cache = NULL;
2292
0
    }
2293
0
    return(0);
2294
0
}
2295
2296
/**
2297
 * xmlXPathCacheWrapNodeSet:
2298
 * @ctxt: the XPath context
2299
 * @val:  the NodePtr value
2300
 *
2301
 * This is the cached version of xmlXPathWrapNodeSet().
2302
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2303
 *
2304
 * Returns the created or reused object.
2305
 */
2306
static xmlXPathObjectPtr
2307
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2308
0
{
2309
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2310
0
  xmlXPathContextCachePtr cache =
2311
0
      (xmlXPathContextCachePtr) ctxt->cache;
2312
2313
0
  if ((cache->miscObjs != NULL) &&
2314
0
      (cache->miscObjs->number != 0))
2315
0
  {
2316
0
      xmlXPathObjectPtr ret;
2317
2318
0
      ret = (xmlXPathObjectPtr)
2319
0
    cache->miscObjs->items[--cache->miscObjs->number];
2320
0
      ret->type = XPATH_NODESET;
2321
0
      ret->nodesetval = val;
2322
#ifdef XP_DEBUG_OBJ_USAGE
2323
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2324
#endif
2325
0
      return(ret);
2326
0
  }
2327
0
    }
2328
2329
0
    return(xmlXPathWrapNodeSet(val));
2330
2331
0
}
2332
2333
/**
2334
 * xmlXPathCacheWrapString:
2335
 * @ctxt: the XPath context
2336
 * @val:  the xmlChar * value
2337
 *
2338
 * This is the cached version of xmlXPathWrapString().
2339
 * Wraps the @val string into an XPath object.
2340
 *
2341
 * Returns the created or reused object.
2342
 */
2343
static xmlXPathObjectPtr
2344
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2345
0
{
2346
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2347
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2348
2349
0
  if ((cache->stringObjs != NULL) &&
2350
0
      (cache->stringObjs->number != 0))
2351
0
  {
2352
2353
0
      xmlXPathObjectPtr ret;
2354
2355
0
      ret = (xmlXPathObjectPtr)
2356
0
    cache->stringObjs->items[--cache->stringObjs->number];
2357
0
      ret->type = XPATH_STRING;
2358
0
      ret->stringval = val;
2359
#ifdef XP_DEBUG_OBJ_USAGE
2360
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2361
#endif
2362
0
      return(ret);
2363
0
  } else if ((cache->miscObjs != NULL) &&
2364
0
      (cache->miscObjs->number != 0))
2365
0
  {
2366
0
      xmlXPathObjectPtr ret;
2367
      /*
2368
      * Fallback to misc-cache.
2369
      */
2370
0
      ret = (xmlXPathObjectPtr)
2371
0
    cache->miscObjs->items[--cache->miscObjs->number];
2372
2373
0
      ret->type = XPATH_STRING;
2374
0
      ret->stringval = val;
2375
#ifdef XP_DEBUG_OBJ_USAGE
2376
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2377
#endif
2378
0
      return(ret);
2379
0
  }
2380
0
    }
2381
0
    return(xmlXPathWrapString(val));
2382
0
}
2383
2384
/**
2385
 * xmlXPathCacheNewNodeSet:
2386
 * @ctxt: the XPath context
2387
 * @val:  the NodePtr value
2388
 *
2389
 * This is the cached version of xmlXPathNewNodeSet().
2390
 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2391
 * it with the single Node @val
2392
 *
2393
 * Returns the created or reused object.
2394
 */
2395
static xmlXPathObjectPtr
2396
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2397
0
{
2398
0
    if ((ctxt != NULL) && (ctxt->cache)) {
2399
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2400
2401
0
  if ((cache->nodesetObjs != NULL) &&
2402
0
      (cache->nodesetObjs->number != 0))
2403
0
  {
2404
0
      xmlXPathObjectPtr ret;
2405
      /*
2406
      * Use the nodset-cache.
2407
      */
2408
0
      ret = (xmlXPathObjectPtr)
2409
0
    cache->nodesetObjs->items[--cache->nodesetObjs->number];
2410
0
      ret->type = XPATH_NODESET;
2411
0
      ret->boolval = 0;
2412
0
      if (val) {
2413
0
    if ((ret->nodesetval->nodeMax == 0) ||
2414
0
        (val->type == XML_NAMESPACE_DECL))
2415
0
    {
2416
0
        xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2417
0
    } else {
2418
0
        ret->nodesetval->nodeTab[0] = val;
2419
0
        ret->nodesetval->nodeNr = 1;
2420
0
    }
2421
0
      }
2422
#ifdef XP_DEBUG_OBJ_USAGE
2423
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2424
#endif
2425
0
      return(ret);
2426
0
  } else if ((cache->miscObjs != NULL) &&
2427
0
      (cache->miscObjs->number != 0))
2428
0
  {
2429
0
      xmlXPathObjectPtr ret;
2430
      /*
2431
      * Fallback to misc-cache.
2432
      */
2433
2434
0
      ret = (xmlXPathObjectPtr)
2435
0
    cache->miscObjs->items[--cache->miscObjs->number];
2436
2437
0
      ret->type = XPATH_NODESET;
2438
0
      ret->boolval = 0;
2439
0
      ret->nodesetval = xmlXPathNodeSetCreate(val);
2440
0
      if (ret->nodesetval == NULL) {
2441
0
    ctxt->lastError.domain = XML_FROM_XPATH;
2442
0
    ctxt->lastError.code = XML_ERR_NO_MEMORY;
2443
0
    return(NULL);
2444
0
      }
2445
#ifdef XP_DEBUG_OBJ_USAGE
2446
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2447
#endif
2448
0
      return(ret);
2449
0
  }
2450
0
    }
2451
0
    return(xmlXPathNewNodeSet(val));
2452
0
}
2453
2454
/**
2455
 * xmlXPathCacheNewCString:
2456
 * @ctxt: the XPath context
2457
 * @val:  the char * value
2458
 *
2459
 * This is the cached version of xmlXPathNewCString().
2460
 * Acquire an xmlXPathObjectPtr of type string and of value @val
2461
 *
2462
 * Returns the created or reused object.
2463
 */
2464
static xmlXPathObjectPtr
2465
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2466
0
{
2467
0
    if ((ctxt != NULL) && (ctxt->cache)) {
2468
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2469
2470
0
  if ((cache->stringObjs != NULL) &&
2471
0
      (cache->stringObjs->number != 0))
2472
0
  {
2473
0
      xmlXPathObjectPtr ret;
2474
2475
0
      ret = (xmlXPathObjectPtr)
2476
0
    cache->stringObjs->items[--cache->stringObjs->number];
2477
2478
0
      ret->type = XPATH_STRING;
2479
0
      ret->stringval = xmlStrdup(BAD_CAST val);
2480
#ifdef XP_DEBUG_OBJ_USAGE
2481
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2482
#endif
2483
0
      return(ret);
2484
0
  } else if ((cache->miscObjs != NULL) &&
2485
0
      (cache->miscObjs->number != 0))
2486
0
  {
2487
0
      xmlXPathObjectPtr ret;
2488
2489
0
      ret = (xmlXPathObjectPtr)
2490
0
    cache->miscObjs->items[--cache->miscObjs->number];
2491
2492
0
      ret->type = XPATH_STRING;
2493
0
      ret->stringval = xmlStrdup(BAD_CAST val);
2494
#ifdef XP_DEBUG_OBJ_USAGE
2495
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2496
#endif
2497
0
      return(ret);
2498
0
  }
2499
0
    }
2500
0
    return(xmlXPathNewCString(val));
2501
0
}
2502
2503
/**
2504
 * xmlXPathCacheNewString:
2505
 * @ctxt: the XPath context
2506
 * @val:  the xmlChar * value
2507
 *
2508
 * This is the cached version of xmlXPathNewString().
2509
 * Acquire an xmlXPathObjectPtr of type string and of value @val
2510
 *
2511
 * Returns the created or reused object.
2512
 */
2513
static xmlXPathObjectPtr
2514
xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2515
0
{
2516
0
    if ((ctxt != NULL) && (ctxt->cache)) {
2517
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2518
2519
0
  if ((cache->stringObjs != NULL) &&
2520
0
      (cache->stringObjs->number != 0))
2521
0
  {
2522
0
      xmlXPathObjectPtr ret;
2523
2524
0
      ret = (xmlXPathObjectPtr)
2525
0
    cache->stringObjs->items[--cache->stringObjs->number];
2526
0
      ret->type = XPATH_STRING;
2527
0
      if (val != NULL)
2528
0
    ret->stringval = xmlStrdup(val);
2529
0
      else
2530
0
    ret->stringval = xmlStrdup((const xmlChar *)"");
2531
#ifdef XP_DEBUG_OBJ_USAGE
2532
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2533
#endif
2534
0
      return(ret);
2535
0
  } else if ((cache->miscObjs != NULL) &&
2536
0
      (cache->miscObjs->number != 0))
2537
0
  {
2538
0
      xmlXPathObjectPtr ret;
2539
2540
0
      ret = (xmlXPathObjectPtr)
2541
0
    cache->miscObjs->items[--cache->miscObjs->number];
2542
2543
0
      ret->type = XPATH_STRING;
2544
0
      if (val != NULL)
2545
0
    ret->stringval = xmlStrdup(val);
2546
0
      else
2547
0
    ret->stringval = xmlStrdup((const xmlChar *)"");
2548
#ifdef XP_DEBUG_OBJ_USAGE
2549
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2550
#endif
2551
0
      return(ret);
2552
0
  }
2553
0
    }
2554
0
    return(xmlXPathNewString(val));
2555
0
}
2556
2557
/**
2558
 * xmlXPathCacheNewBoolean:
2559
 * @ctxt: the XPath context
2560
 * @val:  the boolean value
2561
 *
2562
 * This is the cached version of xmlXPathNewBoolean().
2563
 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2564
 *
2565
 * Returns the created or reused object.
2566
 */
2567
static xmlXPathObjectPtr
2568
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2569
0
{
2570
0
    if ((ctxt != NULL) && (ctxt->cache)) {
2571
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2572
2573
0
  if ((cache->booleanObjs != NULL) &&
2574
0
      (cache->booleanObjs->number != 0))
2575
0
  {
2576
0
      xmlXPathObjectPtr ret;
2577
2578
0
      ret = (xmlXPathObjectPtr)
2579
0
    cache->booleanObjs->items[--cache->booleanObjs->number];
2580
0
      ret->type = XPATH_BOOLEAN;
2581
0
      ret->boolval = (val != 0);
2582
#ifdef XP_DEBUG_OBJ_USAGE
2583
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2584
#endif
2585
0
      return(ret);
2586
0
  } else if ((cache->miscObjs != NULL) &&
2587
0
      (cache->miscObjs->number != 0))
2588
0
  {
2589
0
      xmlXPathObjectPtr ret;
2590
2591
0
      ret = (xmlXPathObjectPtr)
2592
0
    cache->miscObjs->items[--cache->miscObjs->number];
2593
2594
0
      ret->type = XPATH_BOOLEAN;
2595
0
      ret->boolval = (val != 0);
2596
#ifdef XP_DEBUG_OBJ_USAGE
2597
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2598
#endif
2599
0
      return(ret);
2600
0
  }
2601
0
    }
2602
0
    return(xmlXPathNewBoolean(val));
2603
0
}
2604
2605
/**
2606
 * xmlXPathCacheNewFloat:
2607
 * @ctxt: the XPath context
2608
 * @val:  the double value
2609
 *
2610
 * This is the cached version of xmlXPathNewFloat().
2611
 * Acquires an xmlXPathObjectPtr of type double and of value @val
2612
 *
2613
 * Returns the created or reused object.
2614
 */
2615
static xmlXPathObjectPtr
2616
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2617
0
{
2618
0
     if ((ctxt != NULL) && (ctxt->cache)) {
2619
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2620
2621
0
  if ((cache->numberObjs != NULL) &&
2622
0
      (cache->numberObjs->number != 0))
2623
0
  {
2624
0
      xmlXPathObjectPtr ret;
2625
2626
0
      ret = (xmlXPathObjectPtr)
2627
0
    cache->numberObjs->items[--cache->numberObjs->number];
2628
0
      ret->type = XPATH_NUMBER;
2629
0
      ret->floatval = val;
2630
#ifdef XP_DEBUG_OBJ_USAGE
2631
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2632
#endif
2633
0
      return(ret);
2634
0
  } else if ((cache->miscObjs != NULL) &&
2635
0
      (cache->miscObjs->number != 0))
2636
0
  {
2637
0
      xmlXPathObjectPtr ret;
2638
2639
0
      ret = (xmlXPathObjectPtr)
2640
0
    cache->miscObjs->items[--cache->miscObjs->number];
2641
2642
0
      ret->type = XPATH_NUMBER;
2643
0
      ret->floatval = val;
2644
#ifdef XP_DEBUG_OBJ_USAGE
2645
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2646
#endif
2647
0
      return(ret);
2648
0
  }
2649
0
    }
2650
0
    return(xmlXPathNewFloat(val));
2651
0
}
2652
2653
/**
2654
 * xmlXPathCacheConvertString:
2655
 * @ctxt: the XPath context
2656
 * @val:  an XPath object
2657
 *
2658
 * This is the cached version of xmlXPathConvertString().
2659
 * Converts an existing object to its string() equivalent
2660
 *
2661
 * Returns a created or reused object, the old one is freed (cached)
2662
 *         (or the operation is done directly on @val)
2663
 */
2664
2665
static xmlXPathObjectPtr
2666
0
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2667
0
    xmlChar *res = NULL;
2668
2669
0
    if (val == NULL)
2670
0
  return(xmlXPathCacheNewCString(ctxt, ""));
2671
2672
0
    switch (val->type) {
2673
0
    case XPATH_UNDEFINED:
2674
#ifdef DEBUG_EXPR
2675
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2676
#endif
2677
0
  break;
2678
0
    case XPATH_NODESET:
2679
0
    case XPATH_XSLT_TREE:
2680
0
  res = xmlXPathCastNodeSetToString(val->nodesetval);
2681
0
  break;
2682
0
    case XPATH_STRING:
2683
0
  return(val);
2684
0
    case XPATH_BOOLEAN:
2685
0
  res = xmlXPathCastBooleanToString(val->boolval);
2686
0
  break;
2687
0
    case XPATH_NUMBER:
2688
0
  res = xmlXPathCastNumberToString(val->floatval);
2689
0
  break;
2690
0
    case XPATH_USERS:
2691
0
    case XPATH_POINT:
2692
0
    case XPATH_RANGE:
2693
0
    case XPATH_LOCATIONSET:
2694
0
  TODO;
2695
0
  break;
2696
0
    }
2697
0
    xmlXPathReleaseObject(ctxt, val);
2698
0
    if (res == NULL)
2699
0
  return(xmlXPathCacheNewCString(ctxt, ""));
2700
0
    return(xmlXPathCacheWrapString(ctxt, res));
2701
0
}
2702
2703
/**
2704
 * xmlXPathCacheObjectCopy:
2705
 * @ctxt: the XPath context
2706
 * @val:  the original object
2707
 *
2708
 * This is the cached version of xmlXPathObjectCopy().
2709
 * Acquire a copy of a given object
2710
 *
2711
 * Returns a created or reused created object.
2712
 */
2713
static xmlXPathObjectPtr
2714
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2715
0
{
2716
0
    if (val == NULL)
2717
0
  return(NULL);
2718
2719
0
    if (XP_HAS_CACHE(ctxt)) {
2720
0
  switch (val->type) {
2721
0
      case XPATH_NODESET:
2722
0
    return(xmlXPathCacheWrapNodeSet(ctxt,
2723
0
        xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2724
0
      case XPATH_STRING:
2725
0
    return(xmlXPathCacheNewString(ctxt, val->stringval));
2726
0
      case XPATH_BOOLEAN:
2727
0
    return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2728
0
      case XPATH_NUMBER:
2729
0
    return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2730
0
      default:
2731
0
    break;
2732
0
  }
2733
0
    }
2734
0
    return(xmlXPathObjectCopy(val));
2735
0
}
2736
2737
/**
2738
 * xmlXPathCacheConvertBoolean:
2739
 * @ctxt: the XPath context
2740
 * @val:  an XPath object
2741
 *
2742
 * This is the cached version of xmlXPathConvertBoolean().
2743
 * Converts an existing object to its boolean() equivalent
2744
 *
2745
 * Returns a created or reused object, the old one is freed (or the operation
2746
 *         is done directly on @val)
2747
 */
2748
static xmlXPathObjectPtr
2749
0
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2750
0
    xmlXPathObjectPtr ret;
2751
2752
0
    if (val == NULL)
2753
0
  return(xmlXPathCacheNewBoolean(ctxt, 0));
2754
0
    if (val->type == XPATH_BOOLEAN)
2755
0
  return(val);
2756
0
    ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2757
0
    xmlXPathReleaseObject(ctxt, val);
2758
0
    return(ret);
2759
0
}
2760
2761
/**
2762
 * xmlXPathCacheConvertNumber:
2763
 * @ctxt: the XPath context
2764
 * @val:  an XPath object
2765
 *
2766
 * This is the cached version of xmlXPathConvertNumber().
2767
 * Converts an existing object to its number() equivalent
2768
 *
2769
 * Returns a created or reused object, the old one is freed (or the operation
2770
 *         is done directly on @val)
2771
 */
2772
static xmlXPathObjectPtr
2773
0
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2774
0
    xmlXPathObjectPtr ret;
2775
2776
0
    if (val == NULL)
2777
0
  return(xmlXPathCacheNewFloat(ctxt, 0.0));
2778
0
    if (val->type == XPATH_NUMBER)
2779
0
  return(val);
2780
0
    ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2781
0
    xmlXPathReleaseObject(ctxt, val);
2782
0
    return(ret);
2783
0
}
2784
2785
/************************************************************************
2786
 *                  *
2787
 *    Parser stacks related functions and macros    *
2788
 *                  *
2789
 ************************************************************************/
2790
2791
/**
2792
 * xmlXPathSetFrame:
2793
 * @ctxt: an XPath parser context
2794
 *
2795
 * Set the callee evaluation frame
2796
 *
2797
 * Returns the previous frame value to be restored once done
2798
 */
2799
static int
2800
0
xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2801
0
    int ret;
2802
2803
0
    if (ctxt == NULL)
2804
0
        return(0);
2805
0
    ret = ctxt->valueFrame;
2806
0
    ctxt->valueFrame = ctxt->valueNr;
2807
0
    return(ret);
2808
0
}
2809
2810
/**
2811
 * xmlXPathPopFrame:
2812
 * @ctxt: an XPath parser context
2813
 * @frame: the previous frame value
2814
 *
2815
 * Remove the callee evaluation frame
2816
 */
2817
static void
2818
0
xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2819
0
    if (ctxt == NULL)
2820
0
        return;
2821
0
    if (ctxt->valueNr < ctxt->valueFrame) {
2822
0
        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2823
0
    }
2824
0
    ctxt->valueFrame = frame;
2825
0
}
2826
2827
/**
2828
 * valuePop:
2829
 * @ctxt: an XPath evaluation context
2830
 *
2831
 * Pops the top XPath object from the value stack
2832
 *
2833
 * Returns the XPath object just removed
2834
 */
2835
xmlXPathObjectPtr
2836
valuePop(xmlXPathParserContextPtr ctxt)
2837
0
{
2838
0
    xmlXPathObjectPtr ret;
2839
2840
0
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2841
0
        return (NULL);
2842
2843
0
    if (ctxt->valueNr <= ctxt->valueFrame) {
2844
0
        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2845
0
        return (NULL);
2846
0
    }
2847
2848
0
    ctxt->valueNr--;
2849
0
    if (ctxt->valueNr > 0)
2850
0
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2851
0
    else
2852
0
        ctxt->value = NULL;
2853
0
    ret = ctxt->valueTab[ctxt->valueNr];
2854
0
    ctxt->valueTab[ctxt->valueNr] = NULL;
2855
0
    return (ret);
2856
0
}
2857
/**
2858
 * valuePush:
2859
 * @ctxt:  an XPath evaluation context
2860
 * @value:  the XPath object
2861
 *
2862
 * Pushes a new XPath object on top of the value stack
2863
 *
2864
 * returns the number of items on the value stack
2865
 */
2866
int
2867
valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2868
0
{
2869
0
    if ((ctxt == NULL) || (value == NULL)) return(-1);
2870
0
    if (ctxt->valueNr >= ctxt->valueMax) {
2871
0
        xmlXPathObjectPtr *tmp;
2872
2873
0
        if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2874
0
            xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2875
0
            ctxt->error = XPATH_MEMORY_ERROR;
2876
0
            return (0);
2877
0
        }
2878
0
        tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2879
0
                                             2 * ctxt->valueMax *
2880
0
                                             sizeof(ctxt->valueTab[0]));
2881
0
        if (tmp == NULL) {
2882
0
            xmlXPathErrMemory(NULL, "pushing value\n");
2883
0
            ctxt->error = XPATH_MEMORY_ERROR;
2884
0
            return (0);
2885
0
        }
2886
0
        ctxt->valueMax *= 2;
2887
0
  ctxt->valueTab = tmp;
2888
0
    }
2889
0
    ctxt->valueTab[ctxt->valueNr] = value;
2890
0
    ctxt->value = value;
2891
0
    return (ctxt->valueNr++);
2892
0
}
2893
2894
/**
2895
 * xmlXPathPopBoolean:
2896
 * @ctxt:  an XPath parser context
2897
 *
2898
 * Pops a boolean from the stack, handling conversion if needed.
2899
 * Check error with #xmlXPathCheckError.
2900
 *
2901
 * Returns the boolean
2902
 */
2903
int
2904
0
xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2905
0
    xmlXPathObjectPtr obj;
2906
0
    int ret;
2907
2908
0
    obj = valuePop(ctxt);
2909
0
    if (obj == NULL) {
2910
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2911
0
  return(0);
2912
0
    }
2913
0
    if (obj->type != XPATH_BOOLEAN)
2914
0
  ret = xmlXPathCastToBoolean(obj);
2915
0
    else
2916
0
        ret = obj->boolval;
2917
0
    xmlXPathReleaseObject(ctxt->context, obj);
2918
0
    return(ret);
2919
0
}
2920
2921
/**
2922
 * xmlXPathPopNumber:
2923
 * @ctxt:  an XPath parser context
2924
 *
2925
 * Pops a number from the stack, handling conversion if needed.
2926
 * Check error with #xmlXPathCheckError.
2927
 *
2928
 * Returns the number
2929
 */
2930
double
2931
0
xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2932
0
    xmlXPathObjectPtr obj;
2933
0
    double ret;
2934
2935
0
    obj = valuePop(ctxt);
2936
0
    if (obj == NULL) {
2937
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2938
0
  return(0);
2939
0
    }
2940
0
    if (obj->type != XPATH_NUMBER)
2941
0
  ret = xmlXPathCastToNumber(obj);
2942
0
    else
2943
0
        ret = obj->floatval;
2944
0
    xmlXPathReleaseObject(ctxt->context, obj);
2945
0
    return(ret);
2946
0
}
2947
2948
/**
2949
 * xmlXPathPopString:
2950
 * @ctxt:  an XPath parser context
2951
 *
2952
 * Pops a string from the stack, handling conversion if needed.
2953
 * Check error with #xmlXPathCheckError.
2954
 *
2955
 * Returns the string
2956
 */
2957
xmlChar *
2958
0
xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2959
0
    xmlXPathObjectPtr obj;
2960
0
    xmlChar * ret;
2961
2962
0
    obj = valuePop(ctxt);
2963
0
    if (obj == NULL) {
2964
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2965
0
  return(NULL);
2966
0
    }
2967
0
    ret = xmlXPathCastToString(obj);  /* this does required strdup */
2968
    /* TODO: needs refactoring somewhere else */
2969
0
    if (obj->stringval == ret)
2970
0
  obj->stringval = NULL;
2971
0
    xmlXPathReleaseObject(ctxt->context, obj);
2972
0
    return(ret);
2973
0
}
2974
2975
/**
2976
 * xmlXPathPopNodeSet:
2977
 * @ctxt:  an XPath parser context
2978
 *
2979
 * Pops a node-set from the stack, handling conversion if needed.
2980
 * Check error with #xmlXPathCheckError.
2981
 *
2982
 * Returns the node-set
2983
 */
2984
xmlNodeSetPtr
2985
0
xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2986
0
    xmlXPathObjectPtr obj;
2987
0
    xmlNodeSetPtr ret;
2988
2989
0
    if (ctxt == NULL) return(NULL);
2990
0
    if (ctxt->value == NULL) {
2991
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2992
0
  return(NULL);
2993
0
    }
2994
0
    if (!xmlXPathStackIsNodeSet(ctxt)) {
2995
0
  xmlXPathSetTypeError(ctxt);
2996
0
  return(NULL);
2997
0
    }
2998
0
    obj = valuePop(ctxt);
2999
0
    ret = obj->nodesetval;
3000
#if 0
3001
    /* to fix memory leak of not clearing obj->user */
3002
    if (obj->boolval && obj->user != NULL)
3003
        xmlFreeNodeList((xmlNodePtr) obj->user);
3004
#endif
3005
0
    obj->nodesetval = NULL;
3006
0
    xmlXPathReleaseObject(ctxt->context, obj);
3007
0
    return(ret);
3008
0
}
3009
3010
/**
3011
 * xmlXPathPopExternal:
3012
 * @ctxt:  an XPath parser context
3013
 *
3014
 * Pops an external object from the stack, handling conversion if needed.
3015
 * Check error with #xmlXPathCheckError.
3016
 *
3017
 * Returns the object
3018
 */
3019
void *
3020
0
xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3021
0
    xmlXPathObjectPtr obj;
3022
0
    void * ret;
3023
3024
0
    if ((ctxt == NULL) || (ctxt->value == NULL)) {
3025
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3026
0
  return(NULL);
3027
0
    }
3028
0
    if (ctxt->value->type != XPATH_USERS) {
3029
0
  xmlXPathSetTypeError(ctxt);
3030
0
  return(NULL);
3031
0
    }
3032
0
    obj = valuePop(ctxt);
3033
0
    ret = obj->user;
3034
0
    obj->user = NULL;
3035
0
    xmlXPathReleaseObject(ctxt->context, obj);
3036
0
    return(ret);
3037
0
}
3038
3039
/*
3040
 * Macros for accessing the content. Those should be used only by the parser,
3041
 * and not exported.
3042
 *
3043
 * Dirty macros, i.e. one need to make assumption on the context to use them
3044
 *
3045
 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
3046
 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
3047
 *           in ISO-Latin or UTF-8.
3048
 *           This should be used internally by the parser
3049
 *           only to compare to ASCII values otherwise it would break when
3050
 *           running with UTF-8 encoding.
3051
 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
3052
 *           to compare on ASCII based substring.
3053
 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3054
 *           strings within the parser.
3055
 *   CURRENT Returns the current char value, with the full decoding of
3056
 *           UTF-8 if we are using this mode. It returns an int.
3057
 *   NEXT    Skip to the next character, this does the proper decoding
3058
 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
3059
 *           It returns the pointer to the current xmlChar.
3060
 */
3061
3062
0
#define CUR (*ctxt->cur)
3063
0
#define SKIP(val) ctxt->cur += (val)
3064
0
#define NXT(val) ctxt->cur[(val)]
3065
0
#define CUR_PTR ctxt->cur
3066
0
#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3067
3068
#define COPY_BUF(l,b,i,v)                                              \
3069
0
    if (l == 1) b[i++] = (xmlChar) v;                                  \
3070
0
    else i += xmlCopyChar(l,&b[i],v)
3071
3072
0
#define NEXTL(l)  ctxt->cur += l
3073
3074
#define SKIP_BLANKS             \
3075
0
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3076
3077
#define CURRENT (*ctxt->cur)
3078
0
#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
3079
3080
3081
#ifndef DBL_DIG
3082
#define DBL_DIG 16
3083
#endif
3084
#ifndef DBL_EPSILON
3085
#define DBL_EPSILON 1E-9
3086
#endif
3087
3088
0
#define UPPER_DOUBLE 1E9
3089
0
#define LOWER_DOUBLE 1E-5
3090
#define LOWER_DOUBLE_EXP 5
3091
3092
#define INTEGER_DIGITS DBL_DIG
3093
#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3094
0
#define EXPONENT_DIGITS (3 + 2)
3095
3096
/**
3097
 * xmlXPathFormatNumber:
3098
 * @number:     number to format
3099
 * @buffer:     output buffer
3100
 * @buffersize: size of output buffer
3101
 *
3102
 * Convert the number into a string representation.
3103
 */
3104
static void
3105
xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3106
0
{
3107
0
    switch (xmlXPathIsInf(number)) {
3108
0
    case 1:
3109
0
  if (buffersize > (int)sizeof("Infinity"))
3110
0
      snprintf(buffer, buffersize, "Infinity");
3111
0
  break;
3112
0
    case -1:
3113
0
  if (buffersize > (int)sizeof("-Infinity"))
3114
0
      snprintf(buffer, buffersize, "-Infinity");
3115
0
  break;
3116
0
    default:
3117
0
  if (xmlXPathIsNaN(number)) {
3118
0
      if (buffersize > (int)sizeof("NaN"))
3119
0
    snprintf(buffer, buffersize, "NaN");
3120
0
  } else if (number == 0 && xmlXPathGetSign(number) != 0) {
3121
0
      snprintf(buffer, buffersize, "0");
3122
0
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
3123
0
                   (number == (int) number)) {
3124
0
      char work[30];
3125
0
      char *ptr, *cur;
3126
0
      int value = (int) number;
3127
3128
0
            ptr = &buffer[0];
3129
0
      if (value == 0) {
3130
0
    *ptr++ = '0';
3131
0
      } else {
3132
0
    snprintf(work, 29, "%d", value);
3133
0
    cur = &work[0];
3134
0
    while ((*cur) && (ptr - buffer < buffersize)) {
3135
0
        *ptr++ = *cur++;
3136
0
    }
3137
0
      }
3138
0
      if (ptr - buffer < buffersize) {
3139
0
    *ptr = 0;
3140
0
      } else if (buffersize > 0) {
3141
0
    ptr--;
3142
0
    *ptr = 0;
3143
0
      }
3144
0
  } else {
3145
      /*
3146
        For the dimension of work,
3147
            DBL_DIG is number of significant digits
3148
      EXPONENT is only needed for "scientific notation"
3149
            3 is sign, decimal point, and terminating zero
3150
      LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3151
        Note that this dimension is slightly (a few characters)
3152
        larger than actually necessary.
3153
      */
3154
0
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3155
0
      int integer_place, fraction_place;
3156
0
      char *ptr;
3157
0
      char *after_fraction;
3158
0
      double absolute_value;
3159
0
      int size;
3160
3161
0
      absolute_value = fabs(number);
3162
3163
      /*
3164
       * First choose format - scientific or regular floating point.
3165
       * In either case, result is in work, and after_fraction points
3166
       * just past the fractional part.
3167
      */
3168
0
      if ( ((absolute_value > UPPER_DOUBLE) ||
3169
0
      (absolute_value < LOWER_DOUBLE)) &&
3170
0
     (absolute_value != 0.0) ) {
3171
    /* Use scientific notation */
3172
0
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3173
0
    fraction_place = DBL_DIG - 1;
3174
0
    size = snprintf(work, sizeof(work),"%*.*e",
3175
0
       integer_place, fraction_place, number);
3176
0
    while ((size > 0) && (work[size] != 'e')) size--;
3177
3178
0
      }
3179
0
      else {
3180
    /* Use regular notation */
3181
0
    if (absolute_value > 0.0) {
3182
0
        integer_place = (int)log10(absolute_value);
3183
0
        if (integer_place > 0)
3184
0
            fraction_place = DBL_DIG - integer_place - 1;
3185
0
        else
3186
0
            fraction_place = DBL_DIG - integer_place;
3187
0
    } else {
3188
0
        fraction_place = 1;
3189
0
    }
3190
0
    size = snprintf(work, sizeof(work), "%0.*f",
3191
0
        fraction_place, number);
3192
0
      }
3193
3194
      /* Remove leading spaces sometimes inserted by snprintf */
3195
0
      while (work[0] == ' ') {
3196
0
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3197
0
    size--;
3198
0
      }
3199
3200
      /* Remove fractional trailing zeroes */
3201
0
      after_fraction = work + size;
3202
0
      ptr = after_fraction;
3203
0
      while (*(--ptr) == '0')
3204
0
    ;
3205
0
      if (*ptr != '.')
3206
0
          ptr++;
3207
0
      while ((*ptr++ = *after_fraction++) != 0);
3208
3209
      /* Finally copy result back to caller */
3210
0
      size = strlen(work) + 1;
3211
0
      if (size > buffersize) {
3212
0
    work[buffersize - 1] = 0;
3213
0
    size = buffersize;
3214
0
      }
3215
0
      memmove(buffer, work, size);
3216
0
  }
3217
0
  break;
3218
0
    }
3219
0
}
3220
3221
3222
/************************************************************************
3223
 *                  *
3224
 *      Routines to handle NodeSets     *
3225
 *                  *
3226
 ************************************************************************/
3227
3228
/**
3229
 * xmlXPathOrderDocElems:
3230
 * @doc:  an input document
3231
 *
3232
 * Call this routine to speed up XPath computation on static documents.
3233
 * This stamps all the element nodes with the document order
3234
 * Like for line information, the order is kept in the element->content
3235
 * field, the value stored is actually - the node number (starting at -1)
3236
 * to be able to differentiate from line numbers.
3237
 *
3238
 * Returns the number of elements found in the document or -1 in case
3239
 *    of error.
3240
 */
3241
long
3242
0
xmlXPathOrderDocElems(xmlDocPtr doc) {
3243
0
    ptrdiff_t count = 0;
3244
0
    xmlNodePtr cur;
3245
3246
0
    if (doc == NULL)
3247
0
  return(-1);
3248
0
    cur = doc->children;
3249
0
    while (cur != NULL) {
3250
0
  if (cur->type == XML_ELEMENT_NODE) {
3251
0
      cur->content = (void *) (-(++count));
3252
0
      if (cur->children != NULL) {
3253
0
    cur = cur->children;
3254
0
    continue;
3255
0
      }
3256
0
  }
3257
0
  if (cur->next != NULL) {
3258
0
      cur = cur->next;
3259
0
      continue;
3260
0
  }
3261
0
  do {
3262
0
      cur = cur->parent;
3263
0
      if (cur == NULL)
3264
0
    break;
3265
0
      if (cur == (xmlNodePtr) doc) {
3266
0
    cur = NULL;
3267
0
    break;
3268
0
      }
3269
0
      if (cur->next != NULL) {
3270
0
    cur = cur->next;
3271
0
    break;
3272
0
      }
3273
0
  } while (cur != NULL);
3274
0
    }
3275
0
    return((long) count);
3276
0
}
3277
3278
/**
3279
 * xmlXPathCmpNodes:
3280
 * @node1:  the first node
3281
 * @node2:  the second node
3282
 *
3283
 * Compare two nodes w.r.t document order
3284
 *
3285
 * Returns -2 in case of error 1 if first point < second point, 0 if
3286
 *         it's the same node, -1 otherwise
3287
 */
3288
int
3289
0
xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3290
0
    int depth1, depth2;
3291
0
    int attr1 = 0, attr2 = 0;
3292
0
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3293
0
    xmlNodePtr cur, root;
3294
3295
0
    if ((node1 == NULL) || (node2 == NULL))
3296
0
  return(-2);
3297
    /*
3298
     * a couple of optimizations which will avoid computations in most cases
3299
     */
3300
0
    if (node1 == node2)   /* trivial case */
3301
0
  return(0);
3302
0
    if (node1->type == XML_ATTRIBUTE_NODE) {
3303
0
  attr1 = 1;
3304
0
  attrNode1 = node1;
3305
0
  node1 = node1->parent;
3306
0
    }
3307
0
    if (node2->type == XML_ATTRIBUTE_NODE) {
3308
0
  attr2 = 1;
3309
0
  attrNode2 = node2;
3310
0
  node2 = node2->parent;
3311
0
    }
3312
0
    if (node1 == node2) {
3313
0
  if (attr1 == attr2) {
3314
      /* not required, but we keep attributes in order */
3315
0
      if (attr1 != 0) {
3316
0
          cur = attrNode2->prev;
3317
0
    while (cur != NULL) {
3318
0
        if (cur == attrNode1)
3319
0
            return (1);
3320
0
        cur = cur->prev;
3321
0
    }
3322
0
    return (-1);
3323
0
      }
3324
0
      return(0);
3325
0
  }
3326
0
  if (attr2 == 1)
3327
0
      return(1);
3328
0
  return(-1);
3329
0
    }
3330
0
    if ((node1->type == XML_NAMESPACE_DECL) ||
3331
0
        (node2->type == XML_NAMESPACE_DECL))
3332
0
  return(1);
3333
0
    if (node1 == node2->prev)
3334
0
  return(1);
3335
0
    if (node1 == node2->next)
3336
0
  return(-1);
3337
3338
    /*
3339
     * Speedup using document order if availble.
3340
     */
3341
0
    if ((node1->type == XML_ELEMENT_NODE) &&
3342
0
  (node2->type == XML_ELEMENT_NODE) &&
3343
0
  (0 > (ptrdiff_t) node1->content) &&
3344
0
  (0 > (ptrdiff_t) node2->content) &&
3345
0
  (node1->doc == node2->doc)) {
3346
0
  ptrdiff_t l1, l2;
3347
3348
0
  l1 = -((ptrdiff_t) node1->content);
3349
0
  l2 = -((ptrdiff_t) node2->content);
3350
0
  if (l1 < l2)
3351
0
      return(1);
3352
0
  if (l1 > l2)
3353
0
      return(-1);
3354
0
    }
3355
3356
    /*
3357
     * compute depth to root
3358
     */
3359
0
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3360
0
  if (cur->parent == node1)
3361
0
      return(1);
3362
0
  depth2++;
3363
0
    }
3364
0
    root = cur;
3365
0
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3366
0
  if (cur->parent == node2)
3367
0
      return(-1);
3368
0
  depth1++;
3369
0
    }
3370
    /*
3371
     * Distinct document (or distinct entities :-( ) case.
3372
     */
3373
0
    if (root != cur) {
3374
0
  return(-2);
3375
0
    }
3376
    /*
3377
     * get the nearest common ancestor.
3378
     */
3379
0
    while (depth1 > depth2) {
3380
0
  depth1--;
3381
0
  node1 = node1->parent;
3382
0
    }
3383
0
    while (depth2 > depth1) {
3384
0
  depth2--;
3385
0
  node2 = node2->parent;
3386
0
    }
3387
0
    while (node1->parent != node2->parent) {
3388
0
  node1 = node1->parent;
3389
0
  node2 = node2->parent;
3390
  /* should not happen but just in case ... */
3391
0
  if ((node1 == NULL) || (node2 == NULL))
3392
0
      return(-2);
3393
0
    }
3394
    /*
3395
     * Find who's first.
3396
     */
3397
0
    if (node1 == node2->prev)
3398
0
  return(1);
3399
0
    if (node1 == node2->next)
3400
0
  return(-1);
3401
    /*
3402
     * Speedup using document order if availble.
3403
     */
3404
0
    if ((node1->type == XML_ELEMENT_NODE) &&
3405
0
  (node2->type == XML_ELEMENT_NODE) &&
3406
0
  (0 > (ptrdiff_t) node1->content) &&
3407
0
  (0 > (ptrdiff_t) node2->content) &&
3408
0
  (node1->doc == node2->doc)) {
3409
0
  ptrdiff_t l1, l2;
3410
3411
0
  l1 = -((ptrdiff_t) node1->content);
3412
0
  l2 = -((ptrdiff_t) node2->content);
3413
0
  if (l1 < l2)
3414
0
      return(1);
3415
0
  if (l1 > l2)
3416
0
      return(-1);
3417
0
    }
3418
3419
0
    for (cur = node1->next;cur != NULL;cur = cur->next)
3420
0
  if (cur == node2)
3421
0
      return(1);
3422
0
    return(-1); /* assume there is no sibling list corruption */
3423
0
}
3424
3425
/**
3426
 * xmlXPathNodeSetSort:
3427
 * @set:  the node set
3428
 *
3429
 * Sort the node set in document order
3430
 */
3431
void
3432
0
xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3433
#ifndef WITH_TIM_SORT
3434
    int i, j, incr, len;
3435
    xmlNodePtr tmp;
3436
#endif
3437
3438
0
    if (set == NULL)
3439
0
  return;
3440
3441
#ifndef WITH_TIM_SORT
3442
    /*
3443
     * Use the old Shell's sort implementation to sort the node-set
3444
     * Timsort ought to be quite faster
3445
     */
3446
    len = set->nodeNr;
3447
    for (incr = len / 2; incr > 0; incr /= 2) {
3448
  for (i = incr; i < len; i++) {
3449
      j = i - incr;
3450
      while (j >= 0) {
3451
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3452
    if (xmlXPathCmpNodesExt(set->nodeTab[j],
3453
      set->nodeTab[j + incr]) == -1)
3454
#else
3455
    if (xmlXPathCmpNodes(set->nodeTab[j],
3456
      set->nodeTab[j + incr]) == -1)
3457
#endif
3458
    {
3459
        tmp = set->nodeTab[j];
3460
        set->nodeTab[j] = set->nodeTab[j + incr];
3461
        set->nodeTab[j + incr] = tmp;
3462
        j -= incr;
3463
    } else
3464
        break;
3465
      }
3466
  }
3467
    }
3468
#else /* WITH_TIM_SORT */
3469
0
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3470
0
#endif /* WITH_TIM_SORT */
3471
0
}
3472
3473
0
#define XML_NODESET_DEFAULT 10
3474
/**
3475
 * xmlXPathNodeSetDupNs:
3476
 * @node:  the parent node of the namespace XPath node
3477
 * @ns:  the libxml namespace declaration node.
3478
 *
3479
 * Namespace node in libxml don't match the XPath semantic. In a node set
3480
 * the namespace nodes are duplicated and the next pointer is set to the
3481
 * parent node in the XPath semantic.
3482
 *
3483
 * Returns the newly created object.
3484
 */
3485
static xmlNodePtr
3486
0
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3487
0
    xmlNsPtr cur;
3488
3489
0
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3490
0
  return(NULL);
3491
0
    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3492
0
  return((xmlNodePtr) ns);
3493
3494
    /*
3495
     * Allocate a new Namespace and fill the fields.
3496
     */
3497
0
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3498
0
    if (cur == NULL) {
3499
0
        xmlXPathErrMemory(NULL, "duplicating namespace\n");
3500
0
  return(NULL);
3501
0
    }
3502
0
    memset(cur, 0, sizeof(xmlNs));
3503
0
    cur->type = XML_NAMESPACE_DECL;
3504
0
    if (ns->href != NULL)
3505
0
  cur->href = xmlStrdup(ns->href);
3506
0
    if (ns->prefix != NULL)
3507
0
  cur->prefix = xmlStrdup(ns->prefix);
3508
0
    cur->next = (xmlNsPtr) node;
3509
0
    return((xmlNodePtr) cur);
3510
0
}
3511
3512
/**
3513
 * xmlXPathNodeSetFreeNs:
3514
 * @ns:  the XPath namespace node found in a nodeset.
3515
 *
3516
 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3517
 * the namespace nodes are duplicated and the next pointer is set to the
3518
 * parent node in the XPath semantic. Check if such a node needs to be freed
3519
 */
3520
void
3521
0
xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3522
0
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3523
0
  return;
3524
3525
0
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3526
0
  if (ns->href != NULL)
3527
0
      xmlFree((xmlChar *)ns->href);
3528
0
  if (ns->prefix != NULL)
3529
0
      xmlFree((xmlChar *)ns->prefix);
3530
0
  xmlFree(ns);
3531
0
    }
3532
0
}
3533
3534
/**
3535
 * xmlXPathNodeSetCreate:
3536
 * @val:  an initial xmlNodePtr, or NULL
3537
 *
3538
 * Create a new xmlNodeSetPtr of type double and of value @val
3539
 *
3540
 * Returns the newly created object.
3541
 */
3542
xmlNodeSetPtr
3543
0
xmlXPathNodeSetCreate(xmlNodePtr val) {
3544
0
    xmlNodeSetPtr ret;
3545
3546
0
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3547
0
    if (ret == NULL) {
3548
0
        xmlXPathErrMemory(NULL, "creating nodeset\n");
3549
0
  return(NULL);
3550
0
    }
3551
0
    memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3552
0
    if (val != NULL) {
3553
0
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3554
0
               sizeof(xmlNodePtr));
3555
0
  if (ret->nodeTab == NULL) {
3556
0
      xmlXPathErrMemory(NULL, "creating nodeset\n");
3557
0
      xmlFree(ret);
3558
0
      return(NULL);
3559
0
  }
3560
0
  memset(ret->nodeTab, 0 ,
3561
0
         XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3562
0
        ret->nodeMax = XML_NODESET_DEFAULT;
3563
0
  if (val->type == XML_NAMESPACE_DECL) {
3564
0
      xmlNsPtr ns = (xmlNsPtr) val;
3565
3566
0
      ret->nodeTab[ret->nodeNr++] =
3567
0
    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3568
0
  } else
3569
0
      ret->nodeTab[ret->nodeNr++] = val;
3570
0
    }
3571
0
    return(ret);
3572
0
}
3573
3574
/**
3575
 * xmlXPathNodeSetCreateSize:
3576
 * @size:  the initial size of the set
3577
 *
3578
 * Create a new xmlNodeSetPtr of type double and of value @val
3579
 *
3580
 * Returns the newly created object.
3581
 */
3582
static xmlNodeSetPtr
3583
0
xmlXPathNodeSetCreateSize(int size) {
3584
0
    xmlNodeSetPtr ret;
3585
3586
0
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3587
0
    if (ret == NULL) {
3588
0
        xmlXPathErrMemory(NULL, "creating nodeset\n");
3589
0
  return(NULL);
3590
0
    }
3591
0
    memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3592
0
    if (size < XML_NODESET_DEFAULT)
3593
0
  size = XML_NODESET_DEFAULT;
3594
0
    ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3595
0
    if (ret->nodeTab == NULL) {
3596
0
  xmlXPathErrMemory(NULL, "creating nodeset\n");
3597
0
  xmlFree(ret);
3598
0
  return(NULL);
3599
0
    }
3600
0
    memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3601
0
    ret->nodeMax = size;
3602
0
    return(ret);
3603
0
}
3604
3605
/**
3606
 * xmlXPathNodeSetContains:
3607
 * @cur:  the node-set
3608
 * @val:  the node
3609
 *
3610
 * checks whether @cur contains @val
3611
 *
3612
 * Returns true (1) if @cur contains @val, false (0) otherwise
3613
 */
3614
int
3615
0
xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3616
0
    int i;
3617
3618
0
    if ((cur == NULL) || (val == NULL)) return(0);
3619
0
    if (val->type == XML_NAMESPACE_DECL) {
3620
0
  for (i = 0; i < cur->nodeNr; i++) {
3621
0
      if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3622
0
    xmlNsPtr ns1, ns2;
3623
3624
0
    ns1 = (xmlNsPtr) val;
3625
0
    ns2 = (xmlNsPtr) cur->nodeTab[i];
3626
0
    if (ns1 == ns2)
3627
0
        return(1);
3628
0
    if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3629
0
              (xmlStrEqual(ns1->prefix, ns2->prefix)))
3630
0
        return(1);
3631
0
      }
3632
0
  }
3633
0
    } else {
3634
0
  for (i = 0; i < cur->nodeNr; i++) {
3635
0
      if (cur->nodeTab[i] == val)
3636
0
    return(1);
3637
0
  }
3638
0
    }
3639
0
    return(0);
3640
0
}
3641
3642
/**
3643
 * xmlXPathNodeSetAddNs:
3644
 * @cur:  the initial node set
3645
 * @node:  the hosting node
3646
 * @ns:  a the namespace node
3647
 *
3648
 * add a new namespace node to an existing NodeSet
3649
 *
3650
 * Returns 0 in case of success and -1 in case of error
3651
 */
3652
int
3653
0
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3654
0
    int i;
3655
3656
3657
0
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3658
0
        (ns->type != XML_NAMESPACE_DECL) ||
3659
0
  (node->type != XML_ELEMENT_NODE))
3660
0
  return(-1);
3661
3662
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3663
    /*
3664
     * prevent duplicates
3665
     */
3666
0
    for (i = 0;i < cur->nodeNr;i++) {
3667
0
        if ((cur->nodeTab[i] != NULL) &&
3668
0
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3669
0
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3670
0
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3671
0
      return(0);
3672
0
    }
3673
3674
    /*
3675
     * grow the nodeTab if needed
3676
     */
3677
0
    if (cur->nodeMax == 0) {
3678
0
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3679
0
               sizeof(xmlNodePtr));
3680
0
  if (cur->nodeTab == NULL) {
3681
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3682
0
      return(-1);
3683
0
  }
3684
0
  memset(cur->nodeTab, 0 ,
3685
0
         XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3686
0
        cur->nodeMax = XML_NODESET_DEFAULT;
3687
0
    } else if (cur->nodeNr == cur->nodeMax) {
3688
0
        xmlNodePtr *temp;
3689
3690
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3691
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3692
0
            return(-1);
3693
0
        }
3694
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3695
0
              sizeof(xmlNodePtr));
3696
0
  if (temp == NULL) {
3697
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3698
0
      return(-1);
3699
0
  }
3700
0
        cur->nodeMax *= 2;
3701
0
  cur->nodeTab = temp;
3702
0
    }
3703
0
    cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3704
0
    return(0);
3705
0
}
3706
3707
/**
3708
 * xmlXPathNodeSetAdd:
3709
 * @cur:  the initial node set
3710
 * @val:  a new xmlNodePtr
3711
 *
3712
 * add a new xmlNodePtr to an existing NodeSet
3713
 *
3714
 * Returns 0 in case of success, and -1 in case of error
3715
 */
3716
int
3717
0
xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3718
0
    int i;
3719
3720
0
    if ((cur == NULL) || (val == NULL)) return(-1);
3721
3722
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3723
    /*
3724
     * prevent duplicates
3725
     */
3726
0
    for (i = 0;i < cur->nodeNr;i++)
3727
0
        if (cur->nodeTab[i] == val) return(0);
3728
3729
    /*
3730
     * grow the nodeTab if needed
3731
     */
3732
0
    if (cur->nodeMax == 0) {
3733
0
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3734
0
               sizeof(xmlNodePtr));
3735
0
  if (cur->nodeTab == NULL) {
3736
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3737
0
      return(-1);
3738
0
  }
3739
0
  memset(cur->nodeTab, 0 ,
3740
0
         XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3741
0
        cur->nodeMax = XML_NODESET_DEFAULT;
3742
0
    } else if (cur->nodeNr == cur->nodeMax) {
3743
0
        xmlNodePtr *temp;
3744
3745
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3746
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3747
0
            return(-1);
3748
0
        }
3749
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3750
0
              sizeof(xmlNodePtr));
3751
0
  if (temp == NULL) {
3752
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3753
0
      return(-1);
3754
0
  }
3755
0
        cur->nodeMax *= 2;
3756
0
  cur->nodeTab = temp;
3757
0
    }
3758
0
    if (val->type == XML_NAMESPACE_DECL) {
3759
0
  xmlNsPtr ns = (xmlNsPtr) val;
3760
3761
0
  cur->nodeTab[cur->nodeNr++] =
3762
0
      xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3763
0
    } else
3764
0
  cur->nodeTab[cur->nodeNr++] = val;
3765
0
    return(0);
3766
0
}
3767
3768
/**
3769
 * xmlXPathNodeSetAddUnique:
3770
 * @cur:  the initial node set
3771
 * @val:  a new xmlNodePtr
3772
 *
3773
 * add a new xmlNodePtr to an existing NodeSet, optimized version
3774
 * when we are sure the node is not already in the set.
3775
 *
3776
 * Returns 0 in case of success and -1 in case of failure
3777
 */
3778
int
3779
0
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3780
0
    if ((cur == NULL) || (val == NULL)) return(-1);
3781
3782
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3783
    /*
3784
     * grow the nodeTab if needed
3785
     */
3786
0
    if (cur->nodeMax == 0) {
3787
0
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3788
0
               sizeof(xmlNodePtr));
3789
0
  if (cur->nodeTab == NULL) {
3790
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3791
0
      return(-1);
3792
0
  }
3793
0
  memset(cur->nodeTab, 0 ,
3794
0
         XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3795
0
        cur->nodeMax = XML_NODESET_DEFAULT;
3796
0
    } else if (cur->nodeNr == cur->nodeMax) {
3797
0
        xmlNodePtr *temp;
3798
3799
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3800
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3801
0
            return(-1);
3802
0
        }
3803
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3804
0
              sizeof(xmlNodePtr));
3805
0
  if (temp == NULL) {
3806
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3807
0
      return(-1);
3808
0
  }
3809
0
  cur->nodeTab = temp;
3810
0
        cur->nodeMax *= 2;
3811
0
    }
3812
0
    if (val->type == XML_NAMESPACE_DECL) {
3813
0
  xmlNsPtr ns = (xmlNsPtr) val;
3814
3815
0
  cur->nodeTab[cur->nodeNr++] =
3816
0
      xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3817
0
    } else
3818
0
  cur->nodeTab[cur->nodeNr++] = val;
3819
0
    return(0);
3820
0
}
3821
3822
/**
3823
 * xmlXPathNodeSetMerge:
3824
 * @val1:  the first NodeSet or NULL
3825
 * @val2:  the second NodeSet
3826
 *
3827
 * Merges two nodesets, all nodes from @val2 are added to @val1
3828
 * if @val1 is NULL, a new set is created and copied from @val2
3829
 *
3830
 * Returns @val1 once extended or NULL in case of error.
3831
 */
3832
xmlNodeSetPtr
3833
0
xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3834
0
    int i, j, initNr, skip;
3835
0
    xmlNodePtr n1, n2;
3836
3837
0
    if (val2 == NULL) return(val1);
3838
0
    if (val1 == NULL) {
3839
0
  val1 = xmlXPathNodeSetCreate(NULL);
3840
0
    if (val1 == NULL)
3841
0
        return (NULL);
3842
#if 0
3843
  /*
3844
  * TODO: The optimization won't work in every case, since
3845
  *  those nasty namespace nodes need to be added with
3846
  *  xmlXPathNodeSetDupNs() to the set; thus a pure
3847
  *  memcpy is not possible.
3848
  *  If there was a flag on the nodesetval, indicating that
3849
  *  some temporary nodes are in, that would be helpfull.
3850
  */
3851
  /*
3852
  * Optimization: Create an equally sized node-set
3853
  * and memcpy the content.
3854
  */
3855
  val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3856
  if (val1 == NULL)
3857
      return(NULL);
3858
  if (val2->nodeNr != 0) {
3859
      if (val2->nodeNr == 1)
3860
    *(val1->nodeTab) = *(val2->nodeTab);
3861
      else {
3862
    memcpy(val1->nodeTab, val2->nodeTab,
3863
        val2->nodeNr * sizeof(xmlNodePtr));
3864
      }
3865
      val1->nodeNr = val2->nodeNr;
3866
  }
3867
  return(val1);
3868
#endif
3869
0
    }
3870
3871
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3872
0
    initNr = val1->nodeNr;
3873
3874
0
    for (i = 0;i < val2->nodeNr;i++) {
3875
0
  n2 = val2->nodeTab[i];
3876
  /*
3877
   * check against duplicates
3878
   */
3879
0
  skip = 0;
3880
0
  for (j = 0; j < initNr; j++) {
3881
0
      n1 = val1->nodeTab[j];
3882
0
      if (n1 == n2) {
3883
0
    skip = 1;
3884
0
    break;
3885
0
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
3886
0
           (n2->type == XML_NAMESPACE_DECL)) {
3887
0
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3888
0
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3889
0
      ((xmlNsPtr) n2)->prefix)))
3890
0
    {
3891
0
        skip = 1;
3892
0
        break;
3893
0
    }
3894
0
      }
3895
0
  }
3896
0
  if (skip)
3897
0
      continue;
3898
3899
  /*
3900
   * grow the nodeTab if needed
3901
   */
3902
0
  if (val1->nodeMax == 0) {
3903
0
      val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3904
0
                sizeof(xmlNodePtr));
3905
0
      if (val1->nodeTab == NULL) {
3906
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3907
0
    return(NULL);
3908
0
      }
3909
0
      memset(val1->nodeTab, 0 ,
3910
0
       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3911
0
      val1->nodeMax = XML_NODESET_DEFAULT;
3912
0
  } else if (val1->nodeNr == val1->nodeMax) {
3913
0
      xmlNodePtr *temp;
3914
3915
0
            if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3916
0
                xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3917
0
                return(NULL);
3918
0
            }
3919
0
      temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3920
0
               sizeof(xmlNodePtr));
3921
0
      if (temp == NULL) {
3922
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3923
0
    return(NULL);
3924
0
      }
3925
0
      val1->nodeTab = temp;
3926
0
      val1->nodeMax *= 2;
3927
0
  }
3928
0
  if (n2->type == XML_NAMESPACE_DECL) {
3929
0
      xmlNsPtr ns = (xmlNsPtr) n2;
3930
3931
0
      val1->nodeTab[val1->nodeNr++] =
3932
0
    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3933
0
  } else
3934
0
      val1->nodeTab[val1->nodeNr++] = n2;
3935
0
    }
3936
3937
0
    return(val1);
3938
0
}
3939
3940
3941
/**
3942
 * xmlXPathNodeSetMergeAndClear:
3943
 * @set1:  the first NodeSet or NULL
3944
 * @set2:  the second NodeSet
3945
 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3946
 *
3947
 * Merges two nodesets, all nodes from @set2 are added to @set1
3948
 * if @set1 is NULL, a new set is created and copied from @set2.
3949
 * Checks for duplicate nodes. Clears set2.
3950
 *
3951
 * Returns @set1 once extended or NULL in case of error.
3952
 */
3953
static xmlNodeSetPtr
3954
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3955
           int hasNullEntries)
3956
0
{
3957
0
    if ((set1 == NULL) && (hasNullEntries == 0)) {
3958
  /*
3959
  * Note that doing a memcpy of the list, namespace nodes are
3960
  * just assigned to set1, since set2 is cleared anyway.
3961
  */
3962
0
  set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3963
0
  if (set1 == NULL)
3964
0
      return(NULL);
3965
0
  if (set2->nodeNr != 0) {
3966
0
      memcpy(set1->nodeTab, set2->nodeTab,
3967
0
    set2->nodeNr * sizeof(xmlNodePtr));
3968
0
      set1->nodeNr = set2->nodeNr;
3969
0
  }
3970
0
    } else {
3971
0
  int i, j, initNbSet1;
3972
0
  xmlNodePtr n1, n2;
3973
3974
0
  if (set1 == NULL)
3975
0
            set1 = xmlXPathNodeSetCreate(NULL);
3976
0
        if (set1 == NULL)
3977
0
            return (NULL);
3978
3979
0
  initNbSet1 = set1->nodeNr;
3980
0
  for (i = 0;i < set2->nodeNr;i++) {
3981
0
      n2 = set2->nodeTab[i];
3982
      /*
3983
      * Skip NULLed entries.
3984
      */
3985
0
      if (n2 == NULL)
3986
0
    continue;
3987
      /*
3988
      * Skip duplicates.
3989
      */
3990
0
      for (j = 0; j < initNbSet1; j++) {
3991
0
    n1 = set1->nodeTab[j];
3992
0
    if (n1 == n2) {
3993
0
        goto skip_node;
3994
0
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3995
0
        (n2->type == XML_NAMESPACE_DECL))
3996
0
    {
3997
0
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3998
0
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3999
0
      ((xmlNsPtr) n2)->prefix)))
4000
0
        {
4001
      /*
4002
      * Free the namespace node.
4003
      */
4004
0
      set2->nodeTab[i] = NULL;
4005
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
4006
0
      goto skip_node;
4007
0
        }
4008
0
    }
4009
0
      }
4010
      /*
4011
      * grow the nodeTab if needed
4012
      */
4013
0
      if (set1->nodeMax == 0) {
4014
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4015
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4016
0
    if (set1->nodeTab == NULL) {
4017
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4018
0
        return(NULL);
4019
0
    }
4020
0
    memset(set1->nodeTab, 0,
4021
0
        XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4022
0
    set1->nodeMax = XML_NODESET_DEFAULT;
4023
0
      } else if (set1->nodeNr >= set1->nodeMax) {
4024
0
    xmlNodePtr *temp;
4025
4026
0
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4027
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4028
0
                    return(NULL);
4029
0
                }
4030
0
    temp = (xmlNodePtr *) xmlRealloc(
4031
0
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4032
0
    if (temp == NULL) {
4033
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4034
0
        return(NULL);
4035
0
    }
4036
0
    set1->nodeTab = temp;
4037
0
    set1->nodeMax *= 2;
4038
0
      }
4039
0
      set1->nodeTab[set1->nodeNr++] = n2;
4040
0
skip_node:
4041
0
      {}
4042
0
  }
4043
0
    }
4044
0
    set2->nodeNr = 0;
4045
0
    return(set1);
4046
0
}
4047
4048
/**
4049
 * xmlXPathNodeSetMergeAndClearNoDupls:
4050
 * @set1:  the first NodeSet or NULL
4051
 * @set2:  the second NodeSet
4052
 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4053
 *
4054
 * Merges two nodesets, all nodes from @set2 are added to @set1
4055
 * if @set1 is NULL, a new set is created and copied from @set2.
4056
 * Doesn't chack for duplicate nodes. Clears set2.
4057
 *
4058
 * Returns @set1 once extended or NULL in case of error.
4059
 */
4060
static xmlNodeSetPtr
4061
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4062
            int hasNullEntries)
4063
0
{
4064
0
    if (set2 == NULL)
4065
0
  return(set1);
4066
0
    if ((set1 == NULL) && (hasNullEntries == 0)) {
4067
  /*
4068
  * Note that doing a memcpy of the list, namespace nodes are
4069
  * just assigned to set1, since set2 is cleared anyway.
4070
  */
4071
0
  set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4072
0
  if (set1 == NULL)
4073
0
      return(NULL);
4074
0
  if (set2->nodeNr != 0) {
4075
0
      memcpy(set1->nodeTab, set2->nodeTab,
4076
0
    set2->nodeNr * sizeof(xmlNodePtr));
4077
0
      set1->nodeNr = set2->nodeNr;
4078
0
  }
4079
0
    } else {
4080
0
  int i;
4081
0
  xmlNodePtr n2;
4082
4083
0
  if (set1 == NULL)
4084
0
      set1 = xmlXPathNodeSetCreate(NULL);
4085
0
        if (set1 == NULL)
4086
0
            return (NULL);
4087
4088
0
  for (i = 0;i < set2->nodeNr;i++) {
4089
0
      n2 = set2->nodeTab[i];
4090
      /*
4091
      * Skip NULLed entries.
4092
      */
4093
0
      if (n2 == NULL)
4094
0
    continue;
4095
0
      if (set1->nodeMax == 0) {
4096
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4097
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4098
0
    if (set1->nodeTab == NULL) {
4099
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4100
0
        return(NULL);
4101
0
    }
4102
0
    memset(set1->nodeTab, 0,
4103
0
        XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4104
0
    set1->nodeMax = XML_NODESET_DEFAULT;
4105
0
      } else if (set1->nodeNr >= set1->nodeMax) {
4106
0
    xmlNodePtr *temp;
4107
4108
0
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4109
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4110
0
                    return(NULL);
4111
0
                }
4112
0
    temp = (xmlNodePtr *) xmlRealloc(
4113
0
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4114
0
    if (temp == NULL) {
4115
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4116
0
        return(NULL);
4117
0
    }
4118
0
    set1->nodeTab = temp;
4119
0
    set1->nodeMax *= 2;
4120
0
      }
4121
0
      set1->nodeTab[set1->nodeNr++] = n2;
4122
0
  }
4123
0
    }
4124
0
    set2->nodeNr = 0;
4125
0
    return(set1);
4126
0
}
4127
4128
/**
4129
 * xmlXPathNodeSetDel:
4130
 * @cur:  the initial node set
4131
 * @val:  an xmlNodePtr
4132
 *
4133
 * Removes an xmlNodePtr from an existing NodeSet
4134
 */
4135
void
4136
0
xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4137
0
    int i;
4138
4139
0
    if (cur == NULL) return;
4140
0
    if (val == NULL) return;
4141
4142
    /*
4143
     * find node in nodeTab
4144
     */
4145
0
    for (i = 0;i < cur->nodeNr;i++)
4146
0
        if (cur->nodeTab[i] == val) break;
4147
4148
0
    if (i >= cur->nodeNr) { /* not found */
4149
#ifdef DEBUG
4150
        xmlGenericError(xmlGenericErrorContext,
4151
          "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4152
    val->name);
4153
#endif
4154
0
        return;
4155
0
    }
4156
0
    if ((cur->nodeTab[i] != NULL) &&
4157
0
  (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4158
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4159
0
    cur->nodeNr--;
4160
0
    for (;i < cur->nodeNr;i++)
4161
0
        cur->nodeTab[i] = cur->nodeTab[i + 1];
4162
0
    cur->nodeTab[cur->nodeNr] = NULL;
4163
0
}
4164
4165
/**
4166
 * xmlXPathNodeSetRemove:
4167
 * @cur:  the initial node set
4168
 * @val:  the index to remove
4169
 *
4170
 * Removes an entry from an existing NodeSet list.
4171
 */
4172
void
4173
0
xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4174
0
    if (cur == NULL) return;
4175
0
    if (val >= cur->nodeNr) return;
4176
0
    if ((cur->nodeTab[val] != NULL) &&
4177
0
  (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4178
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4179
0
    cur->nodeNr--;
4180
0
    for (;val < cur->nodeNr;val++)
4181
0
        cur->nodeTab[val] = cur->nodeTab[val + 1];
4182
0
    cur->nodeTab[cur->nodeNr] = NULL;
4183
0
}
4184
4185
/**
4186
 * xmlXPathFreeNodeSet:
4187
 * @obj:  the xmlNodeSetPtr to free
4188
 *
4189
 * Free the NodeSet compound (not the actual nodes !).
4190
 */
4191
void
4192
0
xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4193
0
    if (obj == NULL) return;
4194
0
    if (obj->nodeTab != NULL) {
4195
0
  int i;
4196
4197
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4198
0
  for (i = 0;i < obj->nodeNr;i++)
4199
0
      if ((obj->nodeTab[i] != NULL) &&
4200
0
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4201
0
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4202
0
  xmlFree(obj->nodeTab);
4203
0
    }
4204
0
    xmlFree(obj);
4205
0
}
4206
4207
/**
4208
 * xmlXPathNodeSetClearFromPos:
4209
 * @set: the node set to be cleared
4210
 * @pos: the start position to clear from
4211
 *
4212
 * Clears the list from temporary XPath objects (e.g. namespace nodes
4213
 * are feed) starting with the entry at @pos, but does *not* free the list
4214
 * itself. Sets the length of the list to @pos.
4215
 */
4216
static void
4217
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4218
0
{
4219
0
    if ((set == NULL) || (pos >= set->nodeNr))
4220
0
  return;
4221
0
    else if ((hasNsNodes)) {
4222
0
  int i;
4223
0
  xmlNodePtr node;
4224
4225
0
  for (i = pos; i < set->nodeNr; i++) {
4226
0
      node = set->nodeTab[i];
4227
0
      if ((node != NULL) &&
4228
0
    (node->type == XML_NAMESPACE_DECL))
4229
0
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4230
0
  }
4231
0
    }
4232
0
    set->nodeNr = pos;
4233
0
}
4234
4235
/**
4236
 * xmlXPathNodeSetClear:
4237
 * @set:  the node set to clear
4238
 *
4239
 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4240
 * are feed), but does *not* free the list itself. Sets the length of the
4241
 * list to 0.
4242
 */
4243
static void
4244
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4245
0
{
4246
0
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4247
0
}
4248
4249
/**
4250
 * xmlXPathNodeSetKeepLast:
4251
 * @set: the node set to be cleared
4252
 *
4253
 * Move the last node to the first position and clear temporary XPath objects
4254
 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4255
 * to 1.
4256
 */
4257
static void
4258
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4259
0
{
4260
0
    int i;
4261
0
    xmlNodePtr node;
4262
4263
0
    if ((set == NULL) || (set->nodeNr <= 1))
4264
0
  return;
4265
0
    for (i = 0; i < set->nodeNr - 1; i++) {
4266
0
        node = set->nodeTab[i];
4267
0
        if ((node != NULL) &&
4268
0
            (node->type == XML_NAMESPACE_DECL))
4269
0
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4270
0
    }
4271
0
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4272
0
    set->nodeNr = 1;
4273
0
}
4274
4275
/**
4276
 * xmlXPathFreeValueTree:
4277
 * @obj:  the xmlNodeSetPtr to free
4278
 *
4279
 * Free the NodeSet compound and the actual tree, this is different
4280
 * from xmlXPathFreeNodeSet()
4281
 */
4282
static void
4283
0
xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4284
0
    int i;
4285
4286
0
    if (obj == NULL) return;
4287
4288
0
    if (obj->nodeTab != NULL) {
4289
0
  for (i = 0;i < obj->nodeNr;i++) {
4290
0
      if (obj->nodeTab[i] != NULL) {
4291
0
    if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4292
0
        xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4293
0
    } else {
4294
0
        xmlFreeNodeList(obj->nodeTab[i]);
4295
0
    }
4296
0
      }
4297
0
  }
4298
0
  xmlFree(obj->nodeTab);
4299
0
    }
4300
0
    xmlFree(obj);
4301
0
}
4302
4303
#if defined(DEBUG) || defined(DEBUG_STEP)
4304
/**
4305
 * xmlGenericErrorContextNodeSet:
4306
 * @output:  a FILE * for the output
4307
 * @obj:  the xmlNodeSetPtr to display
4308
 *
4309
 * Quick display of a NodeSet
4310
 */
4311
void
4312
xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4313
    int i;
4314
4315
    if (output == NULL) output = xmlGenericErrorContext;
4316
    if (obj == NULL)  {
4317
        fprintf(output, "NodeSet == NULL !\n");
4318
  return;
4319
    }
4320
    if (obj->nodeNr == 0) {
4321
        fprintf(output, "NodeSet is empty\n");
4322
  return;
4323
    }
4324
    if (obj->nodeTab == NULL) {
4325
  fprintf(output, " nodeTab == NULL !\n");
4326
  return;
4327
    }
4328
    for (i = 0; i < obj->nodeNr; i++) {
4329
        if (obj->nodeTab[i] == NULL) {
4330
      fprintf(output, " NULL !\n");
4331
      return;
4332
        }
4333
  if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4334
      (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4335
      fprintf(output, " /");
4336
  else if (obj->nodeTab[i]->name == NULL)
4337
      fprintf(output, " noname!");
4338
  else fprintf(output, " %s", obj->nodeTab[i]->name);
4339
    }
4340
    fprintf(output, "\n");
4341
}
4342
#endif
4343
4344
/**
4345
 * xmlXPathNewNodeSet:
4346
 * @val:  the NodePtr value
4347
 *
4348
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4349
 * it with the single Node @val
4350
 *
4351
 * Returns the newly created object.
4352
 */
4353
xmlXPathObjectPtr
4354
0
xmlXPathNewNodeSet(xmlNodePtr val) {
4355
0
    xmlXPathObjectPtr ret;
4356
4357
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4358
0
    if (ret == NULL) {
4359
0
        xmlXPathErrMemory(NULL, "creating nodeset\n");
4360
0
  return(NULL);
4361
0
    }
4362
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4363
0
    ret->type = XPATH_NODESET;
4364
0
    ret->boolval = 0;
4365
0
    ret->nodesetval = xmlXPathNodeSetCreate(val);
4366
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4367
#ifdef XP_DEBUG_OBJ_USAGE
4368
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4369
#endif
4370
0
    return(ret);
4371
0
}
4372
4373
/**
4374
 * xmlXPathNewValueTree:
4375
 * @val:  the NodePtr value
4376
 *
4377
 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4378
 * it with the tree root @val
4379
 *
4380
 * Returns the newly created object.
4381
 */
4382
xmlXPathObjectPtr
4383
0
xmlXPathNewValueTree(xmlNodePtr val) {
4384
0
    xmlXPathObjectPtr ret;
4385
4386
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4387
0
    if (ret == NULL) {
4388
0
        xmlXPathErrMemory(NULL, "creating result value tree\n");
4389
0
  return(NULL);
4390
0
    }
4391
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4392
0
    ret->type = XPATH_XSLT_TREE;
4393
0
    ret->boolval = 1;
4394
0
    ret->user = (void *) val;
4395
0
    ret->nodesetval = xmlXPathNodeSetCreate(val);
4396
#ifdef XP_DEBUG_OBJ_USAGE
4397
    xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4398
#endif
4399
0
    return(ret);
4400
0
}
4401
4402
/**
4403
 * xmlXPathNewNodeSetList:
4404
 * @val:  an existing NodeSet
4405
 *
4406
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4407
 * it with the Nodeset @val
4408
 *
4409
 * Returns the newly created object.
4410
 */
4411
xmlXPathObjectPtr
4412
xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4413
0
{
4414
0
    xmlXPathObjectPtr ret;
4415
0
    int i;
4416
4417
0
    if (val == NULL)
4418
0
        ret = NULL;
4419
0
    else if (val->nodeTab == NULL)
4420
0
        ret = xmlXPathNewNodeSet(NULL);
4421
0
    else {
4422
0
        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4423
0
        if (ret) {
4424
0
            for (i = 1; i < val->nodeNr; ++i) {
4425
0
                if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4426
0
        < 0) break;
4427
0
      }
4428
0
  }
4429
0
    }
4430
4431
0
    return (ret);
4432
0
}
4433
4434
/**
4435
 * xmlXPathWrapNodeSet:
4436
 * @val:  the NodePtr value
4437
 *
4438
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4439
 *
4440
 * Returns the newly created object.
4441
 */
4442
xmlXPathObjectPtr
4443
0
xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4444
0
    xmlXPathObjectPtr ret;
4445
4446
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4447
0
    if (ret == NULL) {
4448
0
        xmlXPathErrMemory(NULL, "creating node set object\n");
4449
0
  return(NULL);
4450
0
    }
4451
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4452
0
    ret->type = XPATH_NODESET;
4453
0
    ret->nodesetval = val;
4454
#ifdef XP_DEBUG_OBJ_USAGE
4455
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4456
#endif
4457
0
    return(ret);
4458
0
}
4459
4460
/**
4461
 * xmlXPathFreeNodeSetList:
4462
 * @obj:  an existing NodeSetList object
4463
 *
4464
 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4465
 * the list contrary to xmlXPathFreeObject().
4466
 */
4467
void
4468
0
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4469
0
    if (obj == NULL) return;
4470
#ifdef XP_DEBUG_OBJ_USAGE
4471
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
4472
#endif
4473
0
    xmlFree(obj);
4474
0
}
4475
4476
/**
4477
 * xmlXPathDifference:
4478
 * @nodes1:  a node-set
4479
 * @nodes2:  a node-set
4480
 *
4481
 * Implements the EXSLT - Sets difference() function:
4482
 *    node-set set:difference (node-set, node-set)
4483
 *
4484
 * Returns the difference between the two node sets, or nodes1 if
4485
 *         nodes2 is empty
4486
 */
4487
xmlNodeSetPtr
4488
0
xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4489
0
    xmlNodeSetPtr ret;
4490
0
    int i, l1;
4491
0
    xmlNodePtr cur;
4492
4493
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4494
0
  return(nodes1);
4495
4496
0
    ret = xmlXPathNodeSetCreate(NULL);
4497
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4498
0
  return(ret);
4499
4500
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
4501
4502
0
    for (i = 0; i < l1; i++) {
4503
0
  cur = xmlXPathNodeSetItem(nodes1, i);
4504
0
  if (!xmlXPathNodeSetContains(nodes2, cur)) {
4505
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4506
0
          break;
4507
0
  }
4508
0
    }
4509
0
    return(ret);
4510
0
}
4511
4512
/**
4513
 * xmlXPathIntersection:
4514
 * @nodes1:  a node-set
4515
 * @nodes2:  a node-set
4516
 *
4517
 * Implements the EXSLT - Sets intersection() function:
4518
 *    node-set set:intersection (node-set, node-set)
4519
 *
4520
 * Returns a node set comprising the nodes that are within both the
4521
 *         node sets passed as arguments
4522
 */
4523
xmlNodeSetPtr
4524
0
xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4525
0
    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4526
0
    int i, l1;
4527
0
    xmlNodePtr cur;
4528
4529
0
    if (ret == NULL)
4530
0
        return(ret);
4531
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4532
0
  return(ret);
4533
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4534
0
  return(ret);
4535
4536
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
4537
4538
0
    for (i = 0; i < l1; i++) {
4539
0
  cur = xmlXPathNodeSetItem(nodes1, i);
4540
0
  if (xmlXPathNodeSetContains(nodes2, cur)) {
4541
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4542
0
          break;
4543
0
  }
4544
0
    }
4545
0
    return(ret);
4546
0
}
4547
4548
/**
4549
 * xmlXPathDistinctSorted:
4550
 * @nodes:  a node-set, sorted by document order
4551
 *
4552
 * Implements the EXSLT - Sets distinct() function:
4553
 *    node-set set:distinct (node-set)
4554
 *
4555
 * Returns a subset of the nodes contained in @nodes, or @nodes if
4556
 *         it is empty
4557
 */
4558
xmlNodeSetPtr
4559
0
xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4560
0
    xmlNodeSetPtr ret;
4561
0
    xmlHashTablePtr hash;
4562
0
    int i, l;
4563
0
    xmlChar * strval;
4564
0
    xmlNodePtr cur;
4565
4566
0
    if (xmlXPathNodeSetIsEmpty(nodes))
4567
0
  return(nodes);
4568
4569
0
    ret = xmlXPathNodeSetCreate(NULL);
4570
0
    if (ret == NULL)
4571
0
        return(ret);
4572
0
    l = xmlXPathNodeSetGetLength(nodes);
4573
0
    hash = xmlHashCreate (l);
4574
0
    for (i = 0; i < l; i++) {
4575
0
  cur = xmlXPathNodeSetItem(nodes, i);
4576
0
  strval = xmlXPathCastNodeToString(cur);
4577
0
  if (xmlHashLookup(hash, strval) == NULL) {
4578
0
      xmlHashAddEntry(hash, strval, strval);
4579
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4580
0
          break;
4581
0
  } else {
4582
0
      xmlFree(strval);
4583
0
  }
4584
0
    }
4585
0
    xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4586
0
    return(ret);
4587
0
}
4588
4589
/**
4590
 * xmlXPathDistinct:
4591
 * @nodes:  a node-set
4592
 *
4593
 * Implements the EXSLT - Sets distinct() function:
4594
 *    node-set set:distinct (node-set)
4595
 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4596
 * is called with the sorted node-set
4597
 *
4598
 * Returns a subset of the nodes contained in @nodes, or @nodes if
4599
 *         it is empty
4600
 */
4601
xmlNodeSetPtr
4602
0
xmlXPathDistinct (xmlNodeSetPtr nodes) {
4603
0
    if (xmlXPathNodeSetIsEmpty(nodes))
4604
0
  return(nodes);
4605
4606
0
    xmlXPathNodeSetSort(nodes);
4607
0
    return(xmlXPathDistinctSorted(nodes));
4608
0
}
4609
4610
/**
4611
 * xmlXPathHasSameNodes:
4612
 * @nodes1:  a node-set
4613
 * @nodes2:  a node-set
4614
 *
4615
 * Implements the EXSLT - Sets has-same-nodes function:
4616
 *    boolean set:has-same-node(node-set, node-set)
4617
 *
4618
 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4619
 *         otherwise
4620
 */
4621
int
4622
0
xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4623
0
    int i, l;
4624
0
    xmlNodePtr cur;
4625
4626
0
    if (xmlXPathNodeSetIsEmpty(nodes1) ||
4627
0
  xmlXPathNodeSetIsEmpty(nodes2))
4628
0
  return(0);
4629
4630
0
    l = xmlXPathNodeSetGetLength(nodes1);
4631
0
    for (i = 0; i < l; i++) {
4632
0
  cur = xmlXPathNodeSetItem(nodes1, i);
4633
0
  if (xmlXPathNodeSetContains(nodes2, cur))
4634
0
      return(1);
4635
0
    }
4636
0
    return(0);
4637
0
}
4638
4639
/**
4640
 * xmlXPathNodeLeadingSorted:
4641
 * @nodes: a node-set, sorted by document order
4642
 * @node: a node
4643
 *
4644
 * Implements the EXSLT - Sets leading() function:
4645
 *    node-set set:leading (node-set, node-set)
4646
 *
4647
 * Returns the nodes in @nodes that precede @node in document order,
4648
 *         @nodes if @node is NULL or an empty node-set if @nodes
4649
 *         doesn't contain @node
4650
 */
4651
xmlNodeSetPtr
4652
0
xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4653
0
    int i, l;
4654
0
    xmlNodePtr cur;
4655
0
    xmlNodeSetPtr ret;
4656
4657
0
    if (node == NULL)
4658
0
  return(nodes);
4659
4660
0
    ret = xmlXPathNodeSetCreate(NULL);
4661
0
    if (ret == NULL)
4662
0
        return(ret);
4663
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4664
0
  (!xmlXPathNodeSetContains(nodes, node)))
4665
0
  return(ret);
4666
4667
0
    l = xmlXPathNodeSetGetLength(nodes);
4668
0
    for (i = 0; i < l; i++) {
4669
0
  cur = xmlXPathNodeSetItem(nodes, i);
4670
0
  if (cur == node)
4671
0
      break;
4672
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4673
0
      break;
4674
0
    }
4675
0
    return(ret);
4676
0
}
4677
4678
/**
4679
 * xmlXPathNodeLeading:
4680
 * @nodes:  a node-set
4681
 * @node:  a node
4682
 *
4683
 * Implements the EXSLT - Sets leading() function:
4684
 *    node-set set:leading (node-set, node-set)
4685
 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4686
 * is called.
4687
 *
4688
 * Returns the nodes in @nodes that precede @node in document order,
4689
 *         @nodes if @node is NULL or an empty node-set if @nodes
4690
 *         doesn't contain @node
4691
 */
4692
xmlNodeSetPtr
4693
0
xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4694
0
    xmlXPathNodeSetSort(nodes);
4695
0
    return(xmlXPathNodeLeadingSorted(nodes, node));
4696
0
}
4697
4698
/**
4699
 * xmlXPathLeadingSorted:
4700
 * @nodes1:  a node-set, sorted by document order
4701
 * @nodes2:  a node-set, sorted by document order
4702
 *
4703
 * Implements the EXSLT - Sets leading() function:
4704
 *    node-set set:leading (node-set, node-set)
4705
 *
4706
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4707
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4708
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4709
 */
4710
xmlNodeSetPtr
4711
0
xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4712
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4713
0
  return(nodes1);
4714
0
    return(xmlXPathNodeLeadingSorted(nodes1,
4715
0
             xmlXPathNodeSetItem(nodes2, 1)));
4716
0
}
4717
4718
/**
4719
 * xmlXPathLeading:
4720
 * @nodes1:  a node-set
4721
 * @nodes2:  a node-set
4722
 *
4723
 * Implements the EXSLT - Sets leading() function:
4724
 *    node-set set:leading (node-set, node-set)
4725
 * @nodes1 and @nodes2 are sorted by document order, then
4726
 * #exslSetsLeadingSorted is called.
4727
 *
4728
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4729
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4730
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4731
 */
4732
xmlNodeSetPtr
4733
0
xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4734
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4735
0
  return(nodes1);
4736
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4737
0
  return(xmlXPathNodeSetCreate(NULL));
4738
0
    xmlXPathNodeSetSort(nodes1);
4739
0
    xmlXPathNodeSetSort(nodes2);
4740
0
    return(xmlXPathNodeLeadingSorted(nodes1,
4741
0
             xmlXPathNodeSetItem(nodes2, 1)));
4742
0
}
4743
4744
/**
4745
 * xmlXPathNodeTrailingSorted:
4746
 * @nodes: a node-set, sorted by document order
4747
 * @node: a node
4748
 *
4749
 * Implements the EXSLT - Sets trailing() function:
4750
 *    node-set set:trailing (node-set, node-set)
4751
 *
4752
 * Returns the nodes in @nodes that follow @node in document order,
4753
 *         @nodes if @node is NULL or an empty node-set if @nodes
4754
 *         doesn't contain @node
4755
 */
4756
xmlNodeSetPtr
4757
0
xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4758
0
    int i, l;
4759
0
    xmlNodePtr cur;
4760
0
    xmlNodeSetPtr ret;
4761
4762
0
    if (node == NULL)
4763
0
  return(nodes);
4764
4765
0
    ret = xmlXPathNodeSetCreate(NULL);
4766
0
    if (ret == NULL)
4767
0
        return(ret);
4768
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4769
0
  (!xmlXPathNodeSetContains(nodes, node)))
4770
0
  return(ret);
4771
4772
0
    l = xmlXPathNodeSetGetLength(nodes);
4773
0
    for (i = l - 1; i >= 0; i--) {
4774
0
  cur = xmlXPathNodeSetItem(nodes, i);
4775
0
  if (cur == node)
4776
0
      break;
4777
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4778
0
      break;
4779
0
    }
4780
0
    xmlXPathNodeSetSort(ret); /* bug 413451 */
4781
0
    return(ret);
4782
0
}
4783
4784
/**
4785
 * xmlXPathNodeTrailing:
4786
 * @nodes:  a node-set
4787
 * @node:  a node
4788
 *
4789
 * Implements the EXSLT - Sets trailing() function:
4790
 *    node-set set:trailing (node-set, node-set)
4791
 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4792
 * is called.
4793
 *
4794
 * Returns the nodes in @nodes that follow @node in document order,
4795
 *         @nodes if @node is NULL or an empty node-set if @nodes
4796
 *         doesn't contain @node
4797
 */
4798
xmlNodeSetPtr
4799
0
xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4800
0
    xmlXPathNodeSetSort(nodes);
4801
0
    return(xmlXPathNodeTrailingSorted(nodes, node));
4802
0
}
4803
4804
/**
4805
 * xmlXPathTrailingSorted:
4806
 * @nodes1:  a node-set, sorted by document order
4807
 * @nodes2:  a node-set, sorted by document order
4808
 *
4809
 * Implements the EXSLT - Sets trailing() function:
4810
 *    node-set set:trailing (node-set, node-set)
4811
 *
4812
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4813
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4814
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4815
 */
4816
xmlNodeSetPtr
4817
0
xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4818
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4819
0
  return(nodes1);
4820
0
    return(xmlXPathNodeTrailingSorted(nodes1,
4821
0
              xmlXPathNodeSetItem(nodes2, 0)));
4822
0
}
4823
4824
/**
4825
 * xmlXPathTrailing:
4826
 * @nodes1:  a node-set
4827
 * @nodes2:  a node-set
4828
 *
4829
 * Implements the EXSLT - Sets trailing() function:
4830
 *    node-set set:trailing (node-set, node-set)
4831
 * @nodes1 and @nodes2 are sorted by document order, then
4832
 * #xmlXPathTrailingSorted is called.
4833
 *
4834
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4835
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4836
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4837
 */
4838
xmlNodeSetPtr
4839
0
xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4840
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4841
0
  return(nodes1);
4842
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4843
0
  return(xmlXPathNodeSetCreate(NULL));
4844
0
    xmlXPathNodeSetSort(nodes1);
4845
0
    xmlXPathNodeSetSort(nodes2);
4846
0
    return(xmlXPathNodeTrailingSorted(nodes1,
4847
0
              xmlXPathNodeSetItem(nodes2, 0)));
4848
0
}
4849
4850
/************************************************************************
4851
 *                  *
4852
 *    Routines to handle extra functions      *
4853
 *                  *
4854
 ************************************************************************/
4855
4856
/**
4857
 * xmlXPathRegisterFunc:
4858
 * @ctxt:  the XPath context
4859
 * @name:  the function name
4860
 * @f:  the function implementation or NULL
4861
 *
4862
 * Register a new function. If @f is NULL it unregisters the function
4863
 *
4864
 * Returns 0 in case of success, -1 in case of error
4865
 */
4866
int
4867
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4868
0
         xmlXPathFunction f) {
4869
0
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4870
0
}
4871
4872
/**
4873
 * xmlXPathRegisterFuncNS:
4874
 * @ctxt:  the XPath context
4875
 * @name:  the function name
4876
 * @ns_uri:  the function namespace URI
4877
 * @f:  the function implementation or NULL
4878
 *
4879
 * Register a new function. If @f is NULL it unregisters the function
4880
 *
4881
 * Returns 0 in case of success, -1 in case of error
4882
 */
4883
int
4884
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4885
0
           const xmlChar *ns_uri, xmlXPathFunction f) {
4886
0
    if (ctxt == NULL)
4887
0
  return(-1);
4888
0
    if (name == NULL)
4889
0
  return(-1);
4890
4891
0
    if (ctxt->funcHash == NULL)
4892
0
  ctxt->funcHash = xmlHashCreate(0);
4893
0
    if (ctxt->funcHash == NULL)
4894
0
  return(-1);
4895
0
    if (f == NULL)
4896
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4897
0
    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4898
0
}
4899
4900
/**
4901
 * xmlXPathRegisterFuncLookup:
4902
 * @ctxt:  the XPath context
4903
 * @f:  the lookup function
4904
 * @funcCtxt:  the lookup data
4905
 *
4906
 * Registers an external mechanism to do function lookup.
4907
 */
4908
void
4909
xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4910
          xmlXPathFuncLookupFunc f,
4911
0
          void *funcCtxt) {
4912
0
    if (ctxt == NULL)
4913
0
  return;
4914
0
    ctxt->funcLookupFunc = f;
4915
0
    ctxt->funcLookupData = funcCtxt;
4916
0
}
4917
4918
/**
4919
 * xmlXPathFunctionLookup:
4920
 * @ctxt:  the XPath context
4921
 * @name:  the function name
4922
 *
4923
 * Search in the Function array of the context for the given
4924
 * function.
4925
 *
4926
 * Returns the xmlXPathFunction or NULL if not found
4927
 */
4928
xmlXPathFunction
4929
0
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4930
0
    if (ctxt == NULL)
4931
0
  return (NULL);
4932
4933
0
    if (ctxt->funcLookupFunc != NULL) {
4934
0
  xmlXPathFunction ret;
4935
0
  xmlXPathFuncLookupFunc f;
4936
4937
0
  f = ctxt->funcLookupFunc;
4938
0
  ret = f(ctxt->funcLookupData, name, NULL);
4939
0
  if (ret != NULL)
4940
0
      return(ret);
4941
0
    }
4942
0
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4943
0
}
4944
4945
/**
4946
 * xmlXPathFunctionLookupNS:
4947
 * @ctxt:  the XPath context
4948
 * @name:  the function name
4949
 * @ns_uri:  the function namespace URI
4950
 *
4951
 * Search in the Function array of the context for the given
4952
 * function.
4953
 *
4954
 * Returns the xmlXPathFunction or NULL if not found
4955
 */
4956
xmlXPathFunction
4957
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4958
0
       const xmlChar *ns_uri) {
4959
0
    xmlXPathFunction ret;
4960
4961
0
    if (ctxt == NULL)
4962
0
  return(NULL);
4963
0
    if (name == NULL)
4964
0
  return(NULL);
4965
4966
0
    if (ctxt->funcLookupFunc != NULL) {
4967
0
  xmlXPathFuncLookupFunc f;
4968
4969
0
  f = ctxt->funcLookupFunc;
4970
0
  ret = f(ctxt->funcLookupData, name, ns_uri);
4971
0
  if (ret != NULL)
4972
0
      return(ret);
4973
0
    }
4974
4975
0
    if (ctxt->funcHash == NULL)
4976
0
  return(NULL);
4977
4978
0
    XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4979
0
    return(ret);
4980
0
}
4981
4982
/**
4983
 * xmlXPathRegisteredFuncsCleanup:
4984
 * @ctxt:  the XPath context
4985
 *
4986
 * Cleanup the XPath context data associated to registered functions
4987
 */
4988
void
4989
0
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4990
0
    if (ctxt == NULL)
4991
0
  return;
4992
4993
0
    xmlHashFree(ctxt->funcHash, NULL);
4994
0
    ctxt->funcHash = NULL;
4995
0
}
4996
4997
/************************************************************************
4998
 *                  *
4999
 *      Routines to handle Variables      *
5000
 *                  *
5001
 ************************************************************************/
5002
5003
/**
5004
 * xmlXPathRegisterVariable:
5005
 * @ctxt:  the XPath context
5006
 * @name:  the variable name
5007
 * @value:  the variable value or NULL
5008
 *
5009
 * Register a new variable value. If @value is NULL it unregisters
5010
 * the variable
5011
 *
5012
 * Returns 0 in case of success, -1 in case of error
5013
 */
5014
int
5015
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
5016
0
       xmlXPathObjectPtr value) {
5017
0
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
5018
0
}
5019
5020
/**
5021
 * xmlXPathRegisterVariableNS:
5022
 * @ctxt:  the XPath context
5023
 * @name:  the variable name
5024
 * @ns_uri:  the variable namespace URI
5025
 * @value:  the variable value or NULL
5026
 *
5027
 * Register a new variable value. If @value is NULL it unregisters
5028
 * the variable
5029
 *
5030
 * Returns 0 in case of success, -1 in case of error
5031
 */
5032
int
5033
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5034
         const xmlChar *ns_uri,
5035
0
         xmlXPathObjectPtr value) {
5036
0
    if (ctxt == NULL)
5037
0
  return(-1);
5038
0
    if (name == NULL)
5039
0
  return(-1);
5040
5041
0
    if (ctxt->varHash == NULL)
5042
0
  ctxt->varHash = xmlHashCreate(0);
5043
0
    if (ctxt->varHash == NULL)
5044
0
  return(-1);
5045
0
    if (value == NULL)
5046
0
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5047
0
                             (xmlHashDeallocator)xmlXPathFreeObject));
5048
0
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5049
0
             (void *) value,
5050
0
             (xmlHashDeallocator)xmlXPathFreeObject));
5051
0
}
5052
5053
/**
5054
 * xmlXPathRegisterVariableLookup:
5055
 * @ctxt:  the XPath context
5056
 * @f:  the lookup function
5057
 * @data:  the lookup data
5058
 *
5059
 * register an external mechanism to do variable lookup
5060
 */
5061
void
5062
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5063
0
   xmlXPathVariableLookupFunc f, void *data) {
5064
0
    if (ctxt == NULL)
5065
0
  return;
5066
0
    ctxt->varLookupFunc = f;
5067
0
    ctxt->varLookupData = data;
5068
0
}
5069
5070
/**
5071
 * xmlXPathVariableLookup:
5072
 * @ctxt:  the XPath context
5073
 * @name:  the variable name
5074
 *
5075
 * Search in the Variable array of the context for the given
5076
 * variable value.
5077
 *
5078
 * Returns a copy of the value or NULL if not found
5079
 */
5080
xmlXPathObjectPtr
5081
0
xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5082
0
    if (ctxt == NULL)
5083
0
  return(NULL);
5084
5085
0
    if (ctxt->varLookupFunc != NULL) {
5086
0
  xmlXPathObjectPtr ret;
5087
5088
0
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5089
0
          (ctxt->varLookupData, name, NULL);
5090
0
  return(ret);
5091
0
    }
5092
0
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5093
0
}
5094
5095
/**
5096
 * xmlXPathVariableLookupNS:
5097
 * @ctxt:  the XPath context
5098
 * @name:  the variable name
5099
 * @ns_uri:  the variable namespace URI
5100
 *
5101
 * Search in the Variable array of the context for the given
5102
 * variable value.
5103
 *
5104
 * Returns the a copy of the value or NULL if not found
5105
 */
5106
xmlXPathObjectPtr
5107
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5108
0
       const xmlChar *ns_uri) {
5109
0
    if (ctxt == NULL)
5110
0
  return(NULL);
5111
5112
0
    if (ctxt->varLookupFunc != NULL) {
5113
0
  xmlXPathObjectPtr ret;
5114
5115
0
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5116
0
          (ctxt->varLookupData, name, ns_uri);
5117
0
  if (ret != NULL) return(ret);
5118
0
    }
5119
5120
0
    if (ctxt->varHash == NULL)
5121
0
  return(NULL);
5122
0
    if (name == NULL)
5123
0
  return(NULL);
5124
5125
0
    return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5126
0
    xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5127
0
}
5128
5129
/**
5130
 * xmlXPathRegisteredVariablesCleanup:
5131
 * @ctxt:  the XPath context
5132
 *
5133
 * Cleanup the XPath context data associated to registered variables
5134
 */
5135
void
5136
0
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5137
0
    if (ctxt == NULL)
5138
0
  return;
5139
5140
0
    xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
5141
0
    ctxt->varHash = NULL;
5142
0
}
5143
5144
/**
5145
 * xmlXPathRegisterNs:
5146
 * @ctxt:  the XPath context
5147
 * @prefix:  the namespace prefix cannot be NULL or empty string
5148
 * @ns_uri:  the namespace name
5149
 *
5150
 * Register a new namespace. If @ns_uri is NULL it unregisters
5151
 * the namespace
5152
 *
5153
 * Returns 0 in case of success, -1 in case of error
5154
 */
5155
int
5156
xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5157
0
         const xmlChar *ns_uri) {
5158
0
    if (ctxt == NULL)
5159
0
  return(-1);
5160
0
    if (prefix == NULL)
5161
0
  return(-1);
5162
0
    if (prefix[0] == 0)
5163
0
  return(-1);
5164
5165
0
    if (ctxt->nsHash == NULL)
5166
0
  ctxt->nsHash = xmlHashCreate(10);
5167
0
    if (ctxt->nsHash == NULL)
5168
0
  return(-1);
5169
0
    if (ns_uri == NULL)
5170
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5171
0
                            (xmlHashDeallocator)xmlFree));
5172
0
    return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5173
0
            (xmlHashDeallocator)xmlFree));
5174
0
}
5175
5176
/**
5177
 * xmlXPathNsLookup:
5178
 * @ctxt:  the XPath context
5179
 * @prefix:  the namespace prefix value
5180
 *
5181
 * Search in the namespace declaration array of the context for the given
5182
 * namespace name associated to the given prefix
5183
 *
5184
 * Returns the value or NULL if not found
5185
 */
5186
const xmlChar *
5187
0
xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5188
0
    if (ctxt == NULL)
5189
0
  return(NULL);
5190
0
    if (prefix == NULL)
5191
0
  return(NULL);
5192
5193
0
#ifdef XML_XML_NAMESPACE
5194
0
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5195
0
  return(XML_XML_NAMESPACE);
5196
0
#endif
5197
5198
0
    if (ctxt->namespaces != NULL) {
5199
0
  int i;
5200
5201
0
  for (i = 0;i < ctxt->nsNr;i++) {
5202
0
      if ((ctxt->namespaces[i] != NULL) &&
5203
0
    (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5204
0
    return(ctxt->namespaces[i]->href);
5205
0
  }
5206
0
    }
5207
5208
0
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5209
0
}
5210
5211
/**
5212
 * xmlXPathRegisteredNsCleanup:
5213
 * @ctxt:  the XPath context
5214
 *
5215
 * Cleanup the XPath context data associated to registered variables
5216
 */
5217
void
5218
0
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5219
0
    if (ctxt == NULL)
5220
0
  return;
5221
5222
0
    xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5223
0
    ctxt->nsHash = NULL;
5224
0
}
5225
5226
/************************************************************************
5227
 *                  *
5228
 *      Routines to handle Values     *
5229
 *                  *
5230
 ************************************************************************/
5231
5232
/* Allocations are terrible, one needs to optimize all this !!! */
5233
5234
/**
5235
 * xmlXPathNewFloat:
5236
 * @val:  the double value
5237
 *
5238
 * Create a new xmlXPathObjectPtr of type double and of value @val
5239
 *
5240
 * Returns the newly created object.
5241
 */
5242
xmlXPathObjectPtr
5243
0
xmlXPathNewFloat(double val) {
5244
0
    xmlXPathObjectPtr ret;
5245
5246
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5247
0
    if (ret == NULL) {
5248
0
        xmlXPathErrMemory(NULL, "creating float object\n");
5249
0
  return(NULL);
5250
0
    }
5251
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5252
0
    ret->type = XPATH_NUMBER;
5253
0
    ret->floatval = val;
5254
#ifdef XP_DEBUG_OBJ_USAGE
5255
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5256
#endif
5257
0
    return(ret);
5258
0
}
5259
5260
/**
5261
 * xmlXPathNewBoolean:
5262
 * @val:  the boolean value
5263
 *
5264
 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5265
 *
5266
 * Returns the newly created object.
5267
 */
5268
xmlXPathObjectPtr
5269
0
xmlXPathNewBoolean(int val) {
5270
0
    xmlXPathObjectPtr ret;
5271
5272
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5273
0
    if (ret == NULL) {
5274
0
        xmlXPathErrMemory(NULL, "creating boolean object\n");
5275
0
  return(NULL);
5276
0
    }
5277
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5278
0
    ret->type = XPATH_BOOLEAN;
5279
0
    ret->boolval = (val != 0);
5280
#ifdef XP_DEBUG_OBJ_USAGE
5281
    xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5282
#endif
5283
0
    return(ret);
5284
0
}
5285
5286
/**
5287
 * xmlXPathNewString:
5288
 * @val:  the xmlChar * value
5289
 *
5290
 * Create a new xmlXPathObjectPtr of type string and of value @val
5291
 *
5292
 * Returns the newly created object.
5293
 */
5294
xmlXPathObjectPtr
5295
0
xmlXPathNewString(const xmlChar *val) {
5296
0
    xmlXPathObjectPtr ret;
5297
5298
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5299
0
    if (ret == NULL) {
5300
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5301
0
  return(NULL);
5302
0
    }
5303
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5304
0
    ret->type = XPATH_STRING;
5305
0
    if (val != NULL)
5306
0
  ret->stringval = xmlStrdup(val);
5307
0
    else
5308
0
  ret->stringval = xmlStrdup((const xmlChar *)"");
5309
#ifdef XP_DEBUG_OBJ_USAGE
5310
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5311
#endif
5312
0
    return(ret);
5313
0
}
5314
5315
/**
5316
 * xmlXPathWrapString:
5317
 * @val:  the xmlChar * value
5318
 *
5319
 * Wraps the @val string into an XPath object.
5320
 *
5321
 * Returns the newly created object.
5322
 */
5323
xmlXPathObjectPtr
5324
0
xmlXPathWrapString (xmlChar *val) {
5325
0
    xmlXPathObjectPtr ret;
5326
5327
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5328
0
    if (ret == NULL) {
5329
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5330
0
  return(NULL);
5331
0
    }
5332
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5333
0
    ret->type = XPATH_STRING;
5334
0
    ret->stringval = val;
5335
#ifdef XP_DEBUG_OBJ_USAGE
5336
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5337
#endif
5338
0
    return(ret);
5339
0
}
5340
5341
/**
5342
 * xmlXPathNewCString:
5343
 * @val:  the char * value
5344
 *
5345
 * Create a new xmlXPathObjectPtr of type string and of value @val
5346
 *
5347
 * Returns the newly created object.
5348
 */
5349
xmlXPathObjectPtr
5350
0
xmlXPathNewCString(const char *val) {
5351
0
    xmlXPathObjectPtr ret;
5352
5353
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5354
0
    if (ret == NULL) {
5355
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5356
0
  return(NULL);
5357
0
    }
5358
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5359
0
    ret->type = XPATH_STRING;
5360
0
    ret->stringval = xmlStrdup(BAD_CAST val);
5361
#ifdef XP_DEBUG_OBJ_USAGE
5362
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5363
#endif
5364
0
    return(ret);
5365
0
}
5366
5367
/**
5368
 * xmlXPathWrapCString:
5369
 * @val:  the char * value
5370
 *
5371
 * Wraps a string into an XPath object.
5372
 *
5373
 * Returns the newly created object.
5374
 */
5375
xmlXPathObjectPtr
5376
0
xmlXPathWrapCString (char * val) {
5377
0
    return(xmlXPathWrapString((xmlChar *)(val)));
5378
0
}
5379
5380
/**
5381
 * xmlXPathWrapExternal:
5382
 * @val:  the user data
5383
 *
5384
 * Wraps the @val data into an XPath object.
5385
 *
5386
 * Returns the newly created object.
5387
 */
5388
xmlXPathObjectPtr
5389
0
xmlXPathWrapExternal (void *val) {
5390
0
    xmlXPathObjectPtr ret;
5391
5392
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5393
0
    if (ret == NULL) {
5394
0
        xmlXPathErrMemory(NULL, "creating user object\n");
5395
0
  return(NULL);
5396
0
    }
5397
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5398
0
    ret->type = XPATH_USERS;
5399
0
    ret->user = val;
5400
#ifdef XP_DEBUG_OBJ_USAGE
5401
    xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5402
#endif
5403
0
    return(ret);
5404
0
}
5405
5406
/**
5407
 * xmlXPathObjectCopy:
5408
 * @val:  the original object
5409
 *
5410
 * allocate a new copy of a given object
5411
 *
5412
 * Returns the newly created object.
5413
 */
5414
xmlXPathObjectPtr
5415
0
xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5416
0
    xmlXPathObjectPtr ret;
5417
5418
0
    if (val == NULL)
5419
0
  return(NULL);
5420
5421
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5422
0
    if (ret == NULL) {
5423
0
        xmlXPathErrMemory(NULL, "copying object\n");
5424
0
  return(NULL);
5425
0
    }
5426
0
    memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5427
#ifdef XP_DEBUG_OBJ_USAGE
5428
    xmlXPathDebugObjUsageRequested(NULL, val->type);
5429
#endif
5430
0
    switch (val->type) {
5431
0
  case XPATH_BOOLEAN:
5432
0
  case XPATH_NUMBER:
5433
0
  case XPATH_POINT:
5434
0
  case XPATH_RANGE:
5435
0
      break;
5436
0
  case XPATH_STRING:
5437
0
      ret->stringval = xmlStrdup(val->stringval);
5438
0
      break;
5439
0
  case XPATH_XSLT_TREE:
5440
#if 0
5441
/*
5442
  Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5443
  this previous handling is no longer correct, and can cause some serious
5444
  problems (ref. bug 145547)
5445
*/
5446
      if ((val->nodesetval != NULL) &&
5447
    (val->nodesetval->nodeTab != NULL)) {
5448
    xmlNodePtr cur, tmp;
5449
    xmlDocPtr top;
5450
5451
    ret->boolval = 1;
5452
    top =  xmlNewDoc(NULL);
5453
    top->name = (char *)
5454
        xmlStrdup(val->nodesetval->nodeTab[0]->name);
5455
    ret->user = top;
5456
    if (top != NULL) {
5457
        top->doc = top;
5458
        cur = val->nodesetval->nodeTab[0]->children;
5459
        while (cur != NULL) {
5460
      tmp = xmlDocCopyNode(cur, top, 1);
5461
      xmlAddChild((xmlNodePtr) top, tmp);
5462
      cur = cur->next;
5463
        }
5464
    }
5465
5466
    ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5467
      } else
5468
    ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5469
      /* Deallocate the copied tree value */
5470
      break;
5471
#endif
5472
0
  case XPATH_NODESET:
5473
0
      ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5474
      /* Do not deallocate the copied tree value */
5475
0
      ret->boolval = 0;
5476
0
      break;
5477
0
  case XPATH_LOCATIONSET:
5478
0
#ifdef LIBXML_XPTR_ENABLED
5479
0
  {
5480
0
      xmlLocationSetPtr loc = val->user;
5481
0
      ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5482
0
      break;
5483
0
  }
5484
0
#endif
5485
0
        case XPATH_USERS:
5486
0
      ret->user = val->user;
5487
0
      break;
5488
0
        case XPATH_UNDEFINED:
5489
0
      xmlGenericError(xmlGenericErrorContext,
5490
0
        "xmlXPathObjectCopy: unsupported type %d\n",
5491
0
        val->type);
5492
0
      break;
5493
0
    }
5494
0
    return(ret);
5495
0
}
5496
5497
/**
5498
 * xmlXPathFreeObject:
5499
 * @obj:  the object to free
5500
 *
5501
 * Free up an xmlXPathObjectPtr object.
5502
 */
5503
void
5504
0
xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5505
0
    if (obj == NULL) return;
5506
0
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5507
0
  if (obj->boolval) {
5508
#if 0
5509
      if (obj->user != NULL) {
5510
                xmlXPathFreeNodeSet(obj->nodesetval);
5511
    xmlFreeNodeList((xmlNodePtr) obj->user);
5512
      } else
5513
#endif
5514
0
      obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5515
0
      if (obj->nodesetval != NULL)
5516
0
    xmlXPathFreeValueTree(obj->nodesetval);
5517
0
  } else {
5518
0
      if (obj->nodesetval != NULL)
5519
0
    xmlXPathFreeNodeSet(obj->nodesetval);
5520
0
  }
5521
0
#ifdef LIBXML_XPTR_ENABLED
5522
0
    } else if (obj->type == XPATH_LOCATIONSET) {
5523
0
  if (obj->user != NULL)
5524
0
      xmlXPtrFreeLocationSet(obj->user);
5525
0
#endif
5526
0
    } else if (obj->type == XPATH_STRING) {
5527
0
  if (obj->stringval != NULL)
5528
0
      xmlFree(obj->stringval);
5529
0
    }
5530
#ifdef XP_DEBUG_OBJ_USAGE
5531
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
5532
#endif
5533
0
    xmlFree(obj);
5534
0
}
5535
5536
/**
5537
 * xmlXPathReleaseObject:
5538
 * @obj:  the xmlXPathObjectPtr to free or to cache
5539
 *
5540
 * Depending on the state of the cache this frees the given
5541
 * XPath object or stores it in the cache.
5542
 */
5543
static void
5544
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5545
0
{
5546
0
#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5547
0
  sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5548
0
    if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5549
5550
0
#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5551
5552
0
    if (obj == NULL)
5553
0
  return;
5554
0
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5555
0
   xmlXPathFreeObject(obj);
5556
0
    } else {
5557
0
  xmlXPathContextCachePtr cache =
5558
0
      (xmlXPathContextCachePtr) ctxt->cache;
5559
5560
0
  switch (obj->type) {
5561
0
      case XPATH_NODESET:
5562
0
      case XPATH_XSLT_TREE:
5563
0
    if (obj->nodesetval != NULL) {
5564
0
        if (obj->boolval) {
5565
      /*
5566
      * It looks like the @boolval is used for
5567
      * evaluation if this an XSLT Result Tree Fragment.
5568
      * TODO: Check if this assumption is correct.
5569
      */
5570
0
      obj->type = XPATH_XSLT_TREE; /* just for debugging */
5571
0
      xmlXPathFreeValueTree(obj->nodesetval);
5572
0
      obj->nodesetval = NULL;
5573
0
        } else if ((obj->nodesetval->nodeMax <= 40) &&
5574
0
      (XP_CACHE_WANTS(cache->nodesetObjs,
5575
0
          cache->maxNodeset)))
5576
0
        {
5577
0
      XP_CACHE_ADD(cache->nodesetObjs, obj);
5578
0
      goto obj_cached;
5579
0
        } else {
5580
0
      xmlXPathFreeNodeSet(obj->nodesetval);
5581
0
      obj->nodesetval = NULL;
5582
0
        }
5583
0
    }
5584
0
    break;
5585
0
      case XPATH_STRING:
5586
0
    if (obj->stringval != NULL)
5587
0
        xmlFree(obj->stringval);
5588
5589
0
    if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5590
0
        XP_CACHE_ADD(cache->stringObjs, obj);
5591
0
        goto obj_cached;
5592
0
    }
5593
0
    break;
5594
0
      case XPATH_BOOLEAN:
5595
0
    if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5596
0
        XP_CACHE_ADD(cache->booleanObjs, obj);
5597
0
        goto obj_cached;
5598
0
    }
5599
0
    break;
5600
0
      case XPATH_NUMBER:
5601
0
    if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5602
0
        XP_CACHE_ADD(cache->numberObjs, obj);
5603
0
        goto obj_cached;
5604
0
    }
5605
0
    break;
5606
0
#ifdef LIBXML_XPTR_ENABLED
5607
0
      case XPATH_LOCATIONSET:
5608
0
    if (obj->user != NULL) {
5609
0
        xmlXPtrFreeLocationSet(obj->user);
5610
0
    }
5611
0
    goto free_obj;
5612
0
#endif
5613
0
      default:
5614
0
    goto free_obj;
5615
0
  }
5616
5617
  /*
5618
  * Fallback to adding to the misc-objects slot.
5619
  */
5620
0
  if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5621
0
      XP_CACHE_ADD(cache->miscObjs, obj);
5622
0
  } else
5623
0
      goto free_obj;
5624
5625
0
obj_cached:
5626
5627
#ifdef XP_DEBUG_OBJ_USAGE
5628
  xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5629
#endif
5630
5631
0
  if (obj->nodesetval != NULL) {
5632
0
      xmlNodeSetPtr tmpset = obj->nodesetval;
5633
5634
      /*
5635
      * TODO: Due to those nasty ns-nodes, we need to traverse
5636
      *  the list and free the ns-nodes.
5637
      * URGENT TODO: Check if it's actually slowing things down.
5638
      *  Maybe we shouldn't try to preserve the list.
5639
      */
5640
0
      if (tmpset->nodeNr > 1) {
5641
0
    int i;
5642
0
    xmlNodePtr node;
5643
5644
0
    for (i = 0; i < tmpset->nodeNr; i++) {
5645
0
        node = tmpset->nodeTab[i];
5646
0
        if ((node != NULL) &&
5647
0
      (node->type == XML_NAMESPACE_DECL))
5648
0
        {
5649
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5650
0
        }
5651
0
    }
5652
0
      } else if (tmpset->nodeNr == 1) {
5653
0
    if ((tmpset->nodeTab[0] != NULL) &&
5654
0
        (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5655
0
        xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5656
0
      }
5657
0
      tmpset->nodeNr = 0;
5658
0
      memset(obj, 0, sizeof(xmlXPathObject));
5659
0
      obj->nodesetval = tmpset;
5660
0
  } else
5661
0
      memset(obj, 0, sizeof(xmlXPathObject));
5662
5663
0
  return;
5664
5665
0
free_obj:
5666
  /*
5667
  * Cache is full; free the object.
5668
  */
5669
0
  if (obj->nodesetval != NULL)
5670
0
      xmlXPathFreeNodeSet(obj->nodesetval);
5671
#ifdef XP_DEBUG_OBJ_USAGE
5672
  xmlXPathDebugObjUsageReleased(NULL, obj->type);
5673
#endif
5674
0
  xmlFree(obj);
5675
0
    }
5676
0
    return;
5677
0
}
5678
5679
5680
/************************************************************************
5681
 *                  *
5682
 *      Type Casting Routines       *
5683
 *                  *
5684
 ************************************************************************/
5685
5686
/**
5687
 * xmlXPathCastBooleanToString:
5688
 * @val:  a boolean
5689
 *
5690
 * Converts a boolean to its string value.
5691
 *
5692
 * Returns a newly allocated string.
5693
 */
5694
xmlChar *
5695
0
xmlXPathCastBooleanToString (int val) {
5696
0
    xmlChar *ret;
5697
0
    if (val)
5698
0
  ret = xmlStrdup((const xmlChar *) "true");
5699
0
    else
5700
0
  ret = xmlStrdup((const xmlChar *) "false");
5701
0
    return(ret);
5702
0
}
5703
5704
/**
5705
 * xmlXPathCastNumberToString:
5706
 * @val:  a number
5707
 *
5708
 * Converts a number to its string value.
5709
 *
5710
 * Returns a newly allocated string.
5711
 */
5712
xmlChar *
5713
0
xmlXPathCastNumberToString (double val) {
5714
0
    xmlChar *ret;
5715
0
    switch (xmlXPathIsInf(val)) {
5716
0
    case 1:
5717
0
  ret = xmlStrdup((const xmlChar *) "Infinity");
5718
0
  break;
5719
0
    case -1:
5720
0
  ret = xmlStrdup((const xmlChar *) "-Infinity");
5721
0
  break;
5722
0
    default:
5723
0
  if (xmlXPathIsNaN(val)) {
5724
0
      ret = xmlStrdup((const xmlChar *) "NaN");
5725
0
  } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5726
0
      ret = xmlStrdup((const xmlChar *) "0");
5727
0
  } else {
5728
      /* could be improved */
5729
0
      char buf[100];
5730
0
      xmlXPathFormatNumber(val, buf, 99);
5731
0
      buf[99] = 0;
5732
0
      ret = xmlStrdup((const xmlChar *) buf);
5733
0
  }
5734
0
    }
5735
0
    return(ret);
5736
0
}
5737
5738
/**
5739
 * xmlXPathCastNodeToString:
5740
 * @node:  a node
5741
 *
5742
 * Converts a node to its string value.
5743
 *
5744
 * Returns a newly allocated string.
5745
 */
5746
xmlChar *
5747
0
xmlXPathCastNodeToString (xmlNodePtr node) {
5748
0
xmlChar *ret;
5749
0
    if ((ret = xmlNodeGetContent(node)) == NULL)
5750
0
  ret = xmlStrdup((const xmlChar *) "");
5751
0
    return(ret);
5752
0
}
5753
5754
/**
5755
 * xmlXPathCastNodeSetToString:
5756
 * @ns:  a node-set
5757
 *
5758
 * Converts a node-set to its string value.
5759
 *
5760
 * Returns a newly allocated string.
5761
 */
5762
xmlChar *
5763
0
xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5764
0
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5765
0
  return(xmlStrdup((const xmlChar *) ""));
5766
5767
0
    if (ns->nodeNr > 1)
5768
0
  xmlXPathNodeSetSort(ns);
5769
0
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5770
0
}
5771
5772
/**
5773
 * xmlXPathCastToString:
5774
 * @val:  an XPath object
5775
 *
5776
 * Converts an existing object to its string() equivalent
5777
 *
5778
 * Returns the allocated string value of the object, NULL in case of error.
5779
 *         It's up to the caller to free the string memory with xmlFree().
5780
 */
5781
xmlChar *
5782
0
xmlXPathCastToString(xmlXPathObjectPtr val) {
5783
0
    xmlChar *ret = NULL;
5784
5785
0
    if (val == NULL)
5786
0
  return(xmlStrdup((const xmlChar *) ""));
5787
0
    switch (val->type) {
5788
0
  case XPATH_UNDEFINED:
5789
#ifdef DEBUG_EXPR
5790
      xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5791
#endif
5792
0
      ret = xmlStrdup((const xmlChar *) "");
5793
0
      break;
5794
0
        case XPATH_NODESET:
5795
0
        case XPATH_XSLT_TREE:
5796
0
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
5797
0
      break;
5798
0
  case XPATH_STRING:
5799
0
      return(xmlStrdup(val->stringval));
5800
0
        case XPATH_BOOLEAN:
5801
0
      ret = xmlXPathCastBooleanToString(val->boolval);
5802
0
      break;
5803
0
  case XPATH_NUMBER: {
5804
0
      ret = xmlXPathCastNumberToString(val->floatval);
5805
0
      break;
5806
0
  }
5807
0
  case XPATH_USERS:
5808
0
  case XPATH_POINT:
5809
0
  case XPATH_RANGE:
5810
0
  case XPATH_LOCATIONSET:
5811
0
      TODO
5812
0
      ret = xmlStrdup((const xmlChar *) "");
5813
0
      break;
5814
0
    }
5815
0
    return(ret);
5816
0
}
5817
5818
/**
5819
 * xmlXPathConvertString:
5820
 * @val:  an XPath object
5821
 *
5822
 * Converts an existing object to its string() equivalent
5823
 *
5824
 * Returns the new object, the old one is freed (or the operation
5825
 *         is done directly on @val)
5826
 */
5827
xmlXPathObjectPtr
5828
0
xmlXPathConvertString(xmlXPathObjectPtr val) {
5829
0
    xmlChar *res = NULL;
5830
5831
0
    if (val == NULL)
5832
0
  return(xmlXPathNewCString(""));
5833
5834
0
    switch (val->type) {
5835
0
    case XPATH_UNDEFINED:
5836
#ifdef DEBUG_EXPR
5837
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5838
#endif
5839
0
  break;
5840
0
    case XPATH_NODESET:
5841
0
    case XPATH_XSLT_TREE:
5842
0
  res = xmlXPathCastNodeSetToString(val->nodesetval);
5843
0
  break;
5844
0
    case XPATH_STRING:
5845
0
  return(val);
5846
0
    case XPATH_BOOLEAN:
5847
0
  res = xmlXPathCastBooleanToString(val->boolval);
5848
0
  break;
5849
0
    case XPATH_NUMBER:
5850
0
  res = xmlXPathCastNumberToString(val->floatval);
5851
0
  break;
5852
0
    case XPATH_USERS:
5853
0
    case XPATH_POINT:
5854
0
    case XPATH_RANGE:
5855
0
    case XPATH_LOCATIONSET:
5856
0
  TODO;
5857
0
  break;
5858
0
    }
5859
0
    xmlXPathFreeObject(val);
5860
0
    if (res == NULL)
5861
0
  return(xmlXPathNewCString(""));
5862
0
    return(xmlXPathWrapString(res));
5863
0
}
5864
5865
/**
5866
 * xmlXPathCastBooleanToNumber:
5867
 * @val:  a boolean
5868
 *
5869
 * Converts a boolean to its number value
5870
 *
5871
 * Returns the number value
5872
 */
5873
double
5874
0
xmlXPathCastBooleanToNumber(int val) {
5875
0
    if (val)
5876
0
  return(1.0);
5877
0
    return(0.0);
5878
0
}
5879
5880
/**
5881
 * xmlXPathCastStringToNumber:
5882
 * @val:  a string
5883
 *
5884
 * Converts a string to its number value
5885
 *
5886
 * Returns the number value
5887
 */
5888
double
5889
0
xmlXPathCastStringToNumber(const xmlChar * val) {
5890
0
    return(xmlXPathStringEvalNumber(val));
5891
0
}
5892
5893
/**
5894
 * xmlXPathCastNodeToNumber:
5895
 * @node:  a node
5896
 *
5897
 * Converts a node to its number value
5898
 *
5899
 * Returns the number value
5900
 */
5901
double
5902
0
xmlXPathCastNodeToNumber (xmlNodePtr node) {
5903
0
    xmlChar *strval;
5904
0
    double ret;
5905
5906
0
    if (node == NULL)
5907
0
  return(xmlXPathNAN);
5908
0
    strval = xmlXPathCastNodeToString(node);
5909
0
    if (strval == NULL)
5910
0
  return(xmlXPathNAN);
5911
0
    ret = xmlXPathCastStringToNumber(strval);
5912
0
    xmlFree(strval);
5913
5914
0
    return(ret);
5915
0
}
5916
5917
/**
5918
 * xmlXPathCastNodeSetToNumber:
5919
 * @ns:  a node-set
5920
 *
5921
 * Converts a node-set to its number value
5922
 *
5923
 * Returns the number value
5924
 */
5925
double
5926
0
xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5927
0
    xmlChar *str;
5928
0
    double ret;
5929
5930
0
    if (ns == NULL)
5931
0
  return(xmlXPathNAN);
5932
0
    str = xmlXPathCastNodeSetToString(ns);
5933
0
    ret = xmlXPathCastStringToNumber(str);
5934
0
    xmlFree(str);
5935
0
    return(ret);
5936
0
}
5937
5938
/**
5939
 * xmlXPathCastToNumber:
5940
 * @val:  an XPath object
5941
 *
5942
 * Converts an XPath object to its number value
5943
 *
5944
 * Returns the number value
5945
 */
5946
double
5947
0
xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5948
0
    double ret = 0.0;
5949
5950
0
    if (val == NULL)
5951
0
  return(xmlXPathNAN);
5952
0
    switch (val->type) {
5953
0
    case XPATH_UNDEFINED:
5954
#ifdef DEGUB_EXPR
5955
  xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5956
#endif
5957
0
  ret = xmlXPathNAN;
5958
0
  break;
5959
0
    case XPATH_NODESET:
5960
0
    case XPATH_XSLT_TREE:
5961
0
  ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5962
0
  break;
5963
0
    case XPATH_STRING:
5964
0
  ret = xmlXPathCastStringToNumber(val->stringval);
5965
0
  break;
5966
0
    case XPATH_NUMBER:
5967
0
  ret = val->floatval;
5968
0
  break;
5969
0
    case XPATH_BOOLEAN:
5970
0
  ret = xmlXPathCastBooleanToNumber(val->boolval);
5971
0
  break;
5972
0
    case XPATH_USERS:
5973
0
    case XPATH_POINT:
5974
0
    case XPATH_RANGE:
5975
0
    case XPATH_LOCATIONSET:
5976
0
  TODO;
5977
0
  ret = xmlXPathNAN;
5978
0
  break;
5979
0
    }
5980
0
    return(ret);
5981
0
}
5982
5983
/**
5984
 * xmlXPathConvertNumber:
5985
 * @val:  an XPath object
5986
 *
5987
 * Converts an existing object to its number() equivalent
5988
 *
5989
 * Returns the new object, the old one is freed (or the operation
5990
 *         is done directly on @val)
5991
 */
5992
xmlXPathObjectPtr
5993
0
xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5994
0
    xmlXPathObjectPtr ret;
5995
5996
0
    if (val == NULL)
5997
0
  return(xmlXPathNewFloat(0.0));
5998
0
    if (val->type == XPATH_NUMBER)
5999
0
  return(val);
6000
0
    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
6001
0
    xmlXPathFreeObject(val);
6002
0
    return(ret);
6003
0
}
6004
6005
/**
6006
 * xmlXPathCastNumberToBoolean:
6007
 * @val:  a number
6008
 *
6009
 * Converts a number to its boolean value
6010
 *
6011
 * Returns the boolean value
6012
 */
6013
int
6014
0
xmlXPathCastNumberToBoolean (double val) {
6015
0
     if (xmlXPathIsNaN(val) || (val == 0.0))
6016
0
   return(0);
6017
0
     return(1);
6018
0
}
6019
6020
/**
6021
 * xmlXPathCastStringToBoolean:
6022
 * @val:  a string
6023
 *
6024
 * Converts a string to its boolean value
6025
 *
6026
 * Returns the boolean value
6027
 */
6028
int
6029
0
xmlXPathCastStringToBoolean (const xmlChar *val) {
6030
0
    if ((val == NULL) || (xmlStrlen(val) == 0))
6031
0
  return(0);
6032
0
    return(1);
6033
0
}
6034
6035
/**
6036
 * xmlXPathCastNodeSetToBoolean:
6037
 * @ns:  a node-set
6038
 *
6039
 * Converts a node-set to its boolean value
6040
 *
6041
 * Returns the boolean value
6042
 */
6043
int
6044
0
xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6045
0
    if ((ns == NULL) || (ns->nodeNr == 0))
6046
0
  return(0);
6047
0
    return(1);
6048
0
}
6049
6050
/**
6051
 * xmlXPathCastToBoolean:
6052
 * @val:  an XPath object
6053
 *
6054
 * Converts an XPath object to its boolean value
6055
 *
6056
 * Returns the boolean value
6057
 */
6058
int
6059
0
xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6060
0
    int ret = 0;
6061
6062
0
    if (val == NULL)
6063
0
  return(0);
6064
0
    switch (val->type) {
6065
0
    case XPATH_UNDEFINED:
6066
#ifdef DEBUG_EXPR
6067
  xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6068
#endif
6069
0
  ret = 0;
6070
0
  break;
6071
0
    case XPATH_NODESET:
6072
0
    case XPATH_XSLT_TREE:
6073
0
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6074
0
  break;
6075
0
    case XPATH_STRING:
6076
0
  ret = xmlXPathCastStringToBoolean(val->stringval);
6077
0
  break;
6078
0
    case XPATH_NUMBER:
6079
0
  ret = xmlXPathCastNumberToBoolean(val->floatval);
6080
0
  break;
6081
0
    case XPATH_BOOLEAN:
6082
0
  ret = val->boolval;
6083
0
  break;
6084
0
    case XPATH_USERS:
6085
0
    case XPATH_POINT:
6086
0
    case XPATH_RANGE:
6087
0
    case XPATH_LOCATIONSET:
6088
0
  TODO;
6089
0
  ret = 0;
6090
0
  break;
6091
0
    }
6092
0
    return(ret);
6093
0
}
6094
6095
6096
/**
6097
 * xmlXPathConvertBoolean:
6098
 * @val:  an XPath object
6099
 *
6100
 * Converts an existing object to its boolean() equivalent
6101
 *
6102
 * Returns the new object, the old one is freed (or the operation
6103
 *         is done directly on @val)
6104
 */
6105
xmlXPathObjectPtr
6106
0
xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6107
0
    xmlXPathObjectPtr ret;
6108
6109
0
    if (val == NULL)
6110
0
  return(xmlXPathNewBoolean(0));
6111
0
    if (val->type == XPATH_BOOLEAN)
6112
0
  return(val);
6113
0
    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6114
0
    xmlXPathFreeObject(val);
6115
0
    return(ret);
6116
0
}
6117
6118
/************************************************************************
6119
 *                  *
6120
 *    Routines to handle XPath contexts     *
6121
 *                  *
6122
 ************************************************************************/
6123
6124
/**
6125
 * xmlXPathNewContext:
6126
 * @doc:  the XML document
6127
 *
6128
 * Create a new xmlXPathContext
6129
 *
6130
 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6131
 */
6132
xmlXPathContextPtr
6133
0
xmlXPathNewContext(xmlDocPtr doc) {
6134
0
    xmlXPathContextPtr ret;
6135
6136
0
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6137
0
    if (ret == NULL) {
6138
0
        xmlXPathErrMemory(NULL, "creating context\n");
6139
0
  return(NULL);
6140
0
    }
6141
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6142
0
    ret->doc = doc;
6143
0
    ret->node = NULL;
6144
6145
0
    ret->varHash = NULL;
6146
6147
0
    ret->nb_types = 0;
6148
0
    ret->max_types = 0;
6149
0
    ret->types = NULL;
6150
6151
0
    ret->funcHash = xmlHashCreate(0);
6152
6153
0
    ret->nb_axis = 0;
6154
0
    ret->max_axis = 0;
6155
0
    ret->axis = NULL;
6156
6157
0
    ret->nsHash = NULL;
6158
0
    ret->user = NULL;
6159
6160
0
    ret->contextSize = -1;
6161
0
    ret->proximityPosition = -1;
6162
6163
#ifdef XP_DEFAULT_CACHE_ON
6164
    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6165
  xmlXPathFreeContext(ret);
6166
  return(NULL);
6167
    }
6168
#endif
6169
6170
0
    xmlXPathRegisterAllFunctions(ret);
6171
6172
0
    return(ret);
6173
0
}
6174
6175
/**
6176
 * xmlXPathFreeContext:
6177
 * @ctxt:  the context to free
6178
 *
6179
 * Free up an xmlXPathContext
6180
 */
6181
void
6182
0
xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6183
0
    if (ctxt == NULL) return;
6184
6185
0
    if (ctxt->cache != NULL)
6186
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6187
0
    xmlXPathRegisteredNsCleanup(ctxt);
6188
0
    xmlXPathRegisteredFuncsCleanup(ctxt);
6189
0
    xmlXPathRegisteredVariablesCleanup(ctxt);
6190
0
    xmlResetError(&ctxt->lastError);
6191
0
    xmlFree(ctxt);
6192
0
}
6193
6194
/************************************************************************
6195
 *                  *
6196
 *    Routines to handle XPath parser contexts    *
6197
 *                  *
6198
 ************************************************************************/
6199
6200
#define CHECK_CTXT(ctxt)            \
6201
0
    if (ctxt == NULL) {           \
6202
0
  __xmlRaiseError(NULL, NULL, NULL,       \
6203
0
    NULL, NULL, XML_FROM_XPATH,       \
6204
0
    XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \
6205
0
    __FILE__, __LINE__,         \
6206
0
    NULL, NULL, NULL, 0, 0,         \
6207
0
    "NULL context pointer\n");        \
6208
0
  return(NULL);             \
6209
0
    }                  \
6210
6211
#define CHECK_CTXT_NEG(ctxt)            \
6212
0
    if (ctxt == NULL) {           \
6213
0
  __xmlRaiseError(NULL, NULL, NULL,       \
6214
0
    NULL, NULL, XML_FROM_XPATH,       \
6215
0
    XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \
6216
0
    __FILE__, __LINE__,         \
6217
0
    NULL, NULL, NULL, 0, 0,         \
6218
0
    "NULL context pointer\n");        \
6219
0
  return(-1);             \
6220
0
    }                  \
6221
6222
6223
#define CHECK_CONTEXT(ctxt)           \
6224
    if ((ctxt == NULL) || (ctxt->doc == NULL) ||      \
6225
        (ctxt->doc->children == NULL)) {        \
6226
  xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);  \
6227
  return(NULL);             \
6228
    }
6229
6230
6231
/**
6232
 * xmlXPathNewParserContext:
6233
 * @str:  the XPath expression
6234
 * @ctxt:  the XPath context
6235
 *
6236
 * Create a new xmlXPathParserContext
6237
 *
6238
 * Returns the xmlXPathParserContext just allocated.
6239
 */
6240
xmlXPathParserContextPtr
6241
0
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6242
0
    xmlXPathParserContextPtr ret;
6243
6244
0
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6245
0
    if (ret == NULL) {
6246
0
        xmlXPathErrMemory(ctxt, "creating parser context\n");
6247
0
  return(NULL);
6248
0
    }
6249
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6250
0
    ret->cur = ret->base = str;
6251
0
    ret->context = ctxt;
6252
6253
0
    ret->comp = xmlXPathNewCompExpr();
6254
0
    if (ret->comp == NULL) {
6255
0
  xmlFree(ret->valueTab);
6256
0
  xmlFree(ret);
6257
0
  return(NULL);
6258
0
    }
6259
0
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6260
0
        ret->comp->dict = ctxt->dict;
6261
0
  xmlDictReference(ret->comp->dict);
6262
0
    }
6263
6264
0
    return(ret);
6265
0
}
6266
6267
/**
6268
 * xmlXPathCompParserContext:
6269
 * @comp:  the XPath compiled expression
6270
 * @ctxt:  the XPath context
6271
 *
6272
 * Create a new xmlXPathParserContext when processing a compiled expression
6273
 *
6274
 * Returns the xmlXPathParserContext just allocated.
6275
 */
6276
static xmlXPathParserContextPtr
6277
0
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6278
0
    xmlXPathParserContextPtr ret;
6279
6280
0
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6281
0
    if (ret == NULL) {
6282
0
        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6283
0
  return(NULL);
6284
0
    }
6285
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6286
6287
    /* Allocate the value stack */
6288
0
    ret->valueTab = (xmlXPathObjectPtr *)
6289
0
                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6290
0
    if (ret->valueTab == NULL) {
6291
0
  xmlFree(ret);
6292
0
  xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6293
0
  return(NULL);
6294
0
    }
6295
0
    ret->valueNr = 0;
6296
0
    ret->valueMax = 10;
6297
0
    ret->value = NULL;
6298
0
    ret->valueFrame = 0;
6299
6300
0
    ret->context = ctxt;
6301
0
    ret->comp = comp;
6302
6303
0
    return(ret);
6304
0
}
6305
6306
/**
6307
 * xmlXPathFreeParserContext:
6308
 * @ctxt:  the context to free
6309
 *
6310
 * Free up an xmlXPathParserContext
6311
 */
6312
void
6313
0
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6314
0
    int i;
6315
6316
0
    if (ctxt->valueTab != NULL) {
6317
0
        for (i = 0; i < ctxt->valueNr; i++) {
6318
0
            if (ctxt->context)
6319
0
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6320
0
            else
6321
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
6322
0
        }
6323
0
        xmlFree(ctxt->valueTab);
6324
0
    }
6325
0
    if (ctxt->comp != NULL) {
6326
0
#ifdef XPATH_STREAMING
6327
0
  if (ctxt->comp->stream != NULL) {
6328
0
      xmlFreePatternList(ctxt->comp->stream);
6329
0
      ctxt->comp->stream = NULL;
6330
0
  }
6331
0
#endif
6332
0
  xmlXPathFreeCompExpr(ctxt->comp);
6333
0
    }
6334
0
    xmlFree(ctxt);
6335
0
}
6336
6337
/************************************************************************
6338
 *                  *
6339
 *    The implicit core function library      *
6340
 *                  *
6341
 ************************************************************************/
6342
6343
/**
6344
 * xmlXPathNodeValHash:
6345
 * @node:  a node pointer
6346
 *
6347
 * Function computing the beginning of the string value of the node,
6348
 * used to speed up comparisons
6349
 *
6350
 * Returns an int usable as a hash
6351
 */
6352
static unsigned int
6353
0
xmlXPathNodeValHash(xmlNodePtr node) {
6354
0
    int len = 2;
6355
0
    const xmlChar * string = NULL;
6356
0
    xmlNodePtr tmp = NULL;
6357
0
    unsigned int ret = 0;
6358
6359
0
    if (node == NULL)
6360
0
  return(0);
6361
6362
0
    if (node->type == XML_DOCUMENT_NODE) {
6363
0
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
6364
0
  if (tmp == NULL)
6365
0
      node = node->children;
6366
0
  else
6367
0
      node = tmp;
6368
6369
0
  if (node == NULL)
6370
0
      return(0);
6371
0
    }
6372
6373
0
    switch (node->type) {
6374
0
  case XML_COMMENT_NODE:
6375
0
  case XML_PI_NODE:
6376
0
  case XML_CDATA_SECTION_NODE:
6377
0
  case XML_TEXT_NODE:
6378
0
      string = node->content;
6379
0
      if (string == NULL)
6380
0
    return(0);
6381
0
      if (string[0] == 0)
6382
0
    return(0);
6383
0
      return(((unsigned int) string[0]) +
6384
0
       (((unsigned int) string[1]) << 8));
6385
0
  case XML_NAMESPACE_DECL:
6386
0
      string = ((xmlNsPtr)node)->href;
6387
0
      if (string == NULL)
6388
0
    return(0);
6389
0
      if (string[0] == 0)
6390
0
    return(0);
6391
0
      return(((unsigned int) string[0]) +
6392
0
       (((unsigned int) string[1]) << 8));
6393
0
  case XML_ATTRIBUTE_NODE:
6394
0
      tmp = ((xmlAttrPtr) node)->children;
6395
0
      break;
6396
0
  case XML_ELEMENT_NODE:
6397
0
      tmp = node->children;
6398
0
      break;
6399
0
  default:
6400
0
      return(0);
6401
0
    }
6402
0
    while (tmp != NULL) {
6403
0
  switch (tmp->type) {
6404
0
      case XML_CDATA_SECTION_NODE:
6405
0
      case XML_TEXT_NODE:
6406
0
    string = tmp->content;
6407
0
    break;
6408
0
      default:
6409
0
                string = NULL;
6410
0
    break;
6411
0
  }
6412
0
  if ((string != NULL) && (string[0] != 0)) {
6413
0
      if (len == 1) {
6414
0
    return(ret + (((unsigned int) string[0]) << 8));
6415
0
      }
6416
0
      if (string[1] == 0) {
6417
0
    len = 1;
6418
0
    ret = (unsigned int) string[0];
6419
0
      } else {
6420
0
    return(((unsigned int) string[0]) +
6421
0
           (((unsigned int) string[1]) << 8));
6422
0
      }
6423
0
  }
6424
  /*
6425
   * Skip to next node
6426
   */
6427
0
  if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6428
0
      if (tmp->children->type != XML_ENTITY_DECL) {
6429
0
    tmp = tmp->children;
6430
0
    continue;
6431
0
      }
6432
0
  }
6433
0
  if (tmp == node)
6434
0
      break;
6435
6436
0
  if (tmp->next != NULL) {
6437
0
      tmp = tmp->next;
6438
0
      continue;
6439
0
  }
6440
6441
0
  do {
6442
0
      tmp = tmp->parent;
6443
0
      if (tmp == NULL)
6444
0
    break;
6445
0
      if (tmp == node) {
6446
0
    tmp = NULL;
6447
0
    break;
6448
0
      }
6449
0
      if (tmp->next != NULL) {
6450
0
    tmp = tmp->next;
6451
0
    break;
6452
0
      }
6453
0
  } while (tmp != NULL);
6454
0
    }
6455
0
    return(ret);
6456
0
}
6457
6458
/**
6459
 * xmlXPathStringHash:
6460
 * @string:  a string
6461
 *
6462
 * Function computing the beginning of the string value of the node,
6463
 * used to speed up comparisons
6464
 *
6465
 * Returns an int usable as a hash
6466
 */
6467
static unsigned int
6468
0
xmlXPathStringHash(const xmlChar * string) {
6469
0
    if (string == NULL)
6470
0
  return((unsigned int) 0);
6471
0
    if (string[0] == 0)
6472
0
  return(0);
6473
0
    return(((unsigned int) string[0]) +
6474
0
     (((unsigned int) string[1]) << 8));
6475
0
}
6476
6477
/**
6478
 * xmlXPathCompareNodeSetFloat:
6479
 * @ctxt:  the XPath Parser context
6480
 * @inf:  less than (1) or greater than (0)
6481
 * @strict:  is the comparison strict
6482
 * @arg:  the node set
6483
 * @f:  the value
6484
 *
6485
 * Implement the compare operation between a nodeset and a number
6486
 *     @ns < @val    (1, 1, ...
6487
 *     @ns <= @val   (1, 0, ...
6488
 *     @ns > @val    (0, 1, ...
6489
 *     @ns >= @val   (0, 0, ...
6490
 *
6491
 * If one object to be compared is a node-set and the other is a number,
6492
 * then the comparison will be true if and only if there is a node in the
6493
 * node-set such that the result of performing the comparison on the number
6494
 * to be compared and on the result of converting the string-value of that
6495
 * node to a number using the number function is true.
6496
 *
6497
 * Returns 0 or 1 depending on the results of the test.
6498
 */
6499
static int
6500
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6501
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6502
0
    int i, ret = 0;
6503
0
    xmlNodeSetPtr ns;
6504
0
    xmlChar *str2;
6505
6506
0
    if ((f == NULL) || (arg == NULL) ||
6507
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6508
0
  xmlXPathReleaseObject(ctxt->context, arg);
6509
0
  xmlXPathReleaseObject(ctxt->context, f);
6510
0
        return(0);
6511
0
    }
6512
0
    ns = arg->nodesetval;
6513
0
    if (ns != NULL) {
6514
0
  for (i = 0;i < ns->nodeNr;i++) {
6515
0
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6516
0
       if (str2 != NULL) {
6517
0
     valuePush(ctxt,
6518
0
         xmlXPathCacheNewString(ctxt->context, str2));
6519
0
     xmlFree(str2);
6520
0
     xmlXPathNumberFunction(ctxt, 1);
6521
0
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6522
0
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6523
0
     if (ret)
6524
0
         break;
6525
0
       }
6526
0
  }
6527
0
    }
6528
0
    xmlXPathReleaseObject(ctxt->context, arg);
6529
0
    xmlXPathReleaseObject(ctxt->context, f);
6530
0
    return(ret);
6531
0
}
6532
6533
/**
6534
 * xmlXPathCompareNodeSetString:
6535
 * @ctxt:  the XPath Parser context
6536
 * @inf:  less than (1) or greater than (0)
6537
 * @strict:  is the comparison strict
6538
 * @arg:  the node set
6539
 * @s:  the value
6540
 *
6541
 * Implement the compare operation between a nodeset and a string
6542
 *     @ns < @val    (1, 1, ...
6543
 *     @ns <= @val   (1, 0, ...
6544
 *     @ns > @val    (0, 1, ...
6545
 *     @ns >= @val   (0, 0, ...
6546
 *
6547
 * If one object to be compared is a node-set and the other is a string,
6548
 * then the comparison will be true if and only if there is a node in
6549
 * the node-set such that the result of performing the comparison on the
6550
 * string-value of the node and the other string is true.
6551
 *
6552
 * Returns 0 or 1 depending on the results of the test.
6553
 */
6554
static int
6555
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6556
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6557
0
    int i, ret = 0;
6558
0
    xmlNodeSetPtr ns;
6559
0
    xmlChar *str2;
6560
6561
0
    if ((s == NULL) || (arg == NULL) ||
6562
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6563
0
  xmlXPathReleaseObject(ctxt->context, arg);
6564
0
  xmlXPathReleaseObject(ctxt->context, s);
6565
0
        return(0);
6566
0
    }
6567
0
    ns = arg->nodesetval;
6568
0
    if (ns != NULL) {
6569
0
  for (i = 0;i < ns->nodeNr;i++) {
6570
0
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6571
0
       if (str2 != NULL) {
6572
0
     valuePush(ctxt,
6573
0
         xmlXPathCacheNewString(ctxt->context, str2));
6574
0
     xmlFree(str2);
6575
0
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6576
0
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6577
0
     if (ret)
6578
0
         break;
6579
0
       }
6580
0
  }
6581
0
    }
6582
0
    xmlXPathReleaseObject(ctxt->context, arg);
6583
0
    xmlXPathReleaseObject(ctxt->context, s);
6584
0
    return(ret);
6585
0
}
6586
6587
/**
6588
 * xmlXPathCompareNodeSets:
6589
 * @inf:  less than (1) or greater than (0)
6590
 * @strict:  is the comparison strict
6591
 * @arg1:  the first node set object
6592
 * @arg2:  the second node set object
6593
 *
6594
 * Implement the compare operation on nodesets:
6595
 *
6596
 * If both objects to be compared are node-sets, then the comparison
6597
 * will be true if and only if there is a node in the first node-set
6598
 * and a node in the second node-set such that the result of performing
6599
 * the comparison on the string-values of the two nodes is true.
6600
 * ....
6601
 * When neither object to be compared is a node-set and the operator
6602
 * is <=, <, >= or >, then the objects are compared by converting both
6603
 * objects to numbers and comparing the numbers according to IEEE 754.
6604
 * ....
6605
 * The number function converts its argument to a number as follows:
6606
 *  - a string that consists of optional whitespace followed by an
6607
 *    optional minus sign followed by a Number followed by whitespace
6608
 *    is converted to the IEEE 754 number that is nearest (according
6609
 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6610
 *    represented by the string; any other string is converted to NaN
6611
 *
6612
 * Conclusion all nodes need to be converted first to their string value
6613
 * and then the comparison must be done when possible
6614
 */
6615
static int
6616
xmlXPathCompareNodeSets(int inf, int strict,
6617
0
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6618
0
    int i, j, init = 0;
6619
0
    double val1;
6620
0
    double *values2;
6621
0
    int ret = 0;
6622
0
    xmlNodeSetPtr ns1;
6623
0
    xmlNodeSetPtr ns2;
6624
6625
0
    if ((arg1 == NULL) ||
6626
0
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6627
0
  xmlXPathFreeObject(arg2);
6628
0
        return(0);
6629
0
    }
6630
0
    if ((arg2 == NULL) ||
6631
0
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6632
0
  xmlXPathFreeObject(arg1);
6633
0
  xmlXPathFreeObject(arg2);
6634
0
        return(0);
6635
0
    }
6636
6637
0
    ns1 = arg1->nodesetval;
6638
0
    ns2 = arg2->nodesetval;
6639
6640
0
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6641
0
  xmlXPathFreeObject(arg1);
6642
0
  xmlXPathFreeObject(arg2);
6643
0
  return(0);
6644
0
    }
6645
0
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6646
0
  xmlXPathFreeObject(arg1);
6647
0
  xmlXPathFreeObject(arg2);
6648
0
  return(0);
6649
0
    }
6650
6651
0
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6652
0
    if (values2 == NULL) {
6653
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6654
0
  xmlXPathFreeObject(arg1);
6655
0
  xmlXPathFreeObject(arg2);
6656
0
  return(0);
6657
0
    }
6658
0
    for (i = 0;i < ns1->nodeNr;i++) {
6659
0
  val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6660
0
  if (xmlXPathIsNaN(val1))
6661
0
      continue;
6662
0
  for (j = 0;j < ns2->nodeNr;j++) {
6663
0
      if (init == 0) {
6664
0
    values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6665
0
      }
6666
0
      if (xmlXPathIsNaN(values2[j]))
6667
0
    continue;
6668
0
      if (inf && strict)
6669
0
    ret = (val1 < values2[j]);
6670
0
      else if (inf && !strict)
6671
0
    ret = (val1 <= values2[j]);
6672
0
      else if (!inf && strict)
6673
0
    ret = (val1 > values2[j]);
6674
0
      else if (!inf && !strict)
6675
0
    ret = (val1 >= values2[j]);
6676
0
      if (ret)
6677
0
    break;
6678
0
  }
6679
0
  if (ret)
6680
0
      break;
6681
0
  init = 1;
6682
0
    }
6683
0
    xmlFree(values2);
6684
0
    xmlXPathFreeObject(arg1);
6685
0
    xmlXPathFreeObject(arg2);
6686
0
    return(ret);
6687
0
}
6688
6689
/**
6690
 * xmlXPathCompareNodeSetValue:
6691
 * @ctxt:  the XPath Parser context
6692
 * @inf:  less than (1) or greater than (0)
6693
 * @strict:  is the comparison strict
6694
 * @arg:  the node set
6695
 * @val:  the value
6696
 *
6697
 * Implement the compare operation between a nodeset and a value
6698
 *     @ns < @val    (1, 1, ...
6699
 *     @ns <= @val   (1, 0, ...
6700
 *     @ns > @val    (0, 1, ...
6701
 *     @ns >= @val   (0, 0, ...
6702
 *
6703
 * If one object to be compared is a node-set and the other is a boolean,
6704
 * then the comparison will be true if and only if the result of performing
6705
 * the comparison on the boolean and on the result of converting
6706
 * the node-set to a boolean using the boolean function is true.
6707
 *
6708
 * Returns 0 or 1 depending on the results of the test.
6709
 */
6710
static int
6711
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6712
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6713
0
    if ((val == NULL) || (arg == NULL) ||
6714
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6715
0
        return(0);
6716
6717
0
    switch(val->type) {
6718
0
        case XPATH_NUMBER:
6719
0
      return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6720
0
        case XPATH_NODESET:
6721
0
        case XPATH_XSLT_TREE:
6722
0
      return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6723
0
        case XPATH_STRING:
6724
0
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6725
0
        case XPATH_BOOLEAN:
6726
0
      valuePush(ctxt, arg);
6727
0
      xmlXPathBooleanFunction(ctxt, 1);
6728
0
      valuePush(ctxt, val);
6729
0
      return(xmlXPathCompareValues(ctxt, inf, strict));
6730
0
  default:
6731
0
            xmlGenericError(xmlGenericErrorContext,
6732
0
                    "xmlXPathCompareNodeSetValue: Can't compare node set "
6733
0
                    "and object of type %d\n",
6734
0
                    val->type);
6735
0
            xmlXPathReleaseObject(ctxt->context, arg);
6736
0
            xmlXPathReleaseObject(ctxt->context, val);
6737
0
            XP_ERROR0(XPATH_INVALID_TYPE);
6738
0
    }
6739
0
    return(0);
6740
0
}
6741
6742
/**
6743
 * xmlXPathEqualNodeSetString:
6744
 * @arg:  the nodeset object argument
6745
 * @str:  the string to compare to.
6746
 * @neq:  flag to show whether for '=' (0) or '!=' (1)
6747
 *
6748
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6749
 * If one object to be compared is a node-set and the other is a string,
6750
 * then the comparison will be true if and only if there is a node in
6751
 * the node-set such that the result of performing the comparison on the
6752
 * string-value of the node and the other string is true.
6753
 *
6754
 * Returns 0 or 1 depending on the results of the test.
6755
 */
6756
static int
6757
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6758
0
{
6759
0
    int i;
6760
0
    xmlNodeSetPtr ns;
6761
0
    xmlChar *str2;
6762
0
    unsigned int hash;
6763
6764
0
    if ((str == NULL) || (arg == NULL) ||
6765
0
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6766
0
        return (0);
6767
0
    ns = arg->nodesetval;
6768
    /*
6769
     * A NULL nodeset compared with a string is always false
6770
     * (since there is no node equal, and no node not equal)
6771
     */
6772
0
    if ((ns == NULL) || (ns->nodeNr <= 0) )
6773
0
        return (0);
6774
0
    hash = xmlXPathStringHash(str);
6775
0
    for (i = 0; i < ns->nodeNr; i++) {
6776
0
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6777
0
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
6778
0
            if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6779
0
                xmlFree(str2);
6780
0
    if (neq)
6781
0
        continue;
6782
0
                return (1);
6783
0
      } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6784
0
    if (neq)
6785
0
        continue;
6786
0
                return (1);
6787
0
            } else if (neq) {
6788
0
    if (str2 != NULL)
6789
0
        xmlFree(str2);
6790
0
    return (1);
6791
0
      }
6792
0
            if (str2 != NULL)
6793
0
                xmlFree(str2);
6794
0
        } else if (neq)
6795
0
      return (1);
6796
0
    }
6797
0
    return (0);
6798
0
}
6799
6800
/**
6801
 * xmlXPathEqualNodeSetFloat:
6802
 * @arg:  the nodeset object argument
6803
 * @f:  the float to compare to
6804
 * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6805
 *
6806
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6807
 * If one object to be compared is a node-set and the other is a number,
6808
 * then the comparison will be true if and only if there is a node in
6809
 * the node-set such that the result of performing the comparison on the
6810
 * number to be compared and on the result of converting the string-value
6811
 * of that node to a number using the number function is true.
6812
 *
6813
 * Returns 0 or 1 depending on the results of the test.
6814
 */
6815
static int
6816
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6817
0
    xmlXPathObjectPtr arg, double f, int neq) {
6818
0
  int i, ret=0;
6819
0
  xmlNodeSetPtr ns;
6820
0
  xmlChar *str2;
6821
0
  xmlXPathObjectPtr val;
6822
0
  double v;
6823
6824
0
    if ((arg == NULL) ||
6825
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6826
0
        return(0);
6827
6828
0
    ns = arg->nodesetval;
6829
0
    if (ns != NULL) {
6830
0
  for (i=0;i<ns->nodeNr;i++) {
6831
0
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6832
0
      if (str2 != NULL) {
6833
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6834
0
    xmlFree(str2);
6835
0
    xmlXPathNumberFunction(ctxt, 1);
6836
0
    val = valuePop(ctxt);
6837
0
    v = val->floatval;
6838
0
    xmlXPathReleaseObject(ctxt->context, val);
6839
0
    if (!xmlXPathIsNaN(v)) {
6840
0
        if ((!neq) && (v==f)) {
6841
0
      ret = 1;
6842
0
      break;
6843
0
        } else if ((neq) && (v!=f)) {
6844
0
      ret = 1;
6845
0
      break;
6846
0
        }
6847
0
    } else { /* NaN is unequal to any value */
6848
0
        if (neq)
6849
0
      ret = 1;
6850
0
    }
6851
0
      }
6852
0
  }
6853
0
    }
6854
6855
0
    return(ret);
6856
0
}
6857
6858
6859
/**
6860
 * xmlXPathEqualNodeSets:
6861
 * @arg1:  first nodeset object argument
6862
 * @arg2:  second nodeset object argument
6863
 * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6864
 *
6865
 * Implement the equal / not equal operation on XPath nodesets:
6866
 * @arg1 == @arg2  or  @arg1 != @arg2
6867
 * If both objects to be compared are node-sets, then the comparison
6868
 * will be true if and only if there is a node in the first node-set and
6869
 * a node in the second node-set such that the result of performing the
6870
 * comparison on the string-values of the two nodes is true.
6871
 *
6872
 * (needless to say, this is a costly operation)
6873
 *
6874
 * Returns 0 or 1 depending on the results of the test.
6875
 */
6876
static int
6877
0
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6878
0
    int i, j;
6879
0
    unsigned int *hashs1;
6880
0
    unsigned int *hashs2;
6881
0
    xmlChar **values1;
6882
0
    xmlChar **values2;
6883
0
    int ret = 0;
6884
0
    xmlNodeSetPtr ns1;
6885
0
    xmlNodeSetPtr ns2;
6886
6887
0
    if ((arg1 == NULL) ||
6888
0
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6889
0
        return(0);
6890
0
    if ((arg2 == NULL) ||
6891
0
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6892
0
        return(0);
6893
6894
0
    ns1 = arg1->nodesetval;
6895
0
    ns2 = arg2->nodesetval;
6896
6897
0
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6898
0
  return(0);
6899
0
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6900
0
  return(0);
6901
6902
    /*
6903
     * for equal, check if there is a node pertaining to both sets
6904
     */
6905
0
    if (neq == 0)
6906
0
  for (i = 0;i < ns1->nodeNr;i++)
6907
0
      for (j = 0;j < ns2->nodeNr;j++)
6908
0
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
6909
0
        return(1);
6910
6911
0
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6912
0
    if (values1 == NULL) {
6913
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6914
0
  return(0);
6915
0
    }
6916
0
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6917
0
    if (hashs1 == NULL) {
6918
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6919
0
  xmlFree(values1);
6920
0
  return(0);
6921
0
    }
6922
0
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6923
0
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6924
0
    if (values2 == NULL) {
6925
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6926
0
  xmlFree(hashs1);
6927
0
  xmlFree(values1);
6928
0
  return(0);
6929
0
    }
6930
0
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6931
0
    if (hashs2 == NULL) {
6932
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6933
0
  xmlFree(hashs1);
6934
0
  xmlFree(values1);
6935
0
  xmlFree(values2);
6936
0
  return(0);
6937
0
    }
6938
0
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6939
0
    for (i = 0;i < ns1->nodeNr;i++) {
6940
0
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6941
0
  for (j = 0;j < ns2->nodeNr;j++) {
6942
0
      if (i == 0)
6943
0
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6944
0
      if (hashs1[i] != hashs2[j]) {
6945
0
    if (neq) {
6946
0
        ret = 1;
6947
0
        break;
6948
0
    }
6949
0
      }
6950
0
      else {
6951
0
    if (values1[i] == NULL)
6952
0
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6953
0
    if (values2[j] == NULL)
6954
0
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6955
0
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6956
0
    if (ret)
6957
0
        break;
6958
0
      }
6959
0
  }
6960
0
  if (ret)
6961
0
      break;
6962
0
    }
6963
0
    for (i = 0;i < ns1->nodeNr;i++)
6964
0
  if (values1[i] != NULL)
6965
0
      xmlFree(values1[i]);
6966
0
    for (j = 0;j < ns2->nodeNr;j++)
6967
0
  if (values2[j] != NULL)
6968
0
      xmlFree(values2[j]);
6969
0
    xmlFree(values1);
6970
0
    xmlFree(values2);
6971
0
    xmlFree(hashs1);
6972
0
    xmlFree(hashs2);
6973
0
    return(ret);
6974
0
}
6975
6976
static int
6977
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6978
0
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6979
0
    int ret = 0;
6980
    /*
6981
     *At this point we are assured neither arg1 nor arg2
6982
     *is a nodeset, so we can just pick the appropriate routine.
6983
     */
6984
0
    switch (arg1->type) {
6985
0
        case XPATH_UNDEFINED:
6986
#ifdef DEBUG_EXPR
6987
      xmlGenericError(xmlGenericErrorContext,
6988
        "Equal: undefined\n");
6989
#endif
6990
0
      break;
6991
0
        case XPATH_BOOLEAN:
6992
0
      switch (arg2->type) {
6993
0
          case XPATH_UNDEFINED:
6994
#ifdef DEBUG_EXPR
6995
        xmlGenericError(xmlGenericErrorContext,
6996
          "Equal: undefined\n");
6997
#endif
6998
0
        break;
6999
0
    case XPATH_BOOLEAN:
7000
#ifdef DEBUG_EXPR
7001
        xmlGenericError(xmlGenericErrorContext,
7002
          "Equal: %d boolean %d \n",
7003
          arg1->boolval, arg2->boolval);
7004
#endif
7005
0
        ret = (arg1->boolval == arg2->boolval);
7006
0
        break;
7007
0
    case XPATH_NUMBER:
7008
0
        ret = (arg1->boolval ==
7009
0
         xmlXPathCastNumberToBoolean(arg2->floatval));
7010
0
        break;
7011
0
    case XPATH_STRING:
7012
0
        if ((arg2->stringval == NULL) ||
7013
0
      (arg2->stringval[0] == 0)) ret = 0;
7014
0
        else
7015
0
      ret = 1;
7016
0
        ret = (arg1->boolval == ret);
7017
0
        break;
7018
0
    case XPATH_USERS:
7019
0
    case XPATH_POINT:
7020
0
    case XPATH_RANGE:
7021
0
    case XPATH_LOCATIONSET:
7022
0
        TODO
7023
0
        break;
7024
0
    case XPATH_NODESET:
7025
0
    case XPATH_XSLT_TREE:
7026
0
        break;
7027
0
      }
7028
0
      break;
7029
0
        case XPATH_NUMBER:
7030
0
      switch (arg2->type) {
7031
0
          case XPATH_UNDEFINED:
7032
#ifdef DEBUG_EXPR
7033
        xmlGenericError(xmlGenericErrorContext,
7034
          "Equal: undefined\n");
7035
#endif
7036
0
        break;
7037
0
    case XPATH_BOOLEAN:
7038
0
        ret = (arg2->boolval==
7039
0
         xmlXPathCastNumberToBoolean(arg1->floatval));
7040
0
        break;
7041
0
    case XPATH_STRING:
7042
0
        valuePush(ctxt, arg2);
7043
0
        xmlXPathNumberFunction(ctxt, 1);
7044
0
        arg2 = valuePop(ctxt);
7045
                    /* Falls through. */
7046
0
    case XPATH_NUMBER:
7047
        /* Hand check NaN and Infinity equalities */
7048
0
        if (xmlXPathIsNaN(arg1->floatval) ||
7049
0
          xmlXPathIsNaN(arg2->floatval)) {
7050
0
            ret = 0;
7051
0
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7052
0
            if (xmlXPathIsInf(arg2->floatval) == 1)
7053
0
          ret = 1;
7054
0
      else
7055
0
          ret = 0;
7056
0
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7057
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
7058
0
          ret = 1;
7059
0
      else
7060
0
          ret = 0;
7061
0
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7062
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
7063
0
          ret = 1;
7064
0
      else
7065
0
          ret = 0;
7066
0
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7067
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
7068
0
          ret = 1;
7069
0
      else
7070
0
          ret = 0;
7071
0
        } else {
7072
0
            ret = (arg1->floatval == arg2->floatval);
7073
0
        }
7074
0
        break;
7075
0
    case XPATH_USERS:
7076
0
    case XPATH_POINT:
7077
0
    case XPATH_RANGE:
7078
0
    case XPATH_LOCATIONSET:
7079
0
        TODO
7080
0
        break;
7081
0
    case XPATH_NODESET:
7082
0
    case XPATH_XSLT_TREE:
7083
0
        break;
7084
0
      }
7085
0
      break;
7086
0
        case XPATH_STRING:
7087
0
      switch (arg2->type) {
7088
0
          case XPATH_UNDEFINED:
7089
#ifdef DEBUG_EXPR
7090
        xmlGenericError(xmlGenericErrorContext,
7091
          "Equal: undefined\n");
7092
#endif
7093
0
        break;
7094
0
    case XPATH_BOOLEAN:
7095
0
        if ((arg1->stringval == NULL) ||
7096
0
      (arg1->stringval[0] == 0)) ret = 0;
7097
0
        else
7098
0
      ret = 1;
7099
0
        ret = (arg2->boolval == ret);
7100
0
        break;
7101
0
    case XPATH_STRING:
7102
0
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7103
0
        break;
7104
0
    case XPATH_NUMBER:
7105
0
        valuePush(ctxt, arg1);
7106
0
        xmlXPathNumberFunction(ctxt, 1);
7107
0
        arg1 = valuePop(ctxt);
7108
        /* Hand check NaN and Infinity equalities */
7109
0
        if (xmlXPathIsNaN(arg1->floatval) ||
7110
0
          xmlXPathIsNaN(arg2->floatval)) {
7111
0
            ret = 0;
7112
0
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7113
0
      if (xmlXPathIsInf(arg2->floatval) == 1)
7114
0
          ret = 1;
7115
0
      else
7116
0
          ret = 0;
7117
0
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7118
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
7119
0
          ret = 1;
7120
0
      else
7121
0
          ret = 0;
7122
0
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7123
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
7124
0
          ret = 1;
7125
0
      else
7126
0
          ret = 0;
7127
0
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7128
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
7129
0
          ret = 1;
7130
0
      else
7131
0
          ret = 0;
7132
0
        } else {
7133
0
            ret = (arg1->floatval == arg2->floatval);
7134
0
        }
7135
0
        break;
7136
0
    case XPATH_USERS:
7137
0
    case XPATH_POINT:
7138
0
    case XPATH_RANGE:
7139
0
    case XPATH_LOCATIONSET:
7140
0
        TODO
7141
0
        break;
7142
0
    case XPATH_NODESET:
7143
0
    case XPATH_XSLT_TREE:
7144
0
        break;
7145
0
      }
7146
0
      break;
7147
0
        case XPATH_USERS:
7148
0
  case XPATH_POINT:
7149
0
  case XPATH_RANGE:
7150
0
  case XPATH_LOCATIONSET:
7151
0
      TODO
7152
0
      break;
7153
0
  case XPATH_NODESET:
7154
0
  case XPATH_XSLT_TREE:
7155
0
      break;
7156
0
    }
7157
0
    xmlXPathReleaseObject(ctxt->context, arg1);
7158
0
    xmlXPathReleaseObject(ctxt->context, arg2);
7159
0
    return(ret);
7160
0
}
7161
7162
/**
7163
 * xmlXPathEqualValues:
7164
 * @ctxt:  the XPath Parser context
7165
 *
7166
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7167
 *
7168
 * Returns 0 or 1 depending on the results of the test.
7169
 */
7170
int
7171
0
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7172
0
    xmlXPathObjectPtr arg1, arg2, argtmp;
7173
0
    int ret = 0;
7174
7175
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7176
0
    arg2 = valuePop(ctxt);
7177
0
    arg1 = valuePop(ctxt);
7178
0
    if ((arg1 == NULL) || (arg2 == NULL)) {
7179
0
  if (arg1 != NULL)
7180
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7181
0
  else
7182
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7183
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7184
0
    }
7185
7186
0
    if (arg1 == arg2) {
7187
#ifdef DEBUG_EXPR
7188
        xmlGenericError(xmlGenericErrorContext,
7189
    "Equal: by pointer\n");
7190
#endif
7191
0
  xmlXPathFreeObject(arg1);
7192
0
        return(1);
7193
0
    }
7194
7195
    /*
7196
     *If either argument is a nodeset, it's a 'special case'
7197
     */
7198
0
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7199
0
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7200
  /*
7201
   *Hack it to assure arg1 is the nodeset
7202
   */
7203
0
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7204
0
    argtmp = arg2;
7205
0
    arg2 = arg1;
7206
0
    arg1 = argtmp;
7207
0
  }
7208
0
  switch (arg2->type) {
7209
0
      case XPATH_UNDEFINED:
7210
#ifdef DEBUG_EXPR
7211
    xmlGenericError(xmlGenericErrorContext,
7212
      "Equal: undefined\n");
7213
#endif
7214
0
    break;
7215
0
      case XPATH_NODESET:
7216
0
      case XPATH_XSLT_TREE:
7217
0
    ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7218
0
    break;
7219
0
      case XPATH_BOOLEAN:
7220
0
    if ((arg1->nodesetval == NULL) ||
7221
0
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7222
0
    else
7223
0
        ret = 1;
7224
0
    ret = (ret == arg2->boolval);
7225
0
    break;
7226
0
      case XPATH_NUMBER:
7227
0
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7228
0
    break;
7229
0
      case XPATH_STRING:
7230
0
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7231
0
    break;
7232
0
      case XPATH_USERS:
7233
0
      case XPATH_POINT:
7234
0
      case XPATH_RANGE:
7235
0
      case XPATH_LOCATIONSET:
7236
0
    TODO
7237
0
    break;
7238
0
  }
7239
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7240
0
  xmlXPathReleaseObject(ctxt->context, arg2);
7241
0
  return(ret);
7242
0
    }
7243
7244
0
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7245
0
}
7246
7247
/**
7248
 * xmlXPathNotEqualValues:
7249
 * @ctxt:  the XPath Parser context
7250
 *
7251
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7252
 *
7253
 * Returns 0 or 1 depending on the results of the test.
7254
 */
7255
int
7256
0
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7257
0
    xmlXPathObjectPtr arg1, arg2, argtmp;
7258
0
    int ret = 0;
7259
7260
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7261
0
    arg2 = valuePop(ctxt);
7262
0
    arg1 = valuePop(ctxt);
7263
0
    if ((arg1 == NULL) || (arg2 == NULL)) {
7264
0
  if (arg1 != NULL)
7265
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7266
0
  else
7267
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7268
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7269
0
    }
7270
7271
0
    if (arg1 == arg2) {
7272
#ifdef DEBUG_EXPR
7273
        xmlGenericError(xmlGenericErrorContext,
7274
    "NotEqual: by pointer\n");
7275
#endif
7276
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7277
0
        return(0);
7278
0
    }
7279
7280
    /*
7281
     *If either argument is a nodeset, it's a 'special case'
7282
     */
7283
0
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7284
0
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7285
  /*
7286
   *Hack it to assure arg1 is the nodeset
7287
   */
7288
0
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7289
0
    argtmp = arg2;
7290
0
    arg2 = arg1;
7291
0
    arg1 = argtmp;
7292
0
  }
7293
0
  switch (arg2->type) {
7294
0
      case XPATH_UNDEFINED:
7295
#ifdef DEBUG_EXPR
7296
    xmlGenericError(xmlGenericErrorContext,
7297
      "NotEqual: undefined\n");
7298
#endif
7299
0
    break;
7300
0
      case XPATH_NODESET:
7301
0
      case XPATH_XSLT_TREE:
7302
0
    ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7303
0
    break;
7304
0
      case XPATH_BOOLEAN:
7305
0
    if ((arg1->nodesetval == NULL) ||
7306
0
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7307
0
    else
7308
0
        ret = 1;
7309
0
    ret = (ret != arg2->boolval);
7310
0
    break;
7311
0
      case XPATH_NUMBER:
7312
0
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7313
0
    break;
7314
0
      case XPATH_STRING:
7315
0
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7316
0
    break;
7317
0
      case XPATH_USERS:
7318
0
      case XPATH_POINT:
7319
0
      case XPATH_RANGE:
7320
0
      case XPATH_LOCATIONSET:
7321
0
    TODO
7322
0
    break;
7323
0
  }
7324
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7325
0
  xmlXPathReleaseObject(ctxt->context, arg2);
7326
0
  return(ret);
7327
0
    }
7328
7329
0
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7330
0
}
7331
7332
/**
7333
 * xmlXPathCompareValues:
7334
 * @ctxt:  the XPath Parser context
7335
 * @inf:  less than (1) or greater than (0)
7336
 * @strict:  is the comparison strict
7337
 *
7338
 * Implement the compare operation on XPath objects:
7339
 *     @arg1 < @arg2    (1, 1, ...
7340
 *     @arg1 <= @arg2   (1, 0, ...
7341
 *     @arg1 > @arg2    (0, 1, ...
7342
 *     @arg1 >= @arg2   (0, 0, ...
7343
 *
7344
 * When neither object to be compared is a node-set and the operator is
7345
 * <=, <, >=, >, then the objects are compared by converted both objects
7346
 * to numbers and comparing the numbers according to IEEE 754. The <
7347
 * comparison will be true if and only if the first number is less than the
7348
 * second number. The <= comparison will be true if and only if the first
7349
 * number is less than or equal to the second number. The > comparison
7350
 * will be true if and only if the first number is greater than the second
7351
 * number. The >= comparison will be true if and only if the first number
7352
 * is greater than or equal to the second number.
7353
 *
7354
 * Returns 1 if the comparison succeeded, 0 if it failed
7355
 */
7356
int
7357
0
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7358
0
    int ret = 0, arg1i = 0, arg2i = 0;
7359
0
    xmlXPathObjectPtr arg1, arg2;
7360
7361
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7362
0
    arg2 = valuePop(ctxt);
7363
0
    arg1 = valuePop(ctxt);
7364
0
    if ((arg1 == NULL) || (arg2 == NULL)) {
7365
0
  if (arg1 != NULL)
7366
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7367
0
  else
7368
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7369
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7370
0
    }
7371
7372
0
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7373
0
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7374
  /*
7375
   * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7376
   * are not freed from within this routine; they will be freed from the
7377
   * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7378
   */
7379
0
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7380
0
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7381
0
      ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7382
0
  } else {
7383
0
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7384
0
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7385
0
                                arg1, arg2);
7386
0
      } else {
7387
0
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7388
0
                                arg2, arg1);
7389
0
      }
7390
0
  }
7391
0
  return(ret);
7392
0
    }
7393
7394
0
    if (arg1->type != XPATH_NUMBER) {
7395
0
  valuePush(ctxt, arg1);
7396
0
  xmlXPathNumberFunction(ctxt, 1);
7397
0
  arg1 = valuePop(ctxt);
7398
0
    }
7399
0
    if (arg1->type != XPATH_NUMBER) {
7400
0
  xmlXPathFreeObject(arg1);
7401
0
  xmlXPathFreeObject(arg2);
7402
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7403
0
    }
7404
0
    if (arg2->type != XPATH_NUMBER) {
7405
0
  valuePush(ctxt, arg2);
7406
0
  xmlXPathNumberFunction(ctxt, 1);
7407
0
  arg2 = valuePop(ctxt);
7408
0
    }
7409
0
    if (arg2->type != XPATH_NUMBER) {
7410
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7411
0
  xmlXPathReleaseObject(ctxt->context, arg2);
7412
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7413
0
    }
7414
    /*
7415
     * Add tests for infinity and nan
7416
     * => feedback on 3.4 for Inf and NaN
7417
     */
7418
    /* Hand check NaN and Infinity comparisons */
7419
0
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7420
0
  ret=0;
7421
0
    } else {
7422
0
  arg1i=xmlXPathIsInf(arg1->floatval);
7423
0
  arg2i=xmlXPathIsInf(arg2->floatval);
7424
0
  if (inf && strict) {
7425
0
      if ((arg1i == -1 && arg2i != -1) ||
7426
0
    (arg2i == 1 && arg1i != 1)) {
7427
0
    ret = 1;
7428
0
      } else if (arg1i == 0 && arg2i == 0) {
7429
0
    ret = (arg1->floatval < arg2->floatval);
7430
0
      } else {
7431
0
    ret = 0;
7432
0
      }
7433
0
  }
7434
0
  else if (inf && !strict) {
7435
0
      if (arg1i == -1 || arg2i == 1) {
7436
0
    ret = 1;
7437
0
      } else if (arg1i == 0 && arg2i == 0) {
7438
0
    ret = (arg1->floatval <= arg2->floatval);
7439
0
      } else {
7440
0
    ret = 0;
7441
0
      }
7442
0
  }
7443
0
  else if (!inf && strict) {
7444
0
      if ((arg1i == 1 && arg2i != 1) ||
7445
0
    (arg2i == -1 && arg1i != -1)) {
7446
0
    ret = 1;
7447
0
      } else if (arg1i == 0 && arg2i == 0) {
7448
0
    ret = (arg1->floatval > arg2->floatval);
7449
0
      } else {
7450
0
    ret = 0;
7451
0
      }
7452
0
  }
7453
0
  else if (!inf && !strict) {
7454
0
      if (arg1i == 1 || arg2i == -1) {
7455
0
    ret = 1;
7456
0
      } else if (arg1i == 0 && arg2i == 0) {
7457
0
    ret = (arg1->floatval >= arg2->floatval);
7458
0
      } else {
7459
0
    ret = 0;
7460
0
      }
7461
0
  }
7462
0
    }
7463
0
    xmlXPathReleaseObject(ctxt->context, arg1);
7464
0
    xmlXPathReleaseObject(ctxt->context, arg2);
7465
0
    return(ret);
7466
0
}
7467
7468
/**
7469
 * xmlXPathValueFlipSign:
7470
 * @ctxt:  the XPath Parser context
7471
 *
7472
 * Implement the unary - operation on an XPath object
7473
 * The numeric operators convert their operands to numbers as if
7474
 * by calling the number function.
7475
 */
7476
void
7477
0
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7478
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7479
0
    CAST_TO_NUMBER;
7480
0
    CHECK_TYPE(XPATH_NUMBER);
7481
0
    if (xmlXPathIsNaN(ctxt->value->floatval))
7482
0
        ctxt->value->floatval=xmlXPathNAN;
7483
0
    else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7484
0
        ctxt->value->floatval=xmlXPathNINF;
7485
0
    else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7486
0
        ctxt->value->floatval=xmlXPathPINF;
7487
0
    else if (ctxt->value->floatval == 0) {
7488
0
        if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7489
0
      ctxt->value->floatval = xmlXPathNZERO;
7490
0
  else
7491
0
      ctxt->value->floatval = 0;
7492
0
    }
7493
0
    else
7494
0
        ctxt->value->floatval = - ctxt->value->floatval;
7495
0
}
7496
7497
/**
7498
 * xmlXPathAddValues:
7499
 * @ctxt:  the XPath Parser context
7500
 *
7501
 * Implement the add operation on XPath objects:
7502
 * The numeric operators convert their operands to numbers as if
7503
 * by calling the number function.
7504
 */
7505
void
7506
0
xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7507
0
    xmlXPathObjectPtr arg;
7508
0
    double val;
7509
7510
0
    arg = valuePop(ctxt);
7511
0
    if (arg == NULL)
7512
0
  XP_ERROR(XPATH_INVALID_OPERAND);
7513
0
    val = xmlXPathCastToNumber(arg);
7514
0
    xmlXPathReleaseObject(ctxt->context, arg);
7515
0
    CAST_TO_NUMBER;
7516
0
    CHECK_TYPE(XPATH_NUMBER);
7517
0
    ctxt->value->floatval += val;
7518
0
}
7519
7520
/**
7521
 * xmlXPathSubValues:
7522
 * @ctxt:  the XPath Parser context
7523
 *
7524
 * Implement the subtraction operation on XPath objects:
7525
 * The numeric operators convert their operands to numbers as if
7526
 * by calling the number function.
7527
 */
7528
void
7529
0
xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7530
0
    xmlXPathObjectPtr arg;
7531
0
    double val;
7532
7533
0
    arg = valuePop(ctxt);
7534
0
    if (arg == NULL)
7535
0
  XP_ERROR(XPATH_INVALID_OPERAND);
7536
0
    val = xmlXPathCastToNumber(arg);
7537
0
    xmlXPathReleaseObject(ctxt->context, arg);
7538
0
    CAST_TO_NUMBER;
7539
0
    CHECK_TYPE(XPATH_NUMBER);
7540
0
    ctxt->value->floatval -= val;
7541
0
}
7542
7543
/**
7544
 * xmlXPathMultValues:
7545
 * @ctxt:  the XPath Parser context
7546
 *
7547
 * Implement the multiply operation on XPath objects:
7548
 * The numeric operators convert their operands to numbers as if
7549
 * by calling the number function.
7550
 */
7551
void
7552
0
xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7553
0
    xmlXPathObjectPtr arg;
7554
0
    double val;
7555
7556
0
    arg = valuePop(ctxt);
7557
0
    if (arg == NULL)
7558
0
  XP_ERROR(XPATH_INVALID_OPERAND);
7559
0
    val = xmlXPathCastToNumber(arg);
7560
0
    xmlXPathReleaseObject(ctxt->context, arg);
7561
0
    CAST_TO_NUMBER;
7562
0
    CHECK_TYPE(XPATH_NUMBER);
7563
0
    ctxt->value->floatval *= val;
7564
0
}
7565
7566
/**
7567
 * xmlXPathDivValues:
7568
 * @ctxt:  the XPath Parser context
7569
 *
7570
 * Implement the div operation on XPath objects @arg1 / @arg2:
7571
 * The numeric operators convert their operands to numbers as if
7572
 * by calling the number function.
7573
 */
7574
void
7575
0
xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7576
0
    xmlXPathObjectPtr arg;
7577
0
    double val;
7578
7579
0
    arg = valuePop(ctxt);
7580
0
    if (arg == NULL)
7581
0
  XP_ERROR(XPATH_INVALID_OPERAND);
7582
0
    val = xmlXPathCastToNumber(arg);
7583
0
    xmlXPathReleaseObject(ctxt->context, arg);
7584
0
    CAST_TO_NUMBER;
7585
0
    CHECK_TYPE(XPATH_NUMBER);
7586
0
    if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7587
0
  ctxt->value->floatval = xmlXPathNAN;
7588
0
    else if (val == 0 && xmlXPathGetSign(val) != 0) {
7589
0
  if (ctxt->value->floatval == 0)
7590
0
      ctxt->value->floatval = xmlXPathNAN;
7591
0
  else if (ctxt->value->floatval > 0)
7592
0
      ctxt->value->floatval = xmlXPathNINF;
7593
0
  else if (ctxt->value->floatval < 0)
7594
0
      ctxt->value->floatval = xmlXPathPINF;
7595
0
    }
7596
0
    else if (val == 0) {
7597
0
  if (ctxt->value->floatval == 0)
7598
0
      ctxt->value->floatval = xmlXPathNAN;
7599
0
  else if (ctxt->value->floatval > 0)
7600
0
      ctxt->value->floatval = xmlXPathPINF;
7601
0
  else if (ctxt->value->floatval < 0)
7602
0
      ctxt->value->floatval = xmlXPathNINF;
7603
0
    } else
7604
0
  ctxt->value->floatval /= val;
7605
0
}
7606
7607
/**
7608
 * xmlXPathModValues:
7609
 * @ctxt:  the XPath Parser context
7610
 *
7611
 * Implement the mod operation on XPath objects: @arg1 / @arg2
7612
 * The numeric operators convert their operands to numbers as if
7613
 * by calling the number function.
7614
 */
7615
void
7616
0
xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7617
0
    xmlXPathObjectPtr arg;
7618
0
    double arg1, arg2;
7619
7620
0
    arg = valuePop(ctxt);
7621
0
    if (arg == NULL)
7622
0
  XP_ERROR(XPATH_INVALID_OPERAND);
7623
0
    arg2 = xmlXPathCastToNumber(arg);
7624
0
    xmlXPathReleaseObject(ctxt->context, arg);
7625
0
    CAST_TO_NUMBER;
7626
0
    CHECK_TYPE(XPATH_NUMBER);
7627
0
    arg1 = ctxt->value->floatval;
7628
0
    if (arg2 == 0)
7629
0
  ctxt->value->floatval = xmlXPathNAN;
7630
0
    else {
7631
0
  ctxt->value->floatval = fmod(arg1, arg2);
7632
0
    }
7633
0
}
7634
7635
/************************************************************************
7636
 *                  *
7637
 *    The traversal functions         *
7638
 *                  *
7639
 ************************************************************************/
7640
7641
/*
7642
 * A traversal function enumerates nodes along an axis.
7643
 * Initially it must be called with NULL, and it indicates
7644
 * termination on the axis by returning NULL.
7645
 */
7646
typedef xmlNodePtr (*xmlXPathTraversalFunction)
7647
                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7648
7649
/*
7650
 * xmlXPathTraversalFunctionExt:
7651
 * A traversal function enumerates nodes along an axis.
7652
 * Initially it must be called with NULL, and it indicates
7653
 * termination on the axis by returning NULL.
7654
 * The context node of the traversal is specified via @contextNode.
7655
 */
7656
typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7657
                    (xmlNodePtr cur, xmlNodePtr contextNode);
7658
7659
/*
7660
 * xmlXPathNodeSetMergeFunction:
7661
 * Used for merging node sets in xmlXPathCollectAndTest().
7662
 */
7663
typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7664
        (xmlNodeSetPtr, xmlNodeSetPtr, int);
7665
7666
7667
/**
7668
 * xmlXPathNextSelf:
7669
 * @ctxt:  the XPath Parser context
7670
 * @cur:  the current node in the traversal
7671
 *
7672
 * Traversal function for the "self" direction
7673
 * The self axis contains just the context node itself
7674
 *
7675
 * Returns the next element following that axis
7676
 */
7677
xmlNodePtr
7678
0
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7679
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7680
0
    if (cur == NULL)
7681
0
        return(ctxt->context->node);
7682
0
    return(NULL);
7683
0
}
7684
7685
/**
7686
 * xmlXPathNextChild:
7687
 * @ctxt:  the XPath Parser context
7688
 * @cur:  the current node in the traversal
7689
 *
7690
 * Traversal function for the "child" direction
7691
 * The child axis contains the children of the context node in document order.
7692
 *
7693
 * Returns the next element following that axis
7694
 */
7695
xmlNodePtr
7696
0
xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7697
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7698
0
    if (cur == NULL) {
7699
0
  if (ctxt->context->node == NULL) return(NULL);
7700
0
  switch (ctxt->context->node->type) {
7701
0
            case XML_ELEMENT_NODE:
7702
0
            case XML_TEXT_NODE:
7703
0
            case XML_CDATA_SECTION_NODE:
7704
0
            case XML_ENTITY_REF_NODE:
7705
0
            case XML_ENTITY_NODE:
7706
0
            case XML_PI_NODE:
7707
0
            case XML_COMMENT_NODE:
7708
0
            case XML_NOTATION_NODE:
7709
0
            case XML_DTD_NODE:
7710
0
    return(ctxt->context->node->children);
7711
0
            case XML_DOCUMENT_NODE:
7712
0
            case XML_DOCUMENT_TYPE_NODE:
7713
0
            case XML_DOCUMENT_FRAG_NODE:
7714
0
            case XML_HTML_DOCUMENT_NODE:
7715
0
#ifdef LIBXML_DOCB_ENABLED
7716
0
      case XML_DOCB_DOCUMENT_NODE:
7717
0
#endif
7718
0
    return(((xmlDocPtr) ctxt->context->node)->children);
7719
0
      case XML_ELEMENT_DECL:
7720
0
      case XML_ATTRIBUTE_DECL:
7721
0
      case XML_ENTITY_DECL:
7722
0
            case XML_ATTRIBUTE_NODE:
7723
0
      case XML_NAMESPACE_DECL:
7724
0
      case XML_XINCLUDE_START:
7725
0
      case XML_XINCLUDE_END:
7726
0
    return(NULL);
7727
0
  }
7728
0
  return(NULL);
7729
0
    }
7730
0
    if ((cur->type == XML_DOCUMENT_NODE) ||
7731
0
        (cur->type == XML_HTML_DOCUMENT_NODE))
7732
0
  return(NULL);
7733
0
    return(cur->next);
7734
0
}
7735
7736
/**
7737
 * xmlXPathNextChildElement:
7738
 * @ctxt:  the XPath Parser context
7739
 * @cur:  the current node in the traversal
7740
 *
7741
 * Traversal function for the "child" direction and nodes of type element.
7742
 * The child axis contains the children of the context node in document order.
7743
 *
7744
 * Returns the next element following that axis
7745
 */
7746
static xmlNodePtr
7747
0
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7748
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7749
0
    if (cur == NULL) {
7750
0
  cur = ctxt->context->node;
7751
0
  if (cur == NULL) return(NULL);
7752
  /*
7753
  * Get the first element child.
7754
  */
7755
0
  switch (cur->type) {
7756
0
            case XML_ELEMENT_NODE:
7757
0
      case XML_DOCUMENT_FRAG_NODE:
7758
0
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7759
0
            case XML_ENTITY_NODE:
7760
0
    cur = cur->children;
7761
0
    if (cur != NULL) {
7762
0
        if (cur->type == XML_ELEMENT_NODE)
7763
0
      return(cur);
7764
0
        do {
7765
0
      cur = cur->next;
7766
0
        } while ((cur != NULL) &&
7767
0
      (cur->type != XML_ELEMENT_NODE));
7768
0
        return(cur);
7769
0
    }
7770
0
    return(NULL);
7771
0
            case XML_DOCUMENT_NODE:
7772
0
            case XML_HTML_DOCUMENT_NODE:
7773
0
#ifdef LIBXML_DOCB_ENABLED
7774
0
      case XML_DOCB_DOCUMENT_NODE:
7775
0
#endif
7776
0
    return(xmlDocGetRootElement((xmlDocPtr) cur));
7777
0
      default:
7778
0
    return(NULL);
7779
0
  }
7780
0
  return(NULL);
7781
0
    }
7782
    /*
7783
    * Get the next sibling element node.
7784
    */
7785
0
    switch (cur->type) {
7786
0
  case XML_ELEMENT_NODE:
7787
0
  case XML_TEXT_NODE:
7788
0
  case XML_ENTITY_REF_NODE:
7789
0
  case XML_ENTITY_NODE:
7790
0
  case XML_CDATA_SECTION_NODE:
7791
0
  case XML_PI_NODE:
7792
0
  case XML_COMMENT_NODE:
7793
0
  case XML_XINCLUDE_END:
7794
0
      break;
7795
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7796
0
  default:
7797
0
      return(NULL);
7798
0
    }
7799
0
    if (cur->next != NULL) {
7800
0
  if (cur->next->type == XML_ELEMENT_NODE)
7801
0
      return(cur->next);
7802
0
  cur = cur->next;
7803
0
  do {
7804
0
      cur = cur->next;
7805
0
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7806
0
  return(cur);
7807
0
    }
7808
0
    return(NULL);
7809
0
}
7810
7811
#if 0
7812
/**
7813
 * xmlXPathNextDescendantOrSelfElemParent:
7814
 * @ctxt:  the XPath Parser context
7815
 * @cur:  the current node in the traversal
7816
 *
7817
 * Traversal function for the "descendant-or-self" axis.
7818
 * Additionally it returns only nodes which can be parents of
7819
 * element nodes.
7820
 *
7821
 *
7822
 * Returns the next element following that axis
7823
 */
7824
static xmlNodePtr
7825
xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7826
               xmlNodePtr contextNode)
7827
{
7828
    if (cur == NULL) {
7829
  if (contextNode == NULL)
7830
      return(NULL);
7831
  switch (contextNode->type) {
7832
      case XML_ELEMENT_NODE:
7833
      case XML_XINCLUDE_START:
7834
      case XML_DOCUMENT_FRAG_NODE:
7835
      case XML_DOCUMENT_NODE:
7836
#ifdef LIBXML_DOCB_ENABLED
7837
      case XML_DOCB_DOCUMENT_NODE:
7838
#endif
7839
      case XML_HTML_DOCUMENT_NODE:
7840
    return(contextNode);
7841
      default:
7842
    return(NULL);
7843
  }
7844
  return(NULL);
7845
    } else {
7846
  xmlNodePtr start = cur;
7847
7848
  while (cur != NULL) {
7849
      switch (cur->type) {
7850
    case XML_ELEMENT_NODE:
7851
    /* TODO: OK to have XInclude here? */
7852
    case XML_XINCLUDE_START:
7853
    case XML_DOCUMENT_FRAG_NODE:
7854
        if (cur != start)
7855
      return(cur);
7856
        if (cur->children != NULL) {
7857
      cur = cur->children;
7858
      continue;
7859
        }
7860
        break;
7861
    /* Not sure if we need those here. */
7862
    case XML_DOCUMENT_NODE:
7863
#ifdef LIBXML_DOCB_ENABLED
7864
    case XML_DOCB_DOCUMENT_NODE:
7865
#endif
7866
    case XML_HTML_DOCUMENT_NODE:
7867
        if (cur != start)
7868
      return(cur);
7869
        return(xmlDocGetRootElement((xmlDocPtr) cur));
7870
    default:
7871
        break;
7872
      }
7873
7874
next_sibling:
7875
      if ((cur == NULL) || (cur == contextNode))
7876
    return(NULL);
7877
      if (cur->next != NULL) {
7878
    cur = cur->next;
7879
      } else {
7880
    cur = cur->parent;
7881
    goto next_sibling;
7882
      }
7883
  }
7884
    }
7885
    return(NULL);
7886
}
7887
#endif
7888
7889
/**
7890
 * xmlXPathNextDescendant:
7891
 * @ctxt:  the XPath Parser context
7892
 * @cur:  the current node in the traversal
7893
 *
7894
 * Traversal function for the "descendant" direction
7895
 * the descendant axis contains the descendants of the context node in document
7896
 * order; a descendant is a child or a child of a child and so on.
7897
 *
7898
 * Returns the next element following that axis
7899
 */
7900
xmlNodePtr
7901
0
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7902
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7903
0
    if (cur == NULL) {
7904
0
  if (ctxt->context->node == NULL)
7905
0
      return(NULL);
7906
0
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7907
0
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
7908
0
      return(NULL);
7909
7910
0
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7911
0
      return(ctxt->context->doc->children);
7912
0
        return(ctxt->context->node->children);
7913
0
    }
7914
7915
0
    if (cur->type == XML_NAMESPACE_DECL)
7916
0
        return(NULL);
7917
0
    if (cur->children != NULL) {
7918
  /*
7919
   * Do not descend on entities declarations
7920
   */
7921
0
  if (cur->children->type != XML_ENTITY_DECL) {
7922
0
      cur = cur->children;
7923
      /*
7924
       * Skip DTDs
7925
       */
7926
0
      if (cur->type != XML_DTD_NODE)
7927
0
    return(cur);
7928
0
  }
7929
0
    }
7930
7931
0
    if (cur == ctxt->context->node) return(NULL);
7932
7933
0
    while (cur->next != NULL) {
7934
0
  cur = cur->next;
7935
0
  if ((cur->type != XML_ENTITY_DECL) &&
7936
0
      (cur->type != XML_DTD_NODE))
7937
0
      return(cur);
7938
0
    }
7939
7940
0
    do {
7941
0
        cur = cur->parent;
7942
0
  if (cur == NULL) break;
7943
0
  if (cur == ctxt->context->node) return(NULL);
7944
0
  if (cur->next != NULL) {
7945
0
      cur = cur->next;
7946
0
      return(cur);
7947
0
  }
7948
0
    } while (cur != NULL);
7949
0
    return(cur);
7950
0
}
7951
7952
/**
7953
 * xmlXPathNextDescendantOrSelf:
7954
 * @ctxt:  the XPath Parser context
7955
 * @cur:  the current node in the traversal
7956
 *
7957
 * Traversal function for the "descendant-or-self" direction
7958
 * the descendant-or-self axis contains the context node and the descendants
7959
 * of the context node in document order; thus the context node is the first
7960
 * node on the axis, and the first child of the context node is the second node
7961
 * on the axis
7962
 *
7963
 * Returns the next element following that axis
7964
 */
7965
xmlNodePtr
7966
0
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7967
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7968
0
    if (cur == NULL)
7969
0
        return(ctxt->context->node);
7970
7971
0
    if (ctxt->context->node == NULL)
7972
0
        return(NULL);
7973
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7974
0
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
7975
0
        return(NULL);
7976
7977
0
    return(xmlXPathNextDescendant(ctxt, cur));
7978
0
}
7979
7980
/**
7981
 * xmlXPathNextParent:
7982
 * @ctxt:  the XPath Parser context
7983
 * @cur:  the current node in the traversal
7984
 *
7985
 * Traversal function for the "parent" direction
7986
 * The parent axis contains the parent of the context node, if there is one.
7987
 *
7988
 * Returns the next element following that axis
7989
 */
7990
xmlNodePtr
7991
0
xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7992
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7993
    /*
7994
     * the parent of an attribute or namespace node is the element
7995
     * to which the attribute or namespace node is attached
7996
     * Namespace handling !!!
7997
     */
7998
0
    if (cur == NULL) {
7999
0
  if (ctxt->context->node == NULL) return(NULL);
8000
0
  switch (ctxt->context->node->type) {
8001
0
            case XML_ELEMENT_NODE:
8002
0
            case XML_TEXT_NODE:
8003
0
            case XML_CDATA_SECTION_NODE:
8004
0
            case XML_ENTITY_REF_NODE:
8005
0
            case XML_ENTITY_NODE:
8006
0
            case XML_PI_NODE:
8007
0
            case XML_COMMENT_NODE:
8008
0
            case XML_NOTATION_NODE:
8009
0
            case XML_DTD_NODE:
8010
0
      case XML_ELEMENT_DECL:
8011
0
      case XML_ATTRIBUTE_DECL:
8012
0
      case XML_XINCLUDE_START:
8013
0
      case XML_XINCLUDE_END:
8014
0
      case XML_ENTITY_DECL:
8015
0
    if (ctxt->context->node->parent == NULL)
8016
0
        return((xmlNodePtr) ctxt->context->doc);
8017
0
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8018
0
        ((ctxt->context->node->parent->name[0] == ' ') ||
8019
0
         (xmlStrEqual(ctxt->context->node->parent->name,
8020
0
         BAD_CAST "fake node libxslt"))))
8021
0
        return(NULL);
8022
0
    return(ctxt->context->node->parent);
8023
0
            case XML_ATTRIBUTE_NODE: {
8024
0
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8025
8026
0
    return(att->parent);
8027
0
      }
8028
0
            case XML_DOCUMENT_NODE:
8029
0
            case XML_DOCUMENT_TYPE_NODE:
8030
0
            case XML_DOCUMENT_FRAG_NODE:
8031
0
            case XML_HTML_DOCUMENT_NODE:
8032
0
#ifdef LIBXML_DOCB_ENABLED
8033
0
      case XML_DOCB_DOCUMENT_NODE:
8034
0
#endif
8035
0
                return(NULL);
8036
0
      case XML_NAMESPACE_DECL: {
8037
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8038
8039
0
    if ((ns->next != NULL) &&
8040
0
        (ns->next->type != XML_NAMESPACE_DECL))
8041
0
        return((xmlNodePtr) ns->next);
8042
0
                return(NULL);
8043
0
      }
8044
0
  }
8045
0
    }
8046
0
    return(NULL);
8047
0
}
8048
8049
/**
8050
 * xmlXPathNextAncestor:
8051
 * @ctxt:  the XPath Parser context
8052
 * @cur:  the current node in the traversal
8053
 *
8054
 * Traversal function for the "ancestor" direction
8055
 * the ancestor axis contains the ancestors of the context node; the ancestors
8056
 * of the context node consist of the parent of context node and the parent's
8057
 * parent and so on; the nodes are ordered in reverse document order; thus the
8058
 * parent is the first node on the axis, and the parent's parent is the second
8059
 * node on the axis
8060
 *
8061
 * Returns the next element following that axis
8062
 */
8063
xmlNodePtr
8064
0
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8065
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8066
    /*
8067
     * the parent of an attribute or namespace node is the element
8068
     * to which the attribute or namespace node is attached
8069
     * !!!!!!!!!!!!!
8070
     */
8071
0
    if (cur == NULL) {
8072
0
  if (ctxt->context->node == NULL) return(NULL);
8073
0
  switch (ctxt->context->node->type) {
8074
0
            case XML_ELEMENT_NODE:
8075
0
            case XML_TEXT_NODE:
8076
0
            case XML_CDATA_SECTION_NODE:
8077
0
            case XML_ENTITY_REF_NODE:
8078
0
            case XML_ENTITY_NODE:
8079
0
            case XML_PI_NODE:
8080
0
            case XML_COMMENT_NODE:
8081
0
      case XML_DTD_NODE:
8082
0
      case XML_ELEMENT_DECL:
8083
0
      case XML_ATTRIBUTE_DECL:
8084
0
      case XML_ENTITY_DECL:
8085
0
            case XML_NOTATION_NODE:
8086
0
      case XML_XINCLUDE_START:
8087
0
      case XML_XINCLUDE_END:
8088
0
    if (ctxt->context->node->parent == NULL)
8089
0
        return((xmlNodePtr) ctxt->context->doc);
8090
0
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8091
0
        ((ctxt->context->node->parent->name[0] == ' ') ||
8092
0
         (xmlStrEqual(ctxt->context->node->parent->name,
8093
0
         BAD_CAST "fake node libxslt"))))
8094
0
        return(NULL);
8095
0
    return(ctxt->context->node->parent);
8096
0
            case XML_ATTRIBUTE_NODE: {
8097
0
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8098
8099
0
    return(tmp->parent);
8100
0
      }
8101
0
            case XML_DOCUMENT_NODE:
8102
0
            case XML_DOCUMENT_TYPE_NODE:
8103
0
            case XML_DOCUMENT_FRAG_NODE:
8104
0
            case XML_HTML_DOCUMENT_NODE:
8105
0
#ifdef LIBXML_DOCB_ENABLED
8106
0
      case XML_DOCB_DOCUMENT_NODE:
8107
0
#endif
8108
0
                return(NULL);
8109
0
      case XML_NAMESPACE_DECL: {
8110
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8111
8112
0
    if ((ns->next != NULL) &&
8113
0
        (ns->next->type != XML_NAMESPACE_DECL))
8114
0
        return((xmlNodePtr) ns->next);
8115
    /* Bad, how did that namespace end up here ? */
8116
0
                return(NULL);
8117
0
      }
8118
0
  }
8119
0
  return(NULL);
8120
0
    }
8121
0
    if (cur == ctxt->context->doc->children)
8122
0
  return((xmlNodePtr) ctxt->context->doc);
8123
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
8124
0
  return(NULL);
8125
0
    switch (cur->type) {
8126
0
  case XML_ELEMENT_NODE:
8127
0
  case XML_TEXT_NODE:
8128
0
  case XML_CDATA_SECTION_NODE:
8129
0
  case XML_ENTITY_REF_NODE:
8130
0
  case XML_ENTITY_NODE:
8131
0
  case XML_PI_NODE:
8132
0
  case XML_COMMENT_NODE:
8133
0
  case XML_NOTATION_NODE:
8134
0
  case XML_DTD_NODE:
8135
0
        case XML_ELEMENT_DECL:
8136
0
        case XML_ATTRIBUTE_DECL:
8137
0
        case XML_ENTITY_DECL:
8138
0
  case XML_XINCLUDE_START:
8139
0
  case XML_XINCLUDE_END:
8140
0
      if (cur->parent == NULL)
8141
0
    return(NULL);
8142
0
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
8143
0
    ((cur->parent->name[0] == ' ') ||
8144
0
     (xmlStrEqual(cur->parent->name,
8145
0
            BAD_CAST "fake node libxslt"))))
8146
0
    return(NULL);
8147
0
      return(cur->parent);
8148
0
  case XML_ATTRIBUTE_NODE: {
8149
0
      xmlAttrPtr att = (xmlAttrPtr) cur;
8150
8151
0
      return(att->parent);
8152
0
  }
8153
0
  case XML_NAMESPACE_DECL: {
8154
0
      xmlNsPtr ns = (xmlNsPtr) cur;
8155
8156
0
      if ((ns->next != NULL) &&
8157
0
          (ns->next->type != XML_NAMESPACE_DECL))
8158
0
          return((xmlNodePtr) ns->next);
8159
      /* Bad, how did that namespace end up here ? */
8160
0
            return(NULL);
8161
0
  }
8162
0
  case XML_DOCUMENT_NODE:
8163
0
  case XML_DOCUMENT_TYPE_NODE:
8164
0
  case XML_DOCUMENT_FRAG_NODE:
8165
0
  case XML_HTML_DOCUMENT_NODE:
8166
0
#ifdef LIBXML_DOCB_ENABLED
8167
0
  case XML_DOCB_DOCUMENT_NODE:
8168
0
#endif
8169
0
      return(NULL);
8170
0
    }
8171
0
    return(NULL);
8172
0
}
8173
8174
/**
8175
 * xmlXPathNextAncestorOrSelf:
8176
 * @ctxt:  the XPath Parser context
8177
 * @cur:  the current node in the traversal
8178
 *
8179
 * Traversal function for the "ancestor-or-self" direction
8180
 * he ancestor-or-self axis contains the context node and ancestors of
8181
 * the context node in reverse document order; thus the context node is
8182
 * the first node on the axis, and the context node's parent the second;
8183
 * parent here is defined the same as with the parent axis.
8184
 *
8185
 * Returns the next element following that axis
8186
 */
8187
xmlNodePtr
8188
0
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8189
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8190
0
    if (cur == NULL)
8191
0
        return(ctxt->context->node);
8192
0
    return(xmlXPathNextAncestor(ctxt, cur));
8193
0
}
8194
8195
/**
8196
 * xmlXPathNextFollowingSibling:
8197
 * @ctxt:  the XPath Parser context
8198
 * @cur:  the current node in the traversal
8199
 *
8200
 * Traversal function for the "following-sibling" direction
8201
 * The following-sibling axis contains the following siblings of the context
8202
 * node in document order.
8203
 *
8204
 * Returns the next element following that axis
8205
 */
8206
xmlNodePtr
8207
0
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8208
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8209
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8210
0
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8211
0
  return(NULL);
8212
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
8213
0
        return(NULL);
8214
0
    if (cur == NULL)
8215
0
        return(ctxt->context->node->next);
8216
0
    return(cur->next);
8217
0
}
8218
8219
/**
8220
 * xmlXPathNextPrecedingSibling:
8221
 * @ctxt:  the XPath Parser context
8222
 * @cur:  the current node in the traversal
8223
 *
8224
 * Traversal function for the "preceding-sibling" direction
8225
 * The preceding-sibling axis contains the preceding siblings of the context
8226
 * node in reverse document order; the first preceding sibling is first on the
8227
 * axis; the sibling preceding that node is the second on the axis and so on.
8228
 *
8229
 * Returns the next element following that axis
8230
 */
8231
xmlNodePtr
8232
0
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8233
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8234
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8235
0
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8236
0
  return(NULL);
8237
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
8238
0
        return(NULL);
8239
0
    if (cur == NULL)
8240
0
        return(ctxt->context->node->prev);
8241
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8242
0
  cur = cur->prev;
8243
0
  if (cur == NULL)
8244
0
      return(ctxt->context->node->prev);
8245
0
    }
8246
0
    return(cur->prev);
8247
0
}
8248
8249
/**
8250
 * xmlXPathNextFollowing:
8251
 * @ctxt:  the XPath Parser context
8252
 * @cur:  the current node in the traversal
8253
 *
8254
 * Traversal function for the "following" direction
8255
 * The following axis contains all nodes in the same document as the context
8256
 * node that are after the context node in document order, excluding any
8257
 * descendants and excluding attribute nodes and namespace nodes; the nodes
8258
 * are ordered in document order
8259
 *
8260
 * Returns the next element following that axis
8261
 */
8262
xmlNodePtr
8263
0
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8264
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8265
0
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8266
0
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8267
0
        return(cur->children);
8268
8269
0
    if (cur == NULL) {
8270
0
        cur = ctxt->context->node;
8271
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
8272
0
            cur = cur->parent;
8273
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
8274
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8275
8276
0
            if ((ns->next == NULL) ||
8277
0
                (ns->next->type == XML_NAMESPACE_DECL))
8278
0
                return (NULL);
8279
0
            cur = (xmlNodePtr) ns->next;
8280
0
        }
8281
0
    }
8282
0
    if (cur == NULL) return(NULL) ; /* ERROR */
8283
0
    if (cur->next != NULL) return(cur->next) ;
8284
0
    do {
8285
0
        cur = cur->parent;
8286
0
        if (cur == NULL) break;
8287
0
        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8288
0
        if (cur->next != NULL) return(cur->next);
8289
0
    } while (cur != NULL);
8290
0
    return(cur);
8291
0
}
8292
8293
/*
8294
 * xmlXPathIsAncestor:
8295
 * @ancestor:  the ancestor node
8296
 * @node:  the current node
8297
 *
8298
 * Check that @ancestor is a @node's ancestor
8299
 *
8300
 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8301
 */
8302
static int
8303
0
xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8304
0
    if ((ancestor == NULL) || (node == NULL)) return(0);
8305
0
    if (node->type == XML_NAMESPACE_DECL)
8306
0
        return(0);
8307
0
    if (ancestor->type == XML_NAMESPACE_DECL)
8308
0
        return(0);
8309
    /* nodes need to be in the same document */
8310
0
    if (ancestor->doc != node->doc) return(0);
8311
    /* avoid searching if ancestor or node is the root node */
8312
0
    if (ancestor == (xmlNodePtr) node->doc) return(1);
8313
0
    if (node == (xmlNodePtr) ancestor->doc) return(0);
8314
0
    while (node->parent != NULL) {
8315
0
        if (node->parent == ancestor)
8316
0
            return(1);
8317
0
  node = node->parent;
8318
0
    }
8319
0
    return(0);
8320
0
}
8321
8322
/**
8323
 * xmlXPathNextPreceding:
8324
 * @ctxt:  the XPath Parser context
8325
 * @cur:  the current node in the traversal
8326
 *
8327
 * Traversal function for the "preceding" direction
8328
 * the preceding axis contains all nodes in the same document as the context
8329
 * node that are before the context node in document order, excluding any
8330
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8331
 * ordered in reverse document order
8332
 *
8333
 * Returns the next element following that axis
8334
 */
8335
xmlNodePtr
8336
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8337
0
{
8338
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8339
0
    if (cur == NULL) {
8340
0
        cur = ctxt->context->node;
8341
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
8342
0
            cur = cur->parent;
8343
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
8344
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8345
8346
0
            if ((ns->next == NULL) ||
8347
0
                (ns->next->type == XML_NAMESPACE_DECL))
8348
0
                return (NULL);
8349
0
            cur = (xmlNodePtr) ns->next;
8350
0
        }
8351
0
    }
8352
0
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8353
0
  return (NULL);
8354
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8355
0
  cur = cur->prev;
8356
0
    do {
8357
0
        if (cur->prev != NULL) {
8358
0
            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8359
0
            return (cur);
8360
0
        }
8361
8362
0
        cur = cur->parent;
8363
0
        if (cur == NULL)
8364
0
            return (NULL);
8365
0
        if (cur == ctxt->context->doc->children)
8366
0
            return (NULL);
8367
0
    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8368
0
    return (cur);
8369
0
}
8370
8371
/**
8372
 * xmlXPathNextPrecedingInternal:
8373
 * @ctxt:  the XPath Parser context
8374
 * @cur:  the current node in the traversal
8375
 *
8376
 * Traversal function for the "preceding" direction
8377
 * the preceding axis contains all nodes in the same document as the context
8378
 * node that are before the context node in document order, excluding any
8379
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8380
 * ordered in reverse document order
8381
 * This is a faster implementation but internal only since it requires a
8382
 * state kept in the parser context: ctxt->ancestor.
8383
 *
8384
 * Returns the next element following that axis
8385
 */
8386
static xmlNodePtr
8387
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8388
                              xmlNodePtr cur)
8389
0
{
8390
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8391
0
    if (cur == NULL) {
8392
0
        cur = ctxt->context->node;
8393
0
        if (cur == NULL)
8394
0
            return (NULL);
8395
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
8396
0
            cur = cur->parent;
8397
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
8398
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8399
8400
0
            if ((ns->next == NULL) ||
8401
0
                (ns->next->type == XML_NAMESPACE_DECL))
8402
0
                return (NULL);
8403
0
            cur = (xmlNodePtr) ns->next;
8404
0
        }
8405
0
        ctxt->ancestor = cur->parent;
8406
0
    }
8407
0
    if (cur->type == XML_NAMESPACE_DECL)
8408
0
        return(NULL);
8409
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8410
0
  cur = cur->prev;
8411
0
    while (cur->prev == NULL) {
8412
0
        cur = cur->parent;
8413
0
        if (cur == NULL)
8414
0
            return (NULL);
8415
0
        if (cur == ctxt->context->doc->children)
8416
0
            return (NULL);
8417
0
        if (cur != ctxt->ancestor)
8418
0
            return (cur);
8419
0
        ctxt->ancestor = cur->parent;
8420
0
    }
8421
0
    cur = cur->prev;
8422
0
    while (cur->last != NULL)
8423
0
        cur = cur->last;
8424
0
    return (cur);
8425
0
}
8426
8427
/**
8428
 * xmlXPathNextNamespace:
8429
 * @ctxt:  the XPath Parser context
8430
 * @cur:  the current attribute in the traversal
8431
 *
8432
 * Traversal function for the "namespace" direction
8433
 * the namespace axis contains the namespace nodes of the context node;
8434
 * the order of nodes on this axis is implementation-defined; the axis will
8435
 * be empty unless the context node is an element
8436
 *
8437
 * We keep the XML namespace node at the end of the list.
8438
 *
8439
 * Returns the next element following that axis
8440
 */
8441
xmlNodePtr
8442
0
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8443
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8444
0
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8445
0
    if (cur == NULL) {
8446
0
        if (ctxt->context->tmpNsList != NULL)
8447
0
      xmlFree(ctxt->context->tmpNsList);
8448
0
  ctxt->context->tmpNsList =
8449
0
      xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8450
0
  ctxt->context->tmpNsNr = 0;
8451
0
  if (ctxt->context->tmpNsList != NULL) {
8452
0
      while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8453
0
    ctxt->context->tmpNsNr++;
8454
0
      }
8455
0
  }
8456
0
  return((xmlNodePtr) xmlXPathXMLNamespace);
8457
0
    }
8458
0
    if (ctxt->context->tmpNsNr > 0) {
8459
0
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8460
0
    } else {
8461
0
  if (ctxt->context->tmpNsList != NULL)
8462
0
      xmlFree(ctxt->context->tmpNsList);
8463
0
  ctxt->context->tmpNsList = NULL;
8464
0
  return(NULL);
8465
0
    }
8466
0
}
8467
8468
/**
8469
 * xmlXPathNextAttribute:
8470
 * @ctxt:  the XPath Parser context
8471
 * @cur:  the current attribute in the traversal
8472
 *
8473
 * Traversal function for the "attribute" direction
8474
 * TODO: support DTD inherited default attributes
8475
 *
8476
 * Returns the next element following that axis
8477
 */
8478
xmlNodePtr
8479
0
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8480
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8481
0
    if (ctxt->context->node == NULL)
8482
0
  return(NULL);
8483
0
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
8484
0
  return(NULL);
8485
0
    if (cur == NULL) {
8486
0
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8487
0
      return(NULL);
8488
0
        return((xmlNodePtr)ctxt->context->node->properties);
8489
0
    }
8490
0
    return((xmlNodePtr)cur->next);
8491
0
}
8492
8493
/************************************************************************
8494
 *                  *
8495
 *    NodeTest Functions          *
8496
 *                  *
8497
 ************************************************************************/
8498
8499
#define IS_FUNCTION     200
8500
8501
8502
/************************************************************************
8503
 *                  *
8504
 *    Implicit tree core function library     *
8505
 *                  *
8506
 ************************************************************************/
8507
8508
/**
8509
 * xmlXPathRoot:
8510
 * @ctxt:  the XPath Parser context
8511
 *
8512
 * Initialize the context to the root of the document
8513
 */
8514
void
8515
0
xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8516
0
    if ((ctxt == NULL) || (ctxt->context == NULL))
8517
0
  return;
8518
0
    ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8519
0
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8520
0
  ctxt->context->node));
8521
0
}
8522
8523
/************************************************************************
8524
 *                  *
8525
 *    The explicit core function library      *
8526
 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8527
 *                  *
8528
 ************************************************************************/
8529
8530
8531
/**
8532
 * xmlXPathLastFunction:
8533
 * @ctxt:  the XPath Parser context
8534
 * @nargs:  the number of arguments
8535
 *
8536
 * Implement the last() XPath function
8537
 *    number last()
8538
 * The last function returns the number of nodes in the context node list.
8539
 */
8540
void
8541
0
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8542
0
    CHECK_ARITY(0);
8543
0
    if (ctxt->context->contextSize >= 0) {
8544
0
  valuePush(ctxt,
8545
0
      xmlXPathCacheNewFloat(ctxt->context,
8546
0
    (double) ctxt->context->contextSize));
8547
#ifdef DEBUG_EXPR
8548
  xmlGenericError(xmlGenericErrorContext,
8549
    "last() : %d\n", ctxt->context->contextSize);
8550
#endif
8551
0
    } else {
8552
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8553
0
    }
8554
0
}
8555
8556
/**
8557
 * xmlXPathPositionFunction:
8558
 * @ctxt:  the XPath Parser context
8559
 * @nargs:  the number of arguments
8560
 *
8561
 * Implement the position() XPath function
8562
 *    number position()
8563
 * The position function returns the position of the context node in the
8564
 * context node list. The first position is 1, and so the last position
8565
 * will be equal to last().
8566
 */
8567
void
8568
0
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8569
0
    CHECK_ARITY(0);
8570
0
    if (ctxt->context->proximityPosition >= 0) {
8571
0
  valuePush(ctxt,
8572
0
        xmlXPathCacheNewFloat(ctxt->context,
8573
0
    (double) ctxt->context->proximityPosition));
8574
#ifdef DEBUG_EXPR
8575
  xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8576
    ctxt->context->proximityPosition);
8577
#endif
8578
0
    } else {
8579
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8580
0
    }
8581
0
}
8582
8583
/**
8584
 * xmlXPathCountFunction:
8585
 * @ctxt:  the XPath Parser context
8586
 * @nargs:  the number of arguments
8587
 *
8588
 * Implement the count() XPath function
8589
 *    number count(node-set)
8590
 */
8591
void
8592
0
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8593
0
    xmlXPathObjectPtr cur;
8594
8595
0
    CHECK_ARITY(1);
8596
0
    if ((ctxt->value == NULL) ||
8597
0
  ((ctxt->value->type != XPATH_NODESET) &&
8598
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8599
0
  XP_ERROR(XPATH_INVALID_TYPE);
8600
0
    cur = valuePop(ctxt);
8601
8602
0
    if ((cur == NULL) || (cur->nodesetval == NULL))
8603
0
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8604
0
    else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8605
0
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8606
0
      (double) cur->nodesetval->nodeNr));
8607
0
    } else {
8608
0
  if ((cur->nodesetval->nodeNr != 1) ||
8609
0
      (cur->nodesetval->nodeTab == NULL)) {
8610
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8611
0
  } else {
8612
0
      xmlNodePtr tmp;
8613
0
      int i = 0;
8614
8615
0
      tmp = cur->nodesetval->nodeTab[0];
8616
0
      if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
8617
0
    tmp = tmp->children;
8618
0
    while (tmp != NULL) {
8619
0
        tmp = tmp->next;
8620
0
        i++;
8621
0
    }
8622
0
      }
8623
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8624
0
  }
8625
0
    }
8626
0
    xmlXPathReleaseObject(ctxt->context, cur);
8627
0
}
8628
8629
/**
8630
 * xmlXPathGetElementsByIds:
8631
 * @doc:  the document
8632
 * @ids:  a whitespace separated list of IDs
8633
 *
8634
 * Selects elements by their unique ID.
8635
 *
8636
 * Returns a node-set of selected elements.
8637
 */
8638
static xmlNodeSetPtr
8639
0
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8640
0
    xmlNodeSetPtr ret;
8641
0
    const xmlChar *cur = ids;
8642
0
    xmlChar *ID;
8643
0
    xmlAttrPtr attr;
8644
0
    xmlNodePtr elem = NULL;
8645
8646
0
    if (ids == NULL) return(NULL);
8647
8648
0
    ret = xmlXPathNodeSetCreate(NULL);
8649
0
    if (ret == NULL)
8650
0
        return(ret);
8651
8652
0
    while (IS_BLANK_CH(*cur)) cur++;
8653
0
    while (*cur != 0) {
8654
0
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8655
0
      cur++;
8656
8657
0
        ID = xmlStrndup(ids, cur - ids);
8658
0
  if (ID != NULL) {
8659
      /*
8660
       * We used to check the fact that the value passed
8661
       * was an NCName, but this generated much troubles for
8662
       * me and Aleksey Sanin, people blatantly violated that
8663
       * constaint, like Visa3D spec.
8664
       * if (xmlValidateNCName(ID, 1) == 0)
8665
       */
8666
0
      attr = xmlGetID(doc, ID);
8667
0
      if (attr != NULL) {
8668
0
    if (attr->type == XML_ATTRIBUTE_NODE)
8669
0
        elem = attr->parent;
8670
0
    else if (attr->type == XML_ELEMENT_NODE)
8671
0
        elem = (xmlNodePtr) attr;
8672
0
    else
8673
0
        elem = NULL;
8674
0
    if (elem != NULL)
8675
0
        xmlXPathNodeSetAdd(ret, elem);
8676
0
      }
8677
0
      xmlFree(ID);
8678
0
  }
8679
8680
0
  while (IS_BLANK_CH(*cur)) cur++;
8681
0
  ids = cur;
8682
0
    }
8683
0
    return(ret);
8684
0
}
8685
8686
/**
8687
 * xmlXPathIdFunction:
8688
 * @ctxt:  the XPath Parser context
8689
 * @nargs:  the number of arguments
8690
 *
8691
 * Implement the id() XPath function
8692
 *    node-set id(object)
8693
 * The id function selects elements by their unique ID
8694
 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8695
 * then the result is the union of the result of applying id to the
8696
 * string value of each of the nodes in the argument node-set. When the
8697
 * argument to id is of any other type, the argument is converted to a
8698
 * string as if by a call to the string function; the string is split
8699
 * into a whitespace-separated list of tokens (whitespace is any sequence
8700
 * of characters matching the production S); the result is a node-set
8701
 * containing the elements in the same document as the context node that
8702
 * have a unique ID equal to any of the tokens in the list.
8703
 */
8704
void
8705
0
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8706
0
    xmlChar *tokens;
8707
0
    xmlNodeSetPtr ret;
8708
0
    xmlXPathObjectPtr obj;
8709
8710
0
    CHECK_ARITY(1);
8711
0
    obj = valuePop(ctxt);
8712
0
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8713
0
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8714
0
  xmlNodeSetPtr ns;
8715
0
  int i;
8716
8717
0
  ret = xmlXPathNodeSetCreate(NULL);
8718
        /*
8719
         * FIXME -- in an out-of-memory condition this will behave badly.
8720
         * The solution is not clear -- we already popped an item from
8721
         * ctxt, so the object is in a corrupt state.
8722
         */
8723
8724
0
  if (obj->nodesetval != NULL) {
8725
0
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8726
0
    tokens =
8727
0
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8728
0
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8729
0
    ret = xmlXPathNodeSetMerge(ret, ns);
8730
0
    xmlXPathFreeNodeSet(ns);
8731
0
    if (tokens != NULL)
8732
0
        xmlFree(tokens);
8733
0
      }
8734
0
  }
8735
0
  xmlXPathReleaseObject(ctxt->context, obj);
8736
0
  valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8737
0
  return;
8738
0
    }
8739
0
    obj = xmlXPathCacheConvertString(ctxt->context, obj);
8740
0
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8741
0
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8742
0
    xmlXPathReleaseObject(ctxt->context, obj);
8743
0
    return;
8744
0
}
8745
8746
/**
8747
 * xmlXPathLocalNameFunction:
8748
 * @ctxt:  the XPath Parser context
8749
 * @nargs:  the number of arguments
8750
 *
8751
 * Implement the local-name() XPath function
8752
 *    string local-name(node-set?)
8753
 * The local-name function returns a string containing the local part
8754
 * of the name of the node in the argument node-set that is first in
8755
 * document order. If the node-set is empty or the first node has no
8756
 * name, an empty string is returned. If the argument is omitted it
8757
 * defaults to the context node.
8758
 */
8759
void
8760
0
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8761
0
    xmlXPathObjectPtr cur;
8762
8763
0
    if (ctxt == NULL) return;
8764
8765
0
    if (nargs == 0) {
8766
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8767
0
      ctxt->context->node));
8768
0
  nargs = 1;
8769
0
    }
8770
8771
0
    CHECK_ARITY(1);
8772
0
    if ((ctxt->value == NULL) ||
8773
0
  ((ctxt->value->type != XPATH_NODESET) &&
8774
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8775
0
  XP_ERROR(XPATH_INVALID_TYPE);
8776
0
    cur = valuePop(ctxt);
8777
8778
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8779
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8780
0
    } else {
8781
0
  int i = 0; /* Should be first in document order !!!!! */
8782
0
  switch (cur->nodesetval->nodeTab[i]->type) {
8783
0
  case XML_ELEMENT_NODE:
8784
0
  case XML_ATTRIBUTE_NODE:
8785
0
  case XML_PI_NODE:
8786
0
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8787
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8788
0
      else
8789
0
    valuePush(ctxt,
8790
0
          xmlXPathCacheNewString(ctxt->context,
8791
0
      cur->nodesetval->nodeTab[i]->name));
8792
0
      break;
8793
0
  case XML_NAMESPACE_DECL:
8794
0
      valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8795
0
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8796
0
      break;
8797
0
  default:
8798
0
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8799
0
  }
8800
0
    }
8801
0
    xmlXPathReleaseObject(ctxt->context, cur);
8802
0
}
8803
8804
/**
8805
 * xmlXPathNamespaceURIFunction:
8806
 * @ctxt:  the XPath Parser context
8807
 * @nargs:  the number of arguments
8808
 *
8809
 * Implement the namespace-uri() XPath function
8810
 *    string namespace-uri(node-set?)
8811
 * The namespace-uri function returns a string containing the
8812
 * namespace URI of the expanded name of the node in the argument
8813
 * node-set that is first in document order. If the node-set is empty,
8814
 * the first node has no name, or the expanded name has no namespace
8815
 * URI, an empty string is returned. If the argument is omitted it
8816
 * defaults to the context node.
8817
 */
8818
void
8819
0
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8820
0
    xmlXPathObjectPtr cur;
8821
8822
0
    if (ctxt == NULL) return;
8823
8824
0
    if (nargs == 0) {
8825
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8826
0
      ctxt->context->node));
8827
0
  nargs = 1;
8828
0
    }
8829
0
    CHECK_ARITY(1);
8830
0
    if ((ctxt->value == NULL) ||
8831
0
  ((ctxt->value->type != XPATH_NODESET) &&
8832
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8833
0
  XP_ERROR(XPATH_INVALID_TYPE);
8834
0
    cur = valuePop(ctxt);
8835
8836
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8837
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8838
0
    } else {
8839
0
  int i = 0; /* Should be first in document order !!!!! */
8840
0
  switch (cur->nodesetval->nodeTab[i]->type) {
8841
0
  case XML_ELEMENT_NODE:
8842
0
  case XML_ATTRIBUTE_NODE:
8843
0
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
8844
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8845
0
      else
8846
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8847
0
        cur->nodesetval->nodeTab[i]->ns->href));
8848
0
      break;
8849
0
  default:
8850
0
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8851
0
  }
8852
0
    }
8853
0
    xmlXPathReleaseObject(ctxt->context, cur);
8854
0
}
8855
8856
/**
8857
 * xmlXPathNameFunction:
8858
 * @ctxt:  the XPath Parser context
8859
 * @nargs:  the number of arguments
8860
 *
8861
 * Implement the name() XPath function
8862
 *    string name(node-set?)
8863
 * The name function returns a string containing a QName representing
8864
 * the name of the node in the argument node-set that is first in document
8865
 * order. The QName must represent the name with respect to the namespace
8866
 * declarations in effect on the node whose name is being represented.
8867
 * Typically, this will be the form in which the name occurred in the XML
8868
 * source. This need not be the case if there are namespace declarations
8869
 * in effect on the node that associate multiple prefixes with the same
8870
 * namespace. However, an implementation may include information about
8871
 * the original prefix in its representation of nodes; in this case, an
8872
 * implementation can ensure that the returned string is always the same
8873
 * as the QName used in the XML source. If the argument it omitted it
8874
 * defaults to the context node.
8875
 * Libxml keep the original prefix so the "real qualified name" used is
8876
 * returned.
8877
 */
8878
static void
8879
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8880
0
{
8881
0
    xmlXPathObjectPtr cur;
8882
8883
0
    if (nargs == 0) {
8884
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8885
0
      ctxt->context->node));
8886
0
        nargs = 1;
8887
0
    }
8888
8889
0
    CHECK_ARITY(1);
8890
0
    if ((ctxt->value == NULL) ||
8891
0
        ((ctxt->value->type != XPATH_NODESET) &&
8892
0
         (ctxt->value->type != XPATH_XSLT_TREE)))
8893
0
        XP_ERROR(XPATH_INVALID_TYPE);
8894
0
    cur = valuePop(ctxt);
8895
8896
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8897
0
        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8898
0
    } else {
8899
0
        int i = 0;              /* Should be first in document order !!!!! */
8900
8901
0
        switch (cur->nodesetval->nodeTab[i]->type) {
8902
0
            case XML_ELEMENT_NODE:
8903
0
            case XML_ATTRIBUTE_NODE:
8904
0
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8905
0
        valuePush(ctxt,
8906
0
      xmlXPathCacheNewCString(ctxt->context, ""));
8907
0
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8908
0
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8909
0
        valuePush(ctxt,
8910
0
            xmlXPathCacheNewString(ctxt->context,
8911
0
          cur->nodesetval->nodeTab[i]->name));
8912
0
    } else {
8913
0
        xmlChar *fullname;
8914
8915
0
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8916
0
             cur->nodesetval->nodeTab[i]->ns->prefix,
8917
0
             NULL, 0);
8918
0
        if (fullname == cur->nodesetval->nodeTab[i]->name)
8919
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8920
0
        if (fullname == NULL) {
8921
0
      XP_ERROR(XPATH_MEMORY_ERROR);
8922
0
        }
8923
0
        valuePush(ctxt, xmlXPathCacheWrapString(
8924
0
      ctxt->context, fullname));
8925
0
                }
8926
0
                break;
8927
0
            default:
8928
0
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8929
0
        cur->nodesetval->nodeTab[i]));
8930
0
                xmlXPathLocalNameFunction(ctxt, 1);
8931
0
        }
8932
0
    }
8933
0
    xmlXPathReleaseObject(ctxt->context, cur);
8934
0
}
8935
8936
8937
/**
8938
 * xmlXPathStringFunction:
8939
 * @ctxt:  the XPath Parser context
8940
 * @nargs:  the number of arguments
8941
 *
8942
 * Implement the string() XPath function
8943
 *    string string(object?)
8944
 * The string function converts an object to a string as follows:
8945
 *    - A node-set is converted to a string by returning the value of
8946
 *      the node in the node-set that is first in document order.
8947
 *      If the node-set is empty, an empty string is returned.
8948
 *    - A number is converted to a string as follows
8949
 *      + NaN is converted to the string NaN
8950
 *      + positive zero is converted to the string 0
8951
 *      + negative zero is converted to the string 0
8952
 *      + positive infinity is converted to the string Infinity
8953
 *      + negative infinity is converted to the string -Infinity
8954
 *      + if the number is an integer, the number is represented in
8955
 *        decimal form as a Number with no decimal point and no leading
8956
 *        zeros, preceded by a minus sign (-) if the number is negative
8957
 *      + otherwise, the number is represented in decimal form as a
8958
 *        Number including a decimal point with at least one digit
8959
 *        before the decimal point and at least one digit after the
8960
 *        decimal point, preceded by a minus sign (-) if the number
8961
 *        is negative; there must be no leading zeros before the decimal
8962
 *        point apart possibly from the one required digit immediately
8963
 *        before the decimal point; beyond the one required digit
8964
 *        after the decimal point there must be as many, but only as
8965
 *        many, more digits as are needed to uniquely distinguish the
8966
 *        number from all other IEEE 754 numeric values.
8967
 *    - The boolean false value is converted to the string false.
8968
 *      The boolean true value is converted to the string true.
8969
 *
8970
 * If the argument is omitted, it defaults to a node-set with the
8971
 * context node as its only member.
8972
 */
8973
void
8974
0
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8975
0
    xmlXPathObjectPtr cur;
8976
8977
0
    if (ctxt == NULL) return;
8978
0
    if (nargs == 0) {
8979
0
    valuePush(ctxt,
8980
0
  xmlXPathCacheWrapString(ctxt->context,
8981
0
      xmlXPathCastNodeToString(ctxt->context->node)));
8982
0
  return;
8983
0
    }
8984
8985
0
    CHECK_ARITY(1);
8986
0
    cur = valuePop(ctxt);
8987
0
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8988
0
    valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8989
0
}
8990
8991
/**
8992
 * xmlXPathStringLengthFunction:
8993
 * @ctxt:  the XPath Parser context
8994
 * @nargs:  the number of arguments
8995
 *
8996
 * Implement the string-length() XPath function
8997
 *    number string-length(string?)
8998
 * The string-length returns the number of characters in the string
8999
 * (see [3.6 Strings]). If the argument is omitted, it defaults to
9000
 * the context node converted to a string, in other words the value
9001
 * of the context node.
9002
 */
9003
void
9004
0
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9005
0
    xmlXPathObjectPtr cur;
9006
9007
0
    if (nargs == 0) {
9008
0
        if ((ctxt == NULL) || (ctxt->context == NULL))
9009
0
      return;
9010
0
  if (ctxt->context->node == NULL) {
9011
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
9012
0
  } else {
9013
0
      xmlChar *content;
9014
9015
0
      content = xmlXPathCastNodeToString(ctxt->context->node);
9016
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
9017
0
    xmlUTF8Strlen(content)));
9018
0
      xmlFree(content);
9019
0
  }
9020
0
  return;
9021
0
    }
9022
0
    CHECK_ARITY(1);
9023
0
    CAST_TO_STRING;
9024
0
    CHECK_TYPE(XPATH_STRING);
9025
0
    cur = valuePop(ctxt);
9026
0
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
9027
0
  xmlUTF8Strlen(cur->stringval)));
9028
0
    xmlXPathReleaseObject(ctxt->context, cur);
9029
0
}
9030
9031
/**
9032
 * xmlXPathConcatFunction:
9033
 * @ctxt:  the XPath Parser context
9034
 * @nargs:  the number of arguments
9035
 *
9036
 * Implement the concat() XPath function
9037
 *    string concat(string, string, string*)
9038
 * The concat function returns the concatenation of its arguments.
9039
 */
9040
void
9041
0
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9042
0
    xmlXPathObjectPtr cur, newobj;
9043
0
    xmlChar *tmp;
9044
9045
0
    if (ctxt == NULL) return;
9046
0
    if (nargs < 2) {
9047
0
  CHECK_ARITY(2);
9048
0
    }
9049
9050
0
    CAST_TO_STRING;
9051
0
    cur = valuePop(ctxt);
9052
0
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
9053
0
  xmlXPathReleaseObject(ctxt->context, cur);
9054
0
  return;
9055
0
    }
9056
0
    nargs--;
9057
9058
0
    while (nargs > 0) {
9059
0
  CAST_TO_STRING;
9060
0
  newobj = valuePop(ctxt);
9061
0
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
9062
0
      xmlXPathReleaseObject(ctxt->context, newobj);
9063
0
      xmlXPathReleaseObject(ctxt->context, cur);
9064
0
      XP_ERROR(XPATH_INVALID_TYPE);
9065
0
  }
9066
0
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
9067
0
  newobj->stringval = cur->stringval;
9068
0
  cur->stringval = tmp;
9069
0
  xmlXPathReleaseObject(ctxt->context, newobj);
9070
0
  nargs--;
9071
0
    }
9072
0
    valuePush(ctxt, cur);
9073
0
}
9074
9075
/**
9076
 * xmlXPathContainsFunction:
9077
 * @ctxt:  the XPath Parser context
9078
 * @nargs:  the number of arguments
9079
 *
9080
 * Implement the contains() XPath function
9081
 *    boolean contains(string, string)
9082
 * The contains function returns true if the first argument string
9083
 * contains the second argument string, and otherwise returns false.
9084
 */
9085
void
9086
0
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9087
0
    xmlXPathObjectPtr hay, needle;
9088
9089
0
    CHECK_ARITY(2);
9090
0
    CAST_TO_STRING;
9091
0
    CHECK_TYPE(XPATH_STRING);
9092
0
    needle = valuePop(ctxt);
9093
0
    CAST_TO_STRING;
9094
0
    hay = valuePop(ctxt);
9095
9096
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9097
0
  xmlXPathReleaseObject(ctxt->context, hay);
9098
0
  xmlXPathReleaseObject(ctxt->context, needle);
9099
0
  XP_ERROR(XPATH_INVALID_TYPE);
9100
0
    }
9101
0
    if (xmlStrstr(hay->stringval, needle->stringval))
9102
0
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9103
0
    else
9104
0
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9105
0
    xmlXPathReleaseObject(ctxt->context, hay);
9106
0
    xmlXPathReleaseObject(ctxt->context, needle);
9107
0
}
9108
9109
/**
9110
 * xmlXPathStartsWithFunction:
9111
 * @ctxt:  the XPath Parser context
9112
 * @nargs:  the number of arguments
9113
 *
9114
 * Implement the starts-with() XPath function
9115
 *    boolean starts-with(string, string)
9116
 * The starts-with function returns true if the first argument string
9117
 * starts with the second argument string, and otherwise returns false.
9118
 */
9119
void
9120
0
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9121
0
    xmlXPathObjectPtr hay, needle;
9122
0
    int n;
9123
9124
0
    CHECK_ARITY(2);
9125
0
    CAST_TO_STRING;
9126
0
    CHECK_TYPE(XPATH_STRING);
9127
0
    needle = valuePop(ctxt);
9128
0
    CAST_TO_STRING;
9129
0
    hay = valuePop(ctxt);
9130
9131
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9132
0
  xmlXPathReleaseObject(ctxt->context, hay);
9133
0
  xmlXPathReleaseObject(ctxt->context, needle);
9134
0
  XP_ERROR(XPATH_INVALID_TYPE);
9135
0
    }
9136
0
    n = xmlStrlen(needle->stringval);
9137
0
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
9138
0
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9139
0
    else
9140
0
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9141
0
    xmlXPathReleaseObject(ctxt->context, hay);
9142
0
    xmlXPathReleaseObject(ctxt->context, needle);
9143
0
}
9144
9145
/**
9146
 * xmlXPathSubstringFunction:
9147
 * @ctxt:  the XPath Parser context
9148
 * @nargs:  the number of arguments
9149
 *
9150
 * Implement the substring() XPath function
9151
 *    string substring(string, number, number?)
9152
 * The substring function returns the substring of the first argument
9153
 * starting at the position specified in the second argument with
9154
 * length specified in the third argument. For example,
9155
 * substring("12345",2,3) returns "234". If the third argument is not
9156
 * specified, it returns the substring starting at the position specified
9157
 * in the second argument and continuing to the end of the string. For
9158
 * example, substring("12345",2) returns "2345".  More precisely, each
9159
 * character in the string (see [3.6 Strings]) is considered to have a
9160
 * numeric position: the position of the first character is 1, the position
9161
 * of the second character is 2 and so on. The returned substring contains
9162
 * those characters for which the position of the character is greater than
9163
 * or equal to the second argument and, if the third argument is specified,
9164
 * less than the sum of the second and third arguments; the comparisons
9165
 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9166
 *  - substring("12345", 1.5, 2.6) returns "234"
9167
 *  - substring("12345", 0, 3) returns "12"
9168
 *  - substring("12345", 0 div 0, 3) returns ""
9169
 *  - substring("12345", 1, 0 div 0) returns ""
9170
 *  - substring("12345", -42, 1 div 0) returns "12345"
9171
 *  - substring("12345", -1 div 0, 1 div 0) returns ""
9172
 */
9173
void
9174
0
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9175
0
    xmlXPathObjectPtr str, start, len;
9176
0
    double le=0, in;
9177
0
    int i, l, m;
9178
0
    xmlChar *ret;
9179
9180
0
    if (nargs < 2) {
9181
0
  CHECK_ARITY(2);
9182
0
    }
9183
0
    if (nargs > 3) {
9184
0
  CHECK_ARITY(3);
9185
0
    }
9186
    /*
9187
     * take care of possible last (position) argument
9188
    */
9189
0
    if (nargs == 3) {
9190
0
  CAST_TO_NUMBER;
9191
0
  CHECK_TYPE(XPATH_NUMBER);
9192
0
  len = valuePop(ctxt);
9193
0
  le = len->floatval;
9194
0
  xmlXPathReleaseObject(ctxt->context, len);
9195
0
    }
9196
9197
0
    CAST_TO_NUMBER;
9198
0
    CHECK_TYPE(XPATH_NUMBER);
9199
0
    start = valuePop(ctxt);
9200
0
    in = start->floatval;
9201
0
    xmlXPathReleaseObject(ctxt->context, start);
9202
0
    CAST_TO_STRING;
9203
0
    CHECK_TYPE(XPATH_STRING);
9204
0
    str = valuePop(ctxt);
9205
0
    m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9206
9207
    /*
9208
     * If last pos not present, calculate last position
9209
    */
9210
0
    if (nargs != 3) {
9211
0
  le = (double)m;
9212
0
  if (in < 1.0)
9213
0
      in = 1.0;
9214
0
    }
9215
9216
    /* Need to check for the special cases where either
9217
     * the index is NaN, the length is NaN, or both
9218
     * arguments are infinity (relying on Inf + -Inf = NaN)
9219
     */
9220
0
    if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9221
        /*
9222
         * To meet the requirements of the spec, the arguments
9223
   * must be converted to integer format before
9224
   * initial index calculations are done
9225
         *
9226
         * First we go to integer form, rounding up
9227
   * and checking for special cases
9228
         */
9229
0
        i = (int) in;
9230
0
        if (((double)i)+0.5 <= in) i++;
9231
9232
0
  if (xmlXPathIsInf(le) == 1) {
9233
0
      l = m;
9234
0
      if (i < 1)
9235
0
    i = 1;
9236
0
  }
9237
0
  else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9238
0
      l = 0;
9239
0
  else {
9240
0
      l = (int) le;
9241
0
      if (((double)l)+0.5 <= le) l++;
9242
0
  }
9243
9244
  /* Now we normalize inidices */
9245
0
        i -= 1;
9246
0
        l += i;
9247
0
        if (i < 0)
9248
0
            i = 0;
9249
0
        if (l > m)
9250
0
            l = m;
9251
9252
        /* number of chars to copy */
9253
0
        l -= i;
9254
9255
0
        ret = xmlUTF8Strsub(str->stringval, i, l);
9256
0
    }
9257
0
    else {
9258
0
        ret = NULL;
9259
0
    }
9260
0
    if (ret == NULL)
9261
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9262
0
    else {
9263
0
  valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9264
0
  xmlFree(ret);
9265
0
    }
9266
0
    xmlXPathReleaseObject(ctxt->context, str);
9267
0
}
9268
9269
/**
9270
 * xmlXPathSubstringBeforeFunction:
9271
 * @ctxt:  the XPath Parser context
9272
 * @nargs:  the number of arguments
9273
 *
9274
 * Implement the substring-before() XPath function
9275
 *    string substring-before(string, string)
9276
 * The substring-before function returns the substring of the first
9277
 * argument string that precedes the first occurrence of the second
9278
 * argument string in the first argument string, or the empty string
9279
 * if the first argument string does not contain the second argument
9280
 * string. For example, substring-before("1999/04/01","/") returns 1999.
9281
 */
9282
void
9283
0
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9284
0
  xmlXPathObjectPtr str;
9285
0
  xmlXPathObjectPtr find;
9286
0
  xmlBufPtr target;
9287
0
  const xmlChar *point;
9288
0
  int offset;
9289
9290
0
  CHECK_ARITY(2);
9291
0
  CAST_TO_STRING;
9292
0
  find = valuePop(ctxt);
9293
0
  CAST_TO_STRING;
9294
0
  str = valuePop(ctxt);
9295
9296
0
  target = xmlBufCreate();
9297
0
  if (target) {
9298
0
    point = xmlStrstr(str->stringval, find->stringval);
9299
0
    if (point) {
9300
0
      offset = (int)(point - str->stringval);
9301
0
      xmlBufAdd(target, str->stringval, offset);
9302
0
    }
9303
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9304
0
  xmlBufContent(target)));
9305
0
    xmlBufFree(target);
9306
0
  }
9307
0
  xmlXPathReleaseObject(ctxt->context, str);
9308
0
  xmlXPathReleaseObject(ctxt->context, find);
9309
0
}
9310
9311
/**
9312
 * xmlXPathSubstringAfterFunction:
9313
 * @ctxt:  the XPath Parser context
9314
 * @nargs:  the number of arguments
9315
 *
9316
 * Implement the substring-after() XPath function
9317
 *    string substring-after(string, string)
9318
 * The substring-after function returns the substring of the first
9319
 * argument string that follows the first occurrence of the second
9320
 * argument string in the first argument string, or the empty stringi
9321
 * if the first argument string does not contain the second argument
9322
 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9323
 * and substring-after("1999/04/01","19") returns 99/04/01.
9324
 */
9325
void
9326
0
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9327
0
  xmlXPathObjectPtr str;
9328
0
  xmlXPathObjectPtr find;
9329
0
  xmlBufPtr target;
9330
0
  const xmlChar *point;
9331
0
  int offset;
9332
9333
0
  CHECK_ARITY(2);
9334
0
  CAST_TO_STRING;
9335
0
  find = valuePop(ctxt);
9336
0
  CAST_TO_STRING;
9337
0
  str = valuePop(ctxt);
9338
9339
0
  target = xmlBufCreate();
9340
0
  if (target) {
9341
0
    point = xmlStrstr(str->stringval, find->stringval);
9342
0
    if (point) {
9343
0
      offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9344
0
      xmlBufAdd(target, &str->stringval[offset],
9345
0
       xmlStrlen(str->stringval) - offset);
9346
0
    }
9347
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9348
0
  xmlBufContent(target)));
9349
0
    xmlBufFree(target);
9350
0
  }
9351
0
  xmlXPathReleaseObject(ctxt->context, str);
9352
0
  xmlXPathReleaseObject(ctxt->context, find);
9353
0
}
9354
9355
/**
9356
 * xmlXPathNormalizeFunction:
9357
 * @ctxt:  the XPath Parser context
9358
 * @nargs:  the number of arguments
9359
 *
9360
 * Implement the normalize-space() XPath function
9361
 *    string normalize-space(string?)
9362
 * The normalize-space function returns the argument string with white
9363
 * space normalized by stripping leading and trailing whitespace
9364
 * and replacing sequences of whitespace characters by a single
9365
 * space. Whitespace characters are the same allowed by the S production
9366
 * in XML. If the argument is omitted, it defaults to the context
9367
 * node converted to a string, in other words the value of the context node.
9368
 */
9369
void
9370
0
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9371
0
  xmlXPathObjectPtr obj = NULL;
9372
0
  xmlChar *source = NULL;
9373
0
  xmlBufPtr target;
9374
0
  xmlChar blank;
9375
9376
0
  if (ctxt == NULL) return;
9377
0
  if (nargs == 0) {
9378
    /* Use current context node */
9379
0
      valuePush(ctxt,
9380
0
    xmlXPathCacheWrapString(ctxt->context,
9381
0
      xmlXPathCastNodeToString(ctxt->context->node)));
9382
0
    nargs = 1;
9383
0
  }
9384
9385
0
  CHECK_ARITY(1);
9386
0
  CAST_TO_STRING;
9387
0
  CHECK_TYPE(XPATH_STRING);
9388
0
  obj = valuePop(ctxt);
9389
0
  source = obj->stringval;
9390
9391
0
  target = xmlBufCreate();
9392
0
  if (target && source) {
9393
9394
    /* Skip leading whitespaces */
9395
0
    while (IS_BLANK_CH(*source))
9396
0
      source++;
9397
9398
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9399
0
    blank = 0;
9400
0
    while (*source) {
9401
0
      if (IS_BLANK_CH(*source)) {
9402
0
  blank = 0x20;
9403
0
      } else {
9404
0
  if (blank) {
9405
0
    xmlBufAdd(target, &blank, 1);
9406
0
    blank = 0;
9407
0
  }
9408
0
  xmlBufAdd(target, source, 1);
9409
0
      }
9410
0
      source++;
9411
0
    }
9412
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9413
0
  xmlBufContent(target)));
9414
0
    xmlBufFree(target);
9415
0
  }
9416
0
  xmlXPathReleaseObject(ctxt->context, obj);
9417
0
}
9418
9419
/**
9420
 * xmlXPathTranslateFunction:
9421
 * @ctxt:  the XPath Parser context
9422
 * @nargs:  the number of arguments
9423
 *
9424
 * Implement the translate() XPath function
9425
 *    string translate(string, string, string)
9426
 * The translate function returns the first argument string with
9427
 * occurrences of characters in the second argument string replaced
9428
 * by the character at the corresponding position in the third argument
9429
 * string. For example, translate("bar","abc","ABC") returns the string
9430
 * BAr. If there is a character in the second argument string with no
9431
 * character at a corresponding position in the third argument string
9432
 * (because the second argument string is longer than the third argument
9433
 * string), then occurrences of that character in the first argument
9434
 * string are removed. For example, translate("--aaa--","abc-","ABC")
9435
 * returns "AAA". If a character occurs more than once in second
9436
 * argument string, then the first occurrence determines the replacement
9437
 * character. If the third argument string is longer than the second
9438
 * argument string, then excess characters are ignored.
9439
 */
9440
void
9441
0
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9442
0
    xmlXPathObjectPtr str;
9443
0
    xmlXPathObjectPtr from;
9444
0
    xmlXPathObjectPtr to;
9445
0
    xmlBufPtr target;
9446
0
    int offset, max;
9447
0
    xmlChar ch;
9448
0
    const xmlChar *point;
9449
0
    xmlChar *cptr;
9450
9451
0
    CHECK_ARITY(3);
9452
9453
0
    CAST_TO_STRING;
9454
0
    to = valuePop(ctxt);
9455
0
    CAST_TO_STRING;
9456
0
    from = valuePop(ctxt);
9457
0
    CAST_TO_STRING;
9458
0
    str = valuePop(ctxt);
9459
9460
0
    target = xmlBufCreate();
9461
0
    if (target) {
9462
0
  max = xmlUTF8Strlen(to->stringval);
9463
0
  for (cptr = str->stringval; (ch=*cptr); ) {
9464
0
      offset = xmlUTF8Strloc(from->stringval, cptr);
9465
0
      if (offset >= 0) {
9466
0
    if (offset < max) {
9467
0
        point = xmlUTF8Strpos(to->stringval, offset);
9468
0
        if (point)
9469
0
      xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9470
0
    }
9471
0
      } else
9472
0
    xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9473
9474
      /* Step to next character in input */
9475
0
      cptr++;
9476
0
      if ( ch & 0x80 ) {
9477
    /* if not simple ascii, verify proper format */
9478
0
    if ( (ch & 0xc0) != 0xc0 ) {
9479
0
        xmlGenericError(xmlGenericErrorContext,
9480
0
      "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9481
                    /* not asserting an XPath error is probably better */
9482
0
        break;
9483
0
    }
9484
    /* then skip over remaining bytes for this char */
9485
0
    while ( (ch <<= 1) & 0x80 )
9486
0
        if ( (*cptr++ & 0xc0) != 0x80 ) {
9487
0
      xmlGenericError(xmlGenericErrorContext,
9488
0
          "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9489
                        /* not asserting an XPath error is probably better */
9490
0
      break;
9491
0
        }
9492
0
    if (ch & 0x80) /* must have had error encountered */
9493
0
        break;
9494
0
      }
9495
0
  }
9496
0
    }
9497
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9498
0
  xmlBufContent(target)));
9499
0
    xmlBufFree(target);
9500
0
    xmlXPathReleaseObject(ctxt->context, str);
9501
0
    xmlXPathReleaseObject(ctxt->context, from);
9502
0
    xmlXPathReleaseObject(ctxt->context, to);
9503
0
}
9504
9505
/**
9506
 * xmlXPathBooleanFunction:
9507
 * @ctxt:  the XPath Parser context
9508
 * @nargs:  the number of arguments
9509
 *
9510
 * Implement the boolean() XPath function
9511
 *    boolean boolean(object)
9512
 * The boolean function converts its argument to a boolean as follows:
9513
 *    - a number is true if and only if it is neither positive or
9514
 *      negative zero nor NaN
9515
 *    - a node-set is true if and only if it is non-empty
9516
 *    - a string is true if and only if its length is non-zero
9517
 */
9518
void
9519
0
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9520
0
    xmlXPathObjectPtr cur;
9521
9522
0
    CHECK_ARITY(1);
9523
0
    cur = valuePop(ctxt);
9524
0
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9525
0
    cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9526
0
    valuePush(ctxt, cur);
9527
0
}
9528
9529
/**
9530
 * xmlXPathNotFunction:
9531
 * @ctxt:  the XPath Parser context
9532
 * @nargs:  the number of arguments
9533
 *
9534
 * Implement the not() XPath function
9535
 *    boolean not(boolean)
9536
 * The not function returns true if its argument is false,
9537
 * and false otherwise.
9538
 */
9539
void
9540
0
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9541
0
    CHECK_ARITY(1);
9542
0
    CAST_TO_BOOLEAN;
9543
0
    CHECK_TYPE(XPATH_BOOLEAN);
9544
0
    ctxt->value->boolval = ! ctxt->value->boolval;
9545
0
}
9546
9547
/**
9548
 * xmlXPathTrueFunction:
9549
 * @ctxt:  the XPath Parser context
9550
 * @nargs:  the number of arguments
9551
 *
9552
 * Implement the true() XPath function
9553
 *    boolean true()
9554
 */
9555
void
9556
0
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9557
0
    CHECK_ARITY(0);
9558
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9559
0
}
9560
9561
/**
9562
 * xmlXPathFalseFunction:
9563
 * @ctxt:  the XPath Parser context
9564
 * @nargs:  the number of arguments
9565
 *
9566
 * Implement the false() XPath function
9567
 *    boolean false()
9568
 */
9569
void
9570
0
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9571
0
    CHECK_ARITY(0);
9572
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9573
0
}
9574
9575
/**
9576
 * xmlXPathLangFunction:
9577
 * @ctxt:  the XPath Parser context
9578
 * @nargs:  the number of arguments
9579
 *
9580
 * Implement the lang() XPath function
9581
 *    boolean lang(string)
9582
 * The lang function returns true or false depending on whether the
9583
 * language of the context node as specified by xml:lang attributes
9584
 * is the same as or is a sublanguage of the language specified by
9585
 * the argument string. The language of the context node is determined
9586
 * by the value of the xml:lang attribute on the context node, or, if
9587
 * the context node has no xml:lang attribute, by the value of the
9588
 * xml:lang attribute on the nearest ancestor of the context node that
9589
 * has an xml:lang attribute. If there is no such attribute, then lang
9590
 * returns false. If there is such an attribute, then lang returns
9591
 * true if the attribute value is equal to the argument ignoring case,
9592
 * or if there is some suffix starting with - such that the attribute
9593
 * value is equal to the argument ignoring that suffix of the attribute
9594
 * value and ignoring case.
9595
 */
9596
void
9597
0
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9598
0
    xmlXPathObjectPtr val = NULL;
9599
0
    const xmlChar *theLang = NULL;
9600
0
    const xmlChar *lang;
9601
0
    int ret = 0;
9602
0
    int i;
9603
9604
0
    CHECK_ARITY(1);
9605
0
    CAST_TO_STRING;
9606
0
    CHECK_TYPE(XPATH_STRING);
9607
0
    val = valuePop(ctxt);
9608
0
    lang = val->stringval;
9609
0
    theLang = xmlNodeGetLang(ctxt->context->node);
9610
0
    if ((theLang != NULL) && (lang != NULL)) {
9611
0
        for (i = 0;lang[i] != 0;i++)
9612
0
      if (toupper(lang[i]) != toupper(theLang[i]))
9613
0
          goto not_equal;
9614
0
  if ((theLang[i] == 0) || (theLang[i] == '-'))
9615
0
      ret = 1;
9616
0
    }
9617
0
not_equal:
9618
0
    if (theLang != NULL)
9619
0
  xmlFree((void *)theLang);
9620
9621
0
    xmlXPathReleaseObject(ctxt->context, val);
9622
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9623
0
}
9624
9625
/**
9626
 * xmlXPathNumberFunction:
9627
 * @ctxt:  the XPath Parser context
9628
 * @nargs:  the number of arguments
9629
 *
9630
 * Implement the number() XPath function
9631
 *    number number(object?)
9632
 */
9633
void
9634
0
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9635
0
    xmlXPathObjectPtr cur;
9636
0
    double res;
9637
9638
0
    if (ctxt == NULL) return;
9639
0
    if (nargs == 0) {
9640
0
  if (ctxt->context->node == NULL) {
9641
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9642
0
  } else {
9643
0
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9644
9645
0
      res = xmlXPathStringEvalNumber(content);
9646
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9647
0
      xmlFree(content);
9648
0
  }
9649
0
  return;
9650
0
    }
9651
9652
0
    CHECK_ARITY(1);
9653
0
    cur = valuePop(ctxt);
9654
0
    valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9655
0
}
9656
9657
/**
9658
 * xmlXPathSumFunction:
9659
 * @ctxt:  the XPath Parser context
9660
 * @nargs:  the number of arguments
9661
 *
9662
 * Implement the sum() XPath function
9663
 *    number sum(node-set)
9664
 * The sum function returns the sum of the values of the nodes in
9665
 * the argument node-set.
9666
 */
9667
void
9668
0
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9669
0
    xmlXPathObjectPtr cur;
9670
0
    int i;
9671
0
    double res = 0.0;
9672
9673
0
    CHECK_ARITY(1);
9674
0
    if ((ctxt->value == NULL) ||
9675
0
  ((ctxt->value->type != XPATH_NODESET) &&
9676
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
9677
0
  XP_ERROR(XPATH_INVALID_TYPE);
9678
0
    cur = valuePop(ctxt);
9679
9680
0
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9681
0
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9682
0
      res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9683
0
  }
9684
0
    }
9685
0
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9686
0
    xmlXPathReleaseObject(ctxt->context, cur);
9687
0
}
9688
9689
/**
9690
 * xmlXPathFloorFunction:
9691
 * @ctxt:  the XPath Parser context
9692
 * @nargs:  the number of arguments
9693
 *
9694
 * Implement the floor() XPath function
9695
 *    number floor(number)
9696
 * The floor function returns the largest (closest to positive infinity)
9697
 * number that is not greater than the argument and that is an integer.
9698
 */
9699
void
9700
0
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9701
0
    CHECK_ARITY(1);
9702
0
    CAST_TO_NUMBER;
9703
0
    CHECK_TYPE(XPATH_NUMBER);
9704
9705
0
    ctxt->value->floatval = floor(ctxt->value->floatval);
9706
0
}
9707
9708
/**
9709
 * xmlXPathCeilingFunction:
9710
 * @ctxt:  the XPath Parser context
9711
 * @nargs:  the number of arguments
9712
 *
9713
 * Implement the ceiling() XPath function
9714
 *    number ceiling(number)
9715
 * The ceiling function returns the smallest (closest to negative infinity)
9716
 * number that is not less than the argument and that is an integer.
9717
 */
9718
void
9719
0
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9720
0
    CHECK_ARITY(1);
9721
0
    CAST_TO_NUMBER;
9722
0
    CHECK_TYPE(XPATH_NUMBER);
9723
9724
0
    ctxt->value->floatval = ceil(ctxt->value->floatval);
9725
0
}
9726
9727
/**
9728
 * xmlXPathRoundFunction:
9729
 * @ctxt:  the XPath Parser context
9730
 * @nargs:  the number of arguments
9731
 *
9732
 * Implement the round() XPath function
9733
 *    number round(number)
9734
 * The round function returns the number that is closest to the
9735
 * argument and that is an integer. If there are two such numbers,
9736
 * then the one that is closest to positive infinity is returned.
9737
 */
9738
void
9739
0
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9740
0
    double f;
9741
9742
0
    CHECK_ARITY(1);
9743
0
    CAST_TO_NUMBER;
9744
0
    CHECK_TYPE(XPATH_NUMBER);
9745
9746
0
    f = ctxt->value->floatval;
9747
9748
    /* Test for zero to keep negative zero unchanged. */
9749
0
    if ((xmlXPathIsNaN(f)) || (f == 0.0))
9750
0
  return;
9751
9752
0
    if ((f >= -0.5) && (f < 0.0)) {
9753
        /* Negative zero. */
9754
0
        ctxt->value->floatval = xmlXPathNZERO;
9755
0
    }
9756
0
    else {
9757
0
        double rounded = floor(f);
9758
0
        if (f - rounded >= 0.5)
9759
0
            rounded += 1.0;
9760
0
        ctxt->value->floatval = rounded;
9761
0
    }
9762
0
}
9763
9764
/************************************************************************
9765
 *                  *
9766
 *      The Parser          *
9767
 *                  *
9768
 ************************************************************************/
9769
9770
/*
9771
 * a few forward declarations since we use a recursive call based
9772
 * implementation.
9773
 */
9774
static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9775
static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9776
static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9777
static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9778
static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9779
                                    int qualified);
9780
9781
/**
9782
 * xmlXPathCurrentChar:
9783
 * @ctxt:  the XPath parser context
9784
 * @cur:  pointer to the beginning of the char
9785
 * @len:  pointer to the length of the char read
9786
 *
9787
 * The current char value, if using UTF-8 this may actually span multiple
9788
 * bytes in the input buffer.
9789
 *
9790
 * Returns the current char value and its length
9791
 */
9792
9793
static int
9794
0
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9795
0
    unsigned char c;
9796
0
    unsigned int val;
9797
0
    const xmlChar *cur;
9798
9799
0
    if (ctxt == NULL)
9800
0
  return(0);
9801
0
    cur = ctxt->cur;
9802
9803
    /*
9804
     * We are supposed to handle UTF8, check it's valid
9805
     * From rfc2044: encoding of the Unicode values on UTF-8:
9806
     *
9807
     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9808
     * 0000 0000-0000 007F   0xxxxxxx
9809
     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9810
     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9811
     *
9812
     * Check for the 0x110000 limit too
9813
     */
9814
0
    c = *cur;
9815
0
    if (c & 0x80) {
9816
0
  if ((cur[1] & 0xc0) != 0x80)
9817
0
      goto encoding_error;
9818
0
  if ((c & 0xe0) == 0xe0) {
9819
9820
0
      if ((cur[2] & 0xc0) != 0x80)
9821
0
    goto encoding_error;
9822
0
      if ((c & 0xf0) == 0xf0) {
9823
0
    if (((c & 0xf8) != 0xf0) ||
9824
0
        ((cur[3] & 0xc0) != 0x80))
9825
0
        goto encoding_error;
9826
    /* 4-byte code */
9827
0
    *len = 4;
9828
0
    val = (cur[0] & 0x7) << 18;
9829
0
    val |= (cur[1] & 0x3f) << 12;
9830
0
    val |= (cur[2] & 0x3f) << 6;
9831
0
    val |= cur[3] & 0x3f;
9832
0
      } else {
9833
        /* 3-byte code */
9834
0
    *len = 3;
9835
0
    val = (cur[0] & 0xf) << 12;
9836
0
    val |= (cur[1] & 0x3f) << 6;
9837
0
    val |= cur[2] & 0x3f;
9838
0
      }
9839
0
  } else {
9840
    /* 2-byte code */
9841
0
      *len = 2;
9842
0
      val = (cur[0] & 0x1f) << 6;
9843
0
      val |= cur[1] & 0x3f;
9844
0
  }
9845
0
  if (!IS_CHAR(val)) {
9846
0
      XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9847
0
  }
9848
0
  return(val);
9849
0
    } else {
9850
  /* 1-byte code */
9851
0
  *len = 1;
9852
0
  return((int) *cur);
9853
0
    }
9854
0
encoding_error:
9855
    /*
9856
     * If we detect an UTF8 error that probably means that the
9857
     * input encoding didn't get properly advertised in the
9858
     * declaration header. Report the error and switch the encoding
9859
     * to ISO-Latin-1 (if you don't like this policy, just declare the
9860
     * encoding !)
9861
     */
9862
0
    *len = 0;
9863
0
    XP_ERROR0(XPATH_ENCODING_ERROR);
9864
0
}
9865
9866
/**
9867
 * xmlXPathParseNCName:
9868
 * @ctxt:  the XPath Parser context
9869
 *
9870
 * parse an XML namespace non qualified name.
9871
 *
9872
 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9873
 *
9874
 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9875
 *                       CombiningChar | Extender
9876
 *
9877
 * Returns the namespace name or NULL
9878
 */
9879
9880
xmlChar *
9881
0
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9882
0
    const xmlChar *in;
9883
0
    xmlChar *ret;
9884
0
    int count = 0;
9885
9886
0
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9887
    /*
9888
     * Accelerator for simple ASCII names
9889
     */
9890
0
    in = ctxt->cur;
9891
0
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9892
0
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9893
0
  (*in == '_')) {
9894
0
  in++;
9895
0
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9896
0
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9897
0
         ((*in >= 0x30) && (*in <= 0x39)) ||
9898
0
         (*in == '_') || (*in == '.') ||
9899
0
         (*in == '-'))
9900
0
      in++;
9901
0
  if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9902
0
            (*in == '[') || (*in == ']') || (*in == ':') ||
9903
0
            (*in == '@') || (*in == '*')) {
9904
0
      count = in - ctxt->cur;
9905
0
      if (count == 0)
9906
0
    return(NULL);
9907
0
      ret = xmlStrndup(ctxt->cur, count);
9908
0
      ctxt->cur = in;
9909
0
      return(ret);
9910
0
  }
9911
0
    }
9912
0
    return(xmlXPathParseNameComplex(ctxt, 0));
9913
0
}
9914
9915
9916
/**
9917
 * xmlXPathParseQName:
9918
 * @ctxt:  the XPath Parser context
9919
 * @prefix:  a xmlChar **
9920
 *
9921
 * parse an XML qualified name
9922
 *
9923
 * [NS 5] QName ::= (Prefix ':')? LocalPart
9924
 *
9925
 * [NS 6] Prefix ::= NCName
9926
 *
9927
 * [NS 7] LocalPart ::= NCName
9928
 *
9929
 * Returns the function returns the local part, and prefix is updated
9930
 *   to get the Prefix if any.
9931
 */
9932
9933
static xmlChar *
9934
0
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9935
0
    xmlChar *ret = NULL;
9936
9937
0
    *prefix = NULL;
9938
0
    ret = xmlXPathParseNCName(ctxt);
9939
0
    if (ret && CUR == ':') {
9940
0
        *prefix = ret;
9941
0
  NEXT;
9942
0
  ret = xmlXPathParseNCName(ctxt);
9943
0
    }
9944
0
    return(ret);
9945
0
}
9946
9947
/**
9948
 * xmlXPathParseName:
9949
 * @ctxt:  the XPath Parser context
9950
 *
9951
 * parse an XML name
9952
 *
9953
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9954
 *                  CombiningChar | Extender
9955
 *
9956
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9957
 *
9958
 * Returns the namespace name or NULL
9959
 */
9960
9961
xmlChar *
9962
0
xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9963
0
    const xmlChar *in;
9964
0
    xmlChar *ret;
9965
0
    size_t count = 0;
9966
9967
0
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9968
    /*
9969
     * Accelerator for simple ASCII names
9970
     */
9971
0
    in = ctxt->cur;
9972
0
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9973
0
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9974
0
  (*in == '_') || (*in == ':')) {
9975
0
  in++;
9976
0
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9977
0
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9978
0
         ((*in >= 0x30) && (*in <= 0x39)) ||
9979
0
         (*in == '_') || (*in == '-') ||
9980
0
         (*in == ':') || (*in == '.'))
9981
0
      in++;
9982
0
  if ((*in > 0) && (*in < 0x80)) {
9983
0
      count = in - ctxt->cur;
9984
0
            if (count > XML_MAX_NAME_LENGTH) {
9985
0
                ctxt->cur = in;
9986
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9987
0
            }
9988
0
      ret = xmlStrndup(ctxt->cur, count);
9989
0
      ctxt->cur = in;
9990
0
      return(ret);
9991
0
  }
9992
0
    }
9993
0
    return(xmlXPathParseNameComplex(ctxt, 1));
9994
0
}
9995
9996
static xmlChar *
9997
0
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9998
0
    xmlChar buf[XML_MAX_NAMELEN + 5];
9999
0
    int len = 0, l;
10000
0
    int c;
10001
10002
    /*
10003
     * Handler for more complex cases
10004
     */
10005
0
    c = CUR_CHAR(l);
10006
0
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10007
0
        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
10008
0
        (c == '*') || /* accelerators */
10009
0
  (!IS_LETTER(c) && (c != '_') &&
10010
0
         ((!qualified) || (c != ':')))) {
10011
0
  return(NULL);
10012
0
    }
10013
10014
0
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10015
0
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10016
0
            (c == '.') || (c == '-') ||
10017
0
      (c == '_') || ((qualified) && (c == ':')) ||
10018
0
      (IS_COMBINING(c)) ||
10019
0
      (IS_EXTENDER(c)))) {
10020
0
  COPY_BUF(l,buf,len,c);
10021
0
  NEXTL(l);
10022
0
  c = CUR_CHAR(l);
10023
0
  if (len >= XML_MAX_NAMELEN) {
10024
      /*
10025
       * Okay someone managed to make a huge name, so he's ready to pay
10026
       * for the processing speed.
10027
       */
10028
0
      xmlChar *buffer;
10029
0
      int max = len * 2;
10030
10031
0
            if (len > XML_MAX_NAME_LENGTH) {
10032
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
10033
0
            }
10034
0
      buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
10035
0
      if (buffer == NULL) {
10036
0
    XP_ERRORNULL(XPATH_MEMORY_ERROR);
10037
0
      }
10038
0
      memcpy(buffer, buf, len);
10039
0
      while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
10040
0
       (c == '.') || (c == '-') ||
10041
0
       (c == '_') || ((qualified) && (c == ':')) ||
10042
0
       (IS_COMBINING(c)) ||
10043
0
       (IS_EXTENDER(c))) {
10044
0
    if (len + 10 > max) {
10045
0
                    if (max > XML_MAX_NAME_LENGTH) {
10046
0
                        XP_ERRORNULL(XPATH_EXPR_ERROR);
10047
0
                    }
10048
0
        max *= 2;
10049
0
        buffer = (xmlChar *) xmlRealloc(buffer,
10050
0
                                  max * sizeof(xmlChar));
10051
0
        if (buffer == NULL) {
10052
0
      XP_ERRORNULL(XPATH_MEMORY_ERROR);
10053
0
        }
10054
0
    }
10055
0
    COPY_BUF(l,buffer,len,c);
10056
0
    NEXTL(l);
10057
0
    c = CUR_CHAR(l);
10058
0
      }
10059
0
      buffer[len] = 0;
10060
0
      return(buffer);
10061
0
  }
10062
0
    }
10063
0
    if (len == 0)
10064
0
  return(NULL);
10065
0
    return(xmlStrndup(buf, len));
10066
0
}
10067
10068
0
#define MAX_FRAC 20
10069
10070
/**
10071
 * xmlXPathStringEvalNumber:
10072
 * @str:  A string to scan
10073
 *
10074
 *  [30a]  Float  ::= Number ('e' Digits?)?
10075
 *
10076
 *  [30]   Number ::=   Digits ('.' Digits?)?
10077
 *                    | '.' Digits
10078
 *  [31]   Digits ::=   [0-9]+
10079
 *
10080
 * Compile a Number in the string
10081
 * In complement of the Number expression, this function also handles
10082
 * negative values : '-' Number.
10083
 *
10084
 * Returns the double value.
10085
 */
10086
double
10087
0
xmlXPathStringEvalNumber(const xmlChar *str) {
10088
0
    const xmlChar *cur = str;
10089
0
    double ret;
10090
0
    int ok = 0;
10091
0
    int isneg = 0;
10092
0
    int exponent = 0;
10093
0
    int is_exponent_negative = 0;
10094
0
#ifdef __GNUC__
10095
0
    unsigned long tmp = 0;
10096
0
    double temp;
10097
0
#endif
10098
0
    if (cur == NULL) return(0);
10099
0
    while (IS_BLANK_CH(*cur)) cur++;
10100
0
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10101
0
        return(xmlXPathNAN);
10102
0
    }
10103
0
    if (*cur == '-') {
10104
0
  isneg = 1;
10105
0
  cur++;
10106
0
    }
10107
10108
0
#ifdef __GNUC__
10109
    /*
10110
     * tmp/temp is a workaround against a gcc compiler bug
10111
     * http://veillard.com/gcc.bug
10112
     */
10113
0
    ret = 0;
10114
0
    while ((*cur >= '0') && (*cur <= '9')) {
10115
0
  ret = ret * 10;
10116
0
  tmp = (*cur - '0');
10117
0
  ok = 1;
10118
0
  cur++;
10119
0
  temp = (double) tmp;
10120
0
  ret = ret + temp;
10121
0
    }
10122
#else
10123
    ret = 0;
10124
    while ((*cur >= '0') && (*cur <= '9')) {
10125
  ret = ret * 10 + (*cur - '0');
10126
  ok = 1;
10127
  cur++;
10128
    }
10129
#endif
10130
10131
0
    if (*cur == '.') {
10132
0
  int v, frac = 0, max;
10133
0
  double fraction = 0;
10134
10135
0
        cur++;
10136
0
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10137
0
      return(xmlXPathNAN);
10138
0
  }
10139
0
        while (*cur == '0') {
10140
0
      frac = frac + 1;
10141
0
      cur++;
10142
0
        }
10143
0
        max = frac + MAX_FRAC;
10144
0
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10145
0
      v = (*cur - '0');
10146
0
      fraction = fraction * 10 + v;
10147
0
      frac = frac + 1;
10148
0
      cur++;
10149
0
  }
10150
0
  fraction /= pow(10.0, frac);
10151
0
  ret = ret + fraction;
10152
0
  while ((*cur >= '0') && (*cur <= '9'))
10153
0
      cur++;
10154
0
    }
10155
0
    if ((*cur == 'e') || (*cur == 'E')) {
10156
0
      cur++;
10157
0
      if (*cur == '-') {
10158
0
  is_exponent_negative = 1;
10159
0
  cur++;
10160
0
      } else if (*cur == '+') {
10161
0
        cur++;
10162
0
      }
10163
0
      while ((*cur >= '0') && (*cur <= '9')) {
10164
0
        if (exponent < 1000000)
10165
0
    exponent = exponent * 10 + (*cur - '0');
10166
0
  cur++;
10167
0
      }
10168
0
    }
10169
0
    while (IS_BLANK_CH(*cur)) cur++;
10170
0
    if (*cur != 0) return(xmlXPathNAN);
10171
0
    if (isneg) ret = -ret;
10172
0
    if (is_exponent_negative) exponent = -exponent;
10173
0
    ret *= pow(10.0, (double)exponent);
10174
0
    return(ret);
10175
0
}
10176
10177
/**
10178
 * xmlXPathCompNumber:
10179
 * @ctxt:  the XPath Parser context
10180
 *
10181
 *  [30]   Number ::=   Digits ('.' Digits?)?
10182
 *                    | '.' Digits
10183
 *  [31]   Digits ::=   [0-9]+
10184
 *
10185
 * Compile a Number, then push it on the stack
10186
 *
10187
 */
10188
static void
10189
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10190
0
{
10191
0
    double ret = 0.0;
10192
0
    int ok = 0;
10193
0
    int exponent = 0;
10194
0
    int is_exponent_negative = 0;
10195
0
#ifdef __GNUC__
10196
0
    unsigned long tmp = 0;
10197
0
    double temp;
10198
0
#endif
10199
10200
0
    CHECK_ERROR;
10201
0
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10202
0
        XP_ERROR(XPATH_NUMBER_ERROR);
10203
0
    }
10204
0
#ifdef __GNUC__
10205
    /*
10206
     * tmp/temp is a workaround against a gcc compiler bug
10207
     * http://veillard.com/gcc.bug
10208
     */
10209
0
    ret = 0;
10210
0
    while ((CUR >= '0') && (CUR <= '9')) {
10211
0
  ret = ret * 10;
10212
0
  tmp = (CUR - '0');
10213
0
        ok = 1;
10214
0
        NEXT;
10215
0
  temp = (double) tmp;
10216
0
  ret = ret + temp;
10217
0
    }
10218
#else
10219
    ret = 0;
10220
    while ((CUR >= '0') && (CUR <= '9')) {
10221
  ret = ret * 10 + (CUR - '0');
10222
  ok = 1;
10223
  NEXT;
10224
    }
10225
#endif
10226
0
    if (CUR == '.') {
10227
0
  int v, frac = 0, max;
10228
0
  double fraction = 0;
10229
10230
0
        NEXT;
10231
0
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10232
0
            XP_ERROR(XPATH_NUMBER_ERROR);
10233
0
        }
10234
0
        while (CUR == '0') {
10235
0
            frac = frac + 1;
10236
0
            NEXT;
10237
0
        }
10238
0
        max = frac + MAX_FRAC;
10239
0
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10240
0
      v = (CUR - '0');
10241
0
      fraction = fraction * 10 + v;
10242
0
      frac = frac + 1;
10243
0
            NEXT;
10244
0
        }
10245
0
        fraction /= pow(10.0, frac);
10246
0
        ret = ret + fraction;
10247
0
        while ((CUR >= '0') && (CUR <= '9'))
10248
0
            NEXT;
10249
0
    }
10250
0
    if ((CUR == 'e') || (CUR == 'E')) {
10251
0
        NEXT;
10252
0
        if (CUR == '-') {
10253
0
            is_exponent_negative = 1;
10254
0
            NEXT;
10255
0
        } else if (CUR == '+') {
10256
0
      NEXT;
10257
0
  }
10258
0
        while ((CUR >= '0') && (CUR <= '9')) {
10259
0
            if (exponent < 1000000)
10260
0
                exponent = exponent * 10 + (CUR - '0');
10261
0
            NEXT;
10262
0
        }
10263
0
        if (is_exponent_negative)
10264
0
            exponent = -exponent;
10265
0
        ret *= pow(10.0, (double) exponent);
10266
0
    }
10267
0
    PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10268
0
                   xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10269
0
}
10270
10271
/**
10272
 * xmlXPathParseLiteral:
10273
 * @ctxt:  the XPath Parser context
10274
 *
10275
 * Parse a Literal
10276
 *
10277
 *  [29]   Literal ::=   '"' [^"]* '"'
10278
 *                    | "'" [^']* "'"
10279
 *
10280
 * Returns the value found or NULL in case of error
10281
 */
10282
static xmlChar *
10283
0
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10284
0
    const xmlChar *q;
10285
0
    xmlChar *ret = NULL;
10286
10287
0
    if (CUR == '"') {
10288
0
        NEXT;
10289
0
  q = CUR_PTR;
10290
0
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10291
0
      NEXT;
10292
0
  if (!IS_CHAR_CH(CUR)) {
10293
0
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10294
0
  } else {
10295
0
      ret = xmlStrndup(q, CUR_PTR - q);
10296
0
      NEXT;
10297
0
        }
10298
0
    } else if (CUR == '\'') {
10299
0
        NEXT;
10300
0
  q = CUR_PTR;
10301
0
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10302
0
      NEXT;
10303
0
  if (!IS_CHAR_CH(CUR)) {
10304
0
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10305
0
  } else {
10306
0
      ret = xmlStrndup(q, CUR_PTR - q);
10307
0
      NEXT;
10308
0
        }
10309
0
    } else {
10310
0
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10311
0
    }
10312
0
    return(ret);
10313
0
}
10314
10315
/**
10316
 * xmlXPathCompLiteral:
10317
 * @ctxt:  the XPath Parser context
10318
 *
10319
 * Parse a Literal and push it on the stack.
10320
 *
10321
 *  [29]   Literal ::=   '"' [^"]* '"'
10322
 *                    | "'" [^']* "'"
10323
 *
10324
 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10325
 */
10326
static void
10327
0
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10328
0
    const xmlChar *q;
10329
0
    xmlChar *ret = NULL;
10330
10331
0
    if (CUR == '"') {
10332
0
        NEXT;
10333
0
  q = CUR_PTR;
10334
0
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10335
0
      NEXT;
10336
0
  if (!IS_CHAR_CH(CUR)) {
10337
0
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10338
0
  } else {
10339
0
      ret = xmlStrndup(q, CUR_PTR - q);
10340
0
      NEXT;
10341
0
        }
10342
0
    } else if (CUR == '\'') {
10343
0
        NEXT;
10344
0
  q = CUR_PTR;
10345
0
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10346
0
      NEXT;
10347
0
  if (!IS_CHAR_CH(CUR)) {
10348
0
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10349
0
  } else {
10350
0
      ret = xmlStrndup(q, CUR_PTR - q);
10351
0
      NEXT;
10352
0
        }
10353
0
    } else {
10354
0
  XP_ERROR(XPATH_START_LITERAL_ERROR);
10355
0
    }
10356
0
    if (ret == NULL) return;
10357
0
    PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10358
0
             xmlXPathCacheNewString(ctxt->context, ret), NULL);
10359
0
    xmlFree(ret);
10360
0
}
10361
10362
/**
10363
 * xmlXPathCompVariableReference:
10364
 * @ctxt:  the XPath Parser context
10365
 *
10366
 * Parse a VariableReference, evaluate it and push it on the stack.
10367
 *
10368
 * The variable bindings consist of a mapping from variable names
10369
 * to variable values. The value of a variable is an object, which can be
10370
 * of any of the types that are possible for the value of an expression,
10371
 * and may also be of additional types not specified here.
10372
 *
10373
 * Early evaluation is possible since:
10374
 * The variable bindings [...] used to evaluate a subexpression are
10375
 * always the same as those used to evaluate the containing expression.
10376
 *
10377
 *  [36]   VariableReference ::=   '$' QName
10378
 */
10379
static void
10380
0
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10381
0
    xmlChar *name;
10382
0
    xmlChar *prefix;
10383
10384
0
    SKIP_BLANKS;
10385
0
    if (CUR != '$') {
10386
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10387
0
    }
10388
0
    NEXT;
10389
0
    name = xmlXPathParseQName(ctxt, &prefix);
10390
0
    if (name == NULL) {
10391
0
        xmlFree(prefix);
10392
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10393
0
    }
10394
0
    ctxt->comp->last = -1;
10395
0
    PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10396
0
             name, prefix);
10397
0
    SKIP_BLANKS;
10398
0
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10399
0
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10400
0
    }
10401
0
}
10402
10403
/**
10404
 * xmlXPathIsNodeType:
10405
 * @name:  a name string
10406
 *
10407
 * Is the name given a NodeType one.
10408
 *
10409
 *  [38]   NodeType ::=   'comment'
10410
 *                    | 'text'
10411
 *                    | 'processing-instruction'
10412
 *                    | 'node'
10413
 *
10414
 * Returns 1 if true 0 otherwise
10415
 */
10416
int
10417
0
xmlXPathIsNodeType(const xmlChar *name) {
10418
0
    if (name == NULL)
10419
0
  return(0);
10420
10421
0
    if (xmlStrEqual(name, BAD_CAST "node"))
10422
0
  return(1);
10423
0
    if (xmlStrEqual(name, BAD_CAST "text"))
10424
0
  return(1);
10425
0
    if (xmlStrEqual(name, BAD_CAST "comment"))
10426
0
  return(1);
10427
0
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10428
0
  return(1);
10429
0
    return(0);
10430
0
}
10431
10432
/**
10433
 * xmlXPathCompFunctionCall:
10434
 * @ctxt:  the XPath Parser context
10435
 *
10436
 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10437
 *  [17]   Argument ::=   Expr
10438
 *
10439
 * Compile a function call, the evaluation of all arguments are
10440
 * pushed on the stack
10441
 */
10442
static void
10443
0
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10444
0
    xmlChar *name;
10445
0
    xmlChar *prefix;
10446
0
    int nbargs = 0;
10447
0
    int sort = 1;
10448
10449
0
    name = xmlXPathParseQName(ctxt, &prefix);
10450
0
    if (name == NULL) {
10451
0
  xmlFree(prefix);
10452
0
  XP_ERROR(XPATH_EXPR_ERROR);
10453
0
    }
10454
0
    SKIP_BLANKS;
10455
#ifdef DEBUG_EXPR
10456
    if (prefix == NULL)
10457
  xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10458
      name);
10459
    else
10460
  xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10461
      prefix, name);
10462
#endif
10463
10464
0
    if (CUR != '(') {
10465
0
  xmlFree(name);
10466
0
  xmlFree(prefix);
10467
0
  XP_ERROR(XPATH_EXPR_ERROR);
10468
0
    }
10469
0
    NEXT;
10470
0
    SKIP_BLANKS;
10471
10472
    /*
10473
    * Optimization for count(): we don't need the node-set to be sorted.
10474
    */
10475
0
    if ((prefix == NULL) && (name[0] == 'c') &&
10476
0
  xmlStrEqual(name, BAD_CAST "count"))
10477
0
    {
10478
0
  sort = 0;
10479
0
    }
10480
0
    ctxt->comp->last = -1;
10481
0
    if (CUR != ')') {
10482
0
  while (CUR != 0) {
10483
0
      int op1 = ctxt->comp->last;
10484
0
      ctxt->comp->last = -1;
10485
0
      xmlXPathCompileExpr(ctxt, sort);
10486
0
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10487
0
    xmlFree(name);
10488
0
    xmlFree(prefix);
10489
0
    return;
10490
0
      }
10491
0
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10492
0
      nbargs++;
10493
0
      if (CUR == ')') break;
10494
0
      if (CUR != ',') {
10495
0
    xmlFree(name);
10496
0
    xmlFree(prefix);
10497
0
    XP_ERROR(XPATH_EXPR_ERROR);
10498
0
      }
10499
0
      NEXT;
10500
0
      SKIP_BLANKS;
10501
0
  }
10502
0
    }
10503
0
    PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10504
0
             name, prefix);
10505
0
    NEXT;
10506
0
    SKIP_BLANKS;
10507
0
}
10508
10509
/**
10510
 * xmlXPathCompPrimaryExpr:
10511
 * @ctxt:  the XPath Parser context
10512
 *
10513
 *  [15]   PrimaryExpr ::=   VariableReference
10514
 *                | '(' Expr ')'
10515
 *                | Literal
10516
 *                | Number
10517
 *                | FunctionCall
10518
 *
10519
 * Compile a primary expression.
10520
 */
10521
static void
10522
0
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10523
0
    SKIP_BLANKS;
10524
0
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10525
0
    else if (CUR == '(') {
10526
0
  NEXT;
10527
0
  SKIP_BLANKS;
10528
0
  xmlXPathCompileExpr(ctxt, 1);
10529
0
  CHECK_ERROR;
10530
0
  if (CUR != ')') {
10531
0
      XP_ERROR(XPATH_EXPR_ERROR);
10532
0
  }
10533
0
  NEXT;
10534
0
  SKIP_BLANKS;
10535
0
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10536
0
  xmlXPathCompNumber(ctxt);
10537
0
    } else if ((CUR == '\'') || (CUR == '"')) {
10538
0
  xmlXPathCompLiteral(ctxt);
10539
0
    } else {
10540
0
  xmlXPathCompFunctionCall(ctxt);
10541
0
    }
10542
0
    SKIP_BLANKS;
10543
0
}
10544
10545
/**
10546
 * xmlXPathCompFilterExpr:
10547
 * @ctxt:  the XPath Parser context
10548
 *
10549
 *  [20]   FilterExpr ::=   PrimaryExpr
10550
 *               | FilterExpr Predicate
10551
 *
10552
 * Compile a filter expression.
10553
 * Square brackets are used to filter expressions in the same way that
10554
 * they are used in location paths. It is an error if the expression to
10555
 * be filtered does not evaluate to a node-set. The context node list
10556
 * used for evaluating the expression in square brackets is the node-set
10557
 * to be filtered listed in document order.
10558
 */
10559
10560
static void
10561
0
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10562
0
    xmlXPathCompPrimaryExpr(ctxt);
10563
0
    CHECK_ERROR;
10564
0
    SKIP_BLANKS;
10565
10566
0
    while (CUR == '[') {
10567
0
  xmlXPathCompPredicate(ctxt, 1);
10568
0
  SKIP_BLANKS;
10569
0
    }
10570
10571
10572
0
}
10573
10574
/**
10575
 * xmlXPathScanName:
10576
 * @ctxt:  the XPath Parser context
10577
 *
10578
 * Trickery: parse an XML name but without consuming the input flow
10579
 * Needed to avoid insanity in the parser state.
10580
 *
10581
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10582
 *                  CombiningChar | Extender
10583
 *
10584
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10585
 *
10586
 * [6] Names ::= Name (S Name)*
10587
 *
10588
 * Returns the Name parsed or NULL
10589
 */
10590
10591
static xmlChar *
10592
0
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10593
0
    int len = 0, l;
10594
0
    int c;
10595
0
    const xmlChar *cur;
10596
0
    xmlChar *ret;
10597
10598
0
    cur = ctxt->cur;
10599
10600
0
    c = CUR_CHAR(l);
10601
0
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10602
0
  (!IS_LETTER(c) && (c != '_') &&
10603
0
         (c != ':'))) {
10604
0
  return(NULL);
10605
0
    }
10606
10607
0
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10608
0
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10609
0
            (c == '.') || (c == '-') ||
10610
0
      (c == '_') || (c == ':') ||
10611
0
      (IS_COMBINING(c)) ||
10612
0
      (IS_EXTENDER(c)))) {
10613
0
  len += l;
10614
0
  NEXTL(l);
10615
0
  c = CUR_CHAR(l);
10616
0
    }
10617
0
    ret = xmlStrndup(cur, ctxt->cur - cur);
10618
0
    ctxt->cur = cur;
10619
0
    return(ret);
10620
0
}
10621
10622
/**
10623
 * xmlXPathCompPathExpr:
10624
 * @ctxt:  the XPath Parser context
10625
 *
10626
 *  [19]   PathExpr ::=   LocationPath
10627
 *               | FilterExpr
10628
 *               | FilterExpr '/' RelativeLocationPath
10629
 *               | FilterExpr '//' RelativeLocationPath
10630
 *
10631
 * Compile a path expression.
10632
 * The / operator and // operators combine an arbitrary expression
10633
 * and a relative location path. It is an error if the expression
10634
 * does not evaluate to a node-set.
10635
 * The / operator does composition in the same way as when / is
10636
 * used in a location path. As in location paths, // is short for
10637
 * /descendant-or-self::node()/.
10638
 */
10639
10640
static void
10641
0
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10642
0
    int lc = 1;           /* Should we branch to LocationPath ?         */
10643
0
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
10644
10645
0
    SKIP_BLANKS;
10646
0
    if ((CUR == '$') || (CUR == '(') ||
10647
0
  (IS_ASCII_DIGIT(CUR)) ||
10648
0
        (CUR == '\'') || (CUR == '"') ||
10649
0
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10650
0
  lc = 0;
10651
0
    } else if (CUR == '*') {
10652
  /* relative or absolute location path */
10653
0
  lc = 1;
10654
0
    } else if (CUR == '/') {
10655
  /* relative or absolute location path */
10656
0
  lc = 1;
10657
0
    } else if (CUR == '@') {
10658
  /* relative abbreviated attribute location path */
10659
0
  lc = 1;
10660
0
    } else if (CUR == '.') {
10661
  /* relative abbreviated attribute location path */
10662
0
  lc = 1;
10663
0
    } else {
10664
  /*
10665
   * Problem is finding if we have a name here whether it's:
10666
   *   - a nodetype
10667
   *   - a function call in which case it's followed by '('
10668
   *   - an axis in which case it's followed by ':'
10669
   *   - a element name
10670
   * We do an a priori analysis here rather than having to
10671
   * maintain parsed token content through the recursive function
10672
   * calls. This looks uglier but makes the code easier to
10673
   * read/write/debug.
10674
   */
10675
0
  SKIP_BLANKS;
10676
0
  name = xmlXPathScanName(ctxt);
10677
0
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10678
#ifdef DEBUG_STEP
10679
      xmlGenericError(xmlGenericErrorContext,
10680
        "PathExpr: Axis\n");
10681
#endif
10682
0
      lc = 1;
10683
0
      xmlFree(name);
10684
0
  } else if (name != NULL) {
10685
0
      int len =xmlStrlen(name);
10686
10687
10688
0
      while (NXT(len) != 0) {
10689
0
    if (NXT(len) == '/') {
10690
        /* element name */
10691
#ifdef DEBUG_STEP
10692
        xmlGenericError(xmlGenericErrorContext,
10693
          "PathExpr: AbbrRelLocation\n");
10694
#endif
10695
0
        lc = 1;
10696
0
        break;
10697
0
    } else if (IS_BLANK_CH(NXT(len))) {
10698
        /* ignore blanks */
10699
0
        ;
10700
0
    } else if (NXT(len) == ':') {
10701
#ifdef DEBUG_STEP
10702
        xmlGenericError(xmlGenericErrorContext,
10703
          "PathExpr: AbbrRelLocation\n");
10704
#endif
10705
0
        lc = 1;
10706
0
        break;
10707
0
    } else if ((NXT(len) == '(')) {
10708
        /* Node Type or Function */
10709
0
        if (xmlXPathIsNodeType(name)) {
10710
#ifdef DEBUG_STEP
10711
            xmlGenericError(xmlGenericErrorContext,
10712
        "PathExpr: Type search\n");
10713
#endif
10714
0
      lc = 1;
10715
0
#ifdef LIBXML_XPTR_ENABLED
10716
0
                    } else if (ctxt->xptr &&
10717
0
                               xmlStrEqual(name, BAD_CAST "range-to")) {
10718
0
                        lc = 1;
10719
0
#endif
10720
0
        } else {
10721
#ifdef DEBUG_STEP
10722
            xmlGenericError(xmlGenericErrorContext,
10723
        "PathExpr: function call\n");
10724
#endif
10725
0
      lc = 0;
10726
0
        }
10727
0
                    break;
10728
0
    } else if ((NXT(len) == '[')) {
10729
        /* element name */
10730
#ifdef DEBUG_STEP
10731
        xmlGenericError(xmlGenericErrorContext,
10732
          "PathExpr: AbbrRelLocation\n");
10733
#endif
10734
0
        lc = 1;
10735
0
        break;
10736
0
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10737
0
         (NXT(len) == '=')) {
10738
0
        lc = 1;
10739
0
        break;
10740
0
    } else {
10741
0
        lc = 1;
10742
0
        break;
10743
0
    }
10744
0
    len++;
10745
0
      }
10746
0
      if (NXT(len) == 0) {
10747
#ifdef DEBUG_STEP
10748
    xmlGenericError(xmlGenericErrorContext,
10749
      "PathExpr: AbbrRelLocation\n");
10750
#endif
10751
    /* element name */
10752
0
    lc = 1;
10753
0
      }
10754
0
      xmlFree(name);
10755
0
  } else {
10756
      /* make sure all cases are covered explicitly */
10757
0
      XP_ERROR(XPATH_EXPR_ERROR);
10758
0
  }
10759
0
    }
10760
10761
0
    if (lc) {
10762
0
  if (CUR == '/') {
10763
0
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10764
0
  } else {
10765
0
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10766
0
  }
10767
0
  xmlXPathCompLocationPath(ctxt);
10768
0
    } else {
10769
0
  xmlXPathCompFilterExpr(ctxt);
10770
0
  CHECK_ERROR;
10771
0
  if ((CUR == '/') && (NXT(1) == '/')) {
10772
0
      SKIP(2);
10773
0
      SKIP_BLANKS;
10774
10775
0
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10776
0
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10777
0
      PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10778
10779
0
      xmlXPathCompRelativeLocationPath(ctxt);
10780
0
  } else if (CUR == '/') {
10781
0
      xmlXPathCompRelativeLocationPath(ctxt);
10782
0
  }
10783
0
    }
10784
0
    SKIP_BLANKS;
10785
0
}
10786
10787
/**
10788
 * xmlXPathCompUnionExpr:
10789
 * @ctxt:  the XPath Parser context
10790
 *
10791
 *  [18]   UnionExpr ::=   PathExpr
10792
 *               | UnionExpr '|' PathExpr
10793
 *
10794
 * Compile an union expression.
10795
 */
10796
10797
static void
10798
0
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10799
0
    xmlXPathCompPathExpr(ctxt);
10800
0
    CHECK_ERROR;
10801
0
    SKIP_BLANKS;
10802
0
    while (CUR == '|') {
10803
0
  int op1 = ctxt->comp->last;
10804
0
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10805
10806
0
  NEXT;
10807
0
  SKIP_BLANKS;
10808
0
  xmlXPathCompPathExpr(ctxt);
10809
10810
0
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10811
10812
0
  SKIP_BLANKS;
10813
0
    }
10814
0
}
10815
10816
/**
10817
 * xmlXPathCompUnaryExpr:
10818
 * @ctxt:  the XPath Parser context
10819
 *
10820
 *  [27]   UnaryExpr ::=   UnionExpr
10821
 *                   | '-' UnaryExpr
10822
 *
10823
 * Compile an unary expression.
10824
 */
10825
10826
static void
10827
0
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10828
0
    int minus = 0;
10829
0
    int found = 0;
10830
10831
0
    SKIP_BLANKS;
10832
0
    while (CUR == '-') {
10833
0
        minus = 1 - minus;
10834
0
  found = 1;
10835
0
  NEXT;
10836
0
  SKIP_BLANKS;
10837
0
    }
10838
10839
0
    xmlXPathCompUnionExpr(ctxt);
10840
0
    CHECK_ERROR;
10841
0
    if (found) {
10842
0
  if (minus)
10843
0
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10844
0
  else
10845
0
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10846
0
    }
10847
0
}
10848
10849
/**
10850
 * xmlXPathCompMultiplicativeExpr:
10851
 * @ctxt:  the XPath Parser context
10852
 *
10853
 *  [26]   MultiplicativeExpr ::=   UnaryExpr
10854
 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10855
 *                   | MultiplicativeExpr 'div' UnaryExpr
10856
 *                   | MultiplicativeExpr 'mod' UnaryExpr
10857
 *  [34]   MultiplyOperator ::=   '*'
10858
 *
10859
 * Compile an Additive expression.
10860
 */
10861
10862
static void
10863
0
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10864
0
    xmlXPathCompUnaryExpr(ctxt);
10865
0
    CHECK_ERROR;
10866
0
    SKIP_BLANKS;
10867
0
    while ((CUR == '*') ||
10868
0
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10869
0
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10870
0
  int op = -1;
10871
0
  int op1 = ctxt->comp->last;
10872
10873
0
        if (CUR == '*') {
10874
0
      op = 0;
10875
0
      NEXT;
10876
0
  } else if (CUR == 'd') {
10877
0
      op = 1;
10878
0
      SKIP(3);
10879
0
  } else if (CUR == 'm') {
10880
0
      op = 2;
10881
0
      SKIP(3);
10882
0
  }
10883
0
  SKIP_BLANKS;
10884
0
        xmlXPathCompUnaryExpr(ctxt);
10885
0
  CHECK_ERROR;
10886
0
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10887
0
  SKIP_BLANKS;
10888
0
    }
10889
0
}
10890
10891
/**
10892
 * xmlXPathCompAdditiveExpr:
10893
 * @ctxt:  the XPath Parser context
10894
 *
10895
 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10896
 *                   | AdditiveExpr '+' MultiplicativeExpr
10897
 *                   | AdditiveExpr '-' MultiplicativeExpr
10898
 *
10899
 * Compile an Additive expression.
10900
 */
10901
10902
static void
10903
0
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10904
10905
0
    xmlXPathCompMultiplicativeExpr(ctxt);
10906
0
    CHECK_ERROR;
10907
0
    SKIP_BLANKS;
10908
0
    while ((CUR == '+') || (CUR == '-')) {
10909
0
  int plus;
10910
0
  int op1 = ctxt->comp->last;
10911
10912
0
        if (CUR == '+') plus = 1;
10913
0
  else plus = 0;
10914
0
  NEXT;
10915
0
  SKIP_BLANKS;
10916
0
        xmlXPathCompMultiplicativeExpr(ctxt);
10917
0
  CHECK_ERROR;
10918
0
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10919
0
  SKIP_BLANKS;
10920
0
    }
10921
0
}
10922
10923
/**
10924
 * xmlXPathCompRelationalExpr:
10925
 * @ctxt:  the XPath Parser context
10926
 *
10927
 *  [24]   RelationalExpr ::=   AdditiveExpr
10928
 *                 | RelationalExpr '<' AdditiveExpr
10929
 *                 | RelationalExpr '>' AdditiveExpr
10930
 *                 | RelationalExpr '<=' AdditiveExpr
10931
 *                 | RelationalExpr '>=' AdditiveExpr
10932
 *
10933
 *  A <= B > C is allowed ? Answer from James, yes with
10934
 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10935
 *  which is basically what got implemented.
10936
 *
10937
 * Compile a Relational expression, then push the result
10938
 * on the stack
10939
 */
10940
10941
static void
10942
0
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10943
0
    xmlXPathCompAdditiveExpr(ctxt);
10944
0
    CHECK_ERROR;
10945
0
    SKIP_BLANKS;
10946
0
    while ((CUR == '<') ||
10947
0
           (CUR == '>') ||
10948
0
           ((CUR == '<') && (NXT(1) == '=')) ||
10949
0
           ((CUR == '>') && (NXT(1) == '='))) {
10950
0
  int inf, strict;
10951
0
  int op1 = ctxt->comp->last;
10952
10953
0
        if (CUR == '<') inf = 1;
10954
0
  else inf = 0;
10955
0
  if (NXT(1) == '=') strict = 0;
10956
0
  else strict = 1;
10957
0
  NEXT;
10958
0
  if (!strict) NEXT;
10959
0
  SKIP_BLANKS;
10960
0
        xmlXPathCompAdditiveExpr(ctxt);
10961
0
  CHECK_ERROR;
10962
0
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10963
0
  SKIP_BLANKS;
10964
0
    }
10965
0
}
10966
10967
/**
10968
 * xmlXPathCompEqualityExpr:
10969
 * @ctxt:  the XPath Parser context
10970
 *
10971
 *  [23]   EqualityExpr ::=   RelationalExpr
10972
 *                 | EqualityExpr '=' RelationalExpr
10973
 *                 | EqualityExpr '!=' RelationalExpr
10974
 *
10975
 *  A != B != C is allowed ? Answer from James, yes with
10976
 *  (RelationalExpr = RelationalExpr) = RelationalExpr
10977
 *  (RelationalExpr != RelationalExpr) != RelationalExpr
10978
 *  which is basically what got implemented.
10979
 *
10980
 * Compile an Equality expression.
10981
 *
10982
 */
10983
static void
10984
0
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10985
0
    xmlXPathCompRelationalExpr(ctxt);
10986
0
    CHECK_ERROR;
10987
0
    SKIP_BLANKS;
10988
0
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10989
0
  int eq;
10990
0
  int op1 = ctxt->comp->last;
10991
10992
0
        if (CUR == '=') eq = 1;
10993
0
  else eq = 0;
10994
0
  NEXT;
10995
0
  if (!eq) NEXT;
10996
0
  SKIP_BLANKS;
10997
0
        xmlXPathCompRelationalExpr(ctxt);
10998
0
  CHECK_ERROR;
10999
0
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
11000
0
  SKIP_BLANKS;
11001
0
    }
11002
0
}
11003
11004
/**
11005
 * xmlXPathCompAndExpr:
11006
 * @ctxt:  the XPath Parser context
11007
 *
11008
 *  [22]   AndExpr ::=   EqualityExpr
11009
 *                 | AndExpr 'and' EqualityExpr
11010
 *
11011
 * Compile an AND expression.
11012
 *
11013
 */
11014
static void
11015
0
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
11016
0
    xmlXPathCompEqualityExpr(ctxt);
11017
0
    CHECK_ERROR;
11018
0
    SKIP_BLANKS;
11019
0
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
11020
0
  int op1 = ctxt->comp->last;
11021
0
        SKIP(3);
11022
0
  SKIP_BLANKS;
11023
0
        xmlXPathCompEqualityExpr(ctxt);
11024
0
  CHECK_ERROR;
11025
0
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
11026
0
  SKIP_BLANKS;
11027
0
    }
11028
0
}
11029
11030
/**
11031
 * xmlXPathCompileExpr:
11032
 * @ctxt:  the XPath Parser context
11033
 *
11034
 *  [14]   Expr ::=   OrExpr
11035
 *  [21]   OrExpr ::=   AndExpr
11036
 *                 | OrExpr 'or' AndExpr
11037
 *
11038
 * Parse and compile an expression
11039
 */
11040
static void
11041
0
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
11042
0
    xmlXPathCompAndExpr(ctxt);
11043
0
    CHECK_ERROR;
11044
0
    SKIP_BLANKS;
11045
0
    while ((CUR == 'o') && (NXT(1) == 'r')) {
11046
0
  int op1 = ctxt->comp->last;
11047
0
        SKIP(2);
11048
0
  SKIP_BLANKS;
11049
0
        xmlXPathCompAndExpr(ctxt);
11050
0
  CHECK_ERROR;
11051
0
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
11052
0
  SKIP_BLANKS;
11053
0
    }
11054
0
    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
11055
  /* more ops could be optimized too */
11056
  /*
11057
  * This is the main place to eliminate sorting for
11058
  * operations which don't require a sorted node-set.
11059
  * E.g. count().
11060
  */
11061
0
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11062
0
    }
11063
0
}
11064
11065
/**
11066
 * xmlXPathCompPredicate:
11067
 * @ctxt:  the XPath Parser context
11068
 * @filter:  act as a filter
11069
 *
11070
 *  [8]   Predicate ::=   '[' PredicateExpr ']'
11071
 *  [9]   PredicateExpr ::=   Expr
11072
 *
11073
 * Compile a predicate expression
11074
 */
11075
static void
11076
0
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11077
0
    int op1 = ctxt->comp->last;
11078
11079
0
    SKIP_BLANKS;
11080
0
    if (CUR != '[') {
11081
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11082
0
    }
11083
0
    NEXT;
11084
0
    SKIP_BLANKS;
11085
11086
0
    ctxt->comp->last = -1;
11087
    /*
11088
    * This call to xmlXPathCompileExpr() will deactivate sorting
11089
    * of the predicate result.
11090
    * TODO: Sorting is still activated for filters, since I'm not
11091
    *  sure if needed. Normally sorting should not be needed, since
11092
    *  a filter can only diminish the number of items in a sequence,
11093
    *  but won't change its order; so if the initial sequence is sorted,
11094
    *  subsequent sorting is not needed.
11095
    */
11096
0
    if (! filter)
11097
0
  xmlXPathCompileExpr(ctxt, 0);
11098
0
    else
11099
0
  xmlXPathCompileExpr(ctxt, 1);
11100
0
    CHECK_ERROR;
11101
11102
0
    if (CUR != ']') {
11103
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11104
0
    }
11105
11106
0
    if (filter)
11107
0
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11108
0
    else
11109
0
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11110
11111
0
    NEXT;
11112
0
    SKIP_BLANKS;
11113
0
}
11114
11115
/**
11116
 * xmlXPathCompNodeTest:
11117
 * @ctxt:  the XPath Parser context
11118
 * @test:  pointer to a xmlXPathTestVal
11119
 * @type:  pointer to a xmlXPathTypeVal
11120
 * @prefix:  placeholder for a possible name prefix
11121
 *
11122
 * [7] NodeTest ::=   NameTest
11123
 *        | NodeType '(' ')'
11124
 *        | 'processing-instruction' '(' Literal ')'
11125
 *
11126
 * [37] NameTest ::=  '*'
11127
 *        | NCName ':' '*'
11128
 *        | QName
11129
 * [38] NodeType ::= 'comment'
11130
 *       | 'text'
11131
 *       | 'processing-instruction'
11132
 *       | 'node'
11133
 *
11134
 * Returns the name found and updates @test, @type and @prefix appropriately
11135
 */
11136
static xmlChar *
11137
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11138
               xmlXPathTypeVal *type, const xmlChar **prefix,
11139
0
         xmlChar *name) {
11140
0
    int blanks;
11141
11142
0
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11143
0
  STRANGE;
11144
0
  return(NULL);
11145
0
    }
11146
0
    *type = (xmlXPathTypeVal) 0;
11147
0
    *test = (xmlXPathTestVal) 0;
11148
0
    *prefix = NULL;
11149
0
    SKIP_BLANKS;
11150
11151
0
    if ((name == NULL) && (CUR == '*')) {
11152
  /*
11153
   * All elements
11154
   */
11155
0
  NEXT;
11156
0
  *test = NODE_TEST_ALL;
11157
0
  return(NULL);
11158
0
    }
11159
11160
0
    if (name == NULL)
11161
0
  name = xmlXPathParseNCName(ctxt);
11162
0
    if (name == NULL) {
11163
0
  XP_ERRORNULL(XPATH_EXPR_ERROR);
11164
0
    }
11165
11166
0
    blanks = IS_BLANK_CH(CUR);
11167
0
    SKIP_BLANKS;
11168
0
    if (CUR == '(') {
11169
0
  NEXT;
11170
  /*
11171
   * NodeType or PI search
11172
   */
11173
0
  if (xmlStrEqual(name, BAD_CAST "comment"))
11174
0
      *type = NODE_TYPE_COMMENT;
11175
0
  else if (xmlStrEqual(name, BAD_CAST "node"))
11176
0
      *type = NODE_TYPE_NODE;
11177
0
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11178
0
      *type = NODE_TYPE_PI;
11179
0
  else if (xmlStrEqual(name, BAD_CAST "text"))
11180
0
      *type = NODE_TYPE_TEXT;
11181
0
  else {
11182
0
      if (name != NULL)
11183
0
    xmlFree(name);
11184
0
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11185
0
  }
11186
11187
0
  *test = NODE_TEST_TYPE;
11188
11189
0
  SKIP_BLANKS;
11190
0
  if (*type == NODE_TYPE_PI) {
11191
      /*
11192
       * Specific case: search a PI by name.
11193
       */
11194
0
      if (name != NULL)
11195
0
    xmlFree(name);
11196
0
      name = NULL;
11197
0
      if (CUR != ')') {
11198
0
    name = xmlXPathParseLiteral(ctxt);
11199
0
    CHECK_ERROR NULL;
11200
0
    *test = NODE_TEST_PI;
11201
0
    SKIP_BLANKS;
11202
0
      }
11203
0
  }
11204
0
  if (CUR != ')') {
11205
0
      if (name != NULL)
11206
0
    xmlFree(name);
11207
0
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11208
0
  }
11209
0
  NEXT;
11210
0
  return(name);
11211
0
    }
11212
0
    *test = NODE_TEST_NAME;
11213
0
    if ((!blanks) && (CUR == ':')) {
11214
0
  NEXT;
11215
11216
  /*
11217
   * Since currently the parser context don't have a
11218
   * namespace list associated:
11219
   * The namespace name for this prefix can be computed
11220
   * only at evaluation time. The compilation is done
11221
   * outside of any context.
11222
   */
11223
#if 0
11224
  *prefix = xmlXPathNsLookup(ctxt->context, name);
11225
  if (name != NULL)
11226
      xmlFree(name);
11227
  if (*prefix == NULL) {
11228
      XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11229
  }
11230
#else
11231
0
  *prefix = name;
11232
0
#endif
11233
11234
0
  if (CUR == '*') {
11235
      /*
11236
       * All elements
11237
       */
11238
0
      NEXT;
11239
0
      *test = NODE_TEST_ALL;
11240
0
      return(NULL);
11241
0
  }
11242
11243
0
  name = xmlXPathParseNCName(ctxt);
11244
0
  if (name == NULL) {
11245
0
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11246
0
  }
11247
0
    }
11248
0
    return(name);
11249
0
}
11250
11251
/**
11252
 * xmlXPathIsAxisName:
11253
 * @name:  a preparsed name token
11254
 *
11255
 * [6] AxisName ::=   'ancestor'
11256
 *                  | 'ancestor-or-self'
11257
 *                  | 'attribute'
11258
 *                  | 'child'
11259
 *                  | 'descendant'
11260
 *                  | 'descendant-or-self'
11261
 *                  | 'following'
11262
 *                  | 'following-sibling'
11263
 *                  | 'namespace'
11264
 *                  | 'parent'
11265
 *                  | 'preceding'
11266
 *                  | 'preceding-sibling'
11267
 *                  | 'self'
11268
 *
11269
 * Returns the axis or 0
11270
 */
11271
static xmlXPathAxisVal
11272
0
xmlXPathIsAxisName(const xmlChar *name) {
11273
0
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11274
0
    switch (name[0]) {
11275
0
  case 'a':
11276
0
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
11277
0
    ret = AXIS_ANCESTOR;
11278
0
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11279
0
    ret = AXIS_ANCESTOR_OR_SELF;
11280
0
      if (xmlStrEqual(name, BAD_CAST "attribute"))
11281
0
    ret = AXIS_ATTRIBUTE;
11282
0
      break;
11283
0
  case 'c':
11284
0
      if (xmlStrEqual(name, BAD_CAST "child"))
11285
0
    ret = AXIS_CHILD;
11286
0
      break;
11287
0
  case 'd':
11288
0
      if (xmlStrEqual(name, BAD_CAST "descendant"))
11289
0
    ret = AXIS_DESCENDANT;
11290
0
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11291
0
    ret = AXIS_DESCENDANT_OR_SELF;
11292
0
      break;
11293
0
  case 'f':
11294
0
      if (xmlStrEqual(name, BAD_CAST "following"))
11295
0
    ret = AXIS_FOLLOWING;
11296
0
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11297
0
    ret = AXIS_FOLLOWING_SIBLING;
11298
0
      break;
11299
0
  case 'n':
11300
0
      if (xmlStrEqual(name, BAD_CAST "namespace"))
11301
0
    ret = AXIS_NAMESPACE;
11302
0
      break;
11303
0
  case 'p':
11304
0
      if (xmlStrEqual(name, BAD_CAST "parent"))
11305
0
    ret = AXIS_PARENT;
11306
0
      if (xmlStrEqual(name, BAD_CAST "preceding"))
11307
0
    ret = AXIS_PRECEDING;
11308
0
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11309
0
    ret = AXIS_PRECEDING_SIBLING;
11310
0
      break;
11311
0
  case 's':
11312
0
      if (xmlStrEqual(name, BAD_CAST "self"))
11313
0
    ret = AXIS_SELF;
11314
0
      break;
11315
0
    }
11316
0
    return(ret);
11317
0
}
11318
11319
/**
11320
 * xmlXPathCompStep:
11321
 * @ctxt:  the XPath Parser context
11322
 *
11323
 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11324
 *                  | AbbreviatedStep
11325
 *
11326
 * [12] AbbreviatedStep ::=   '.' | '..'
11327
 *
11328
 * [5] AxisSpecifier ::= AxisName '::'
11329
 *                  | AbbreviatedAxisSpecifier
11330
 *
11331
 * [13] AbbreviatedAxisSpecifier ::= '@'?
11332
 *
11333
 * Modified for XPtr range support as:
11334
 *
11335
 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11336
 *                     | AbbreviatedStep
11337
 *                     | 'range-to' '(' Expr ')' Predicate*
11338
 *
11339
 * Compile one step in a Location Path
11340
 * A location step of . is short for self::node(). This is
11341
 * particularly useful in conjunction with //. For example, the
11342
 * location path .//para is short for
11343
 * self::node()/descendant-or-self::node()/child::para
11344
 * and so will select all para descendant elements of the context
11345
 * node.
11346
 * Similarly, a location step of .. is short for parent::node().
11347
 * For example, ../title is short for parent::node()/child::title
11348
 * and so will select the title children of the parent of the context
11349
 * node.
11350
 */
11351
static void
11352
0
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11353
0
#ifdef LIBXML_XPTR_ENABLED
11354
0
    int rangeto = 0;
11355
0
    int op2 = -1;
11356
0
#endif
11357
11358
0
    SKIP_BLANKS;
11359
0
    if ((CUR == '.') && (NXT(1) == '.')) {
11360
0
  SKIP(2);
11361
0
  SKIP_BLANKS;
11362
0
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11363
0
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11364
0
    } else if (CUR == '.') {
11365
0
  NEXT;
11366
0
  SKIP_BLANKS;
11367
0
    } else {
11368
0
  xmlChar *name = NULL;
11369
0
  const xmlChar *prefix = NULL;
11370
0
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
11371
0
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11372
0
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11373
0
  int op1;
11374
11375
  /*
11376
   * The modification needed for XPointer change to the production
11377
   */
11378
0
#ifdef LIBXML_XPTR_ENABLED
11379
0
  if (ctxt->xptr) {
11380
0
      name = xmlXPathParseNCName(ctxt);
11381
0
      if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11382
0
                op2 = ctxt->comp->last;
11383
0
    xmlFree(name);
11384
0
    SKIP_BLANKS;
11385
0
    if (CUR != '(') {
11386
0
        XP_ERROR(XPATH_EXPR_ERROR);
11387
0
    }
11388
0
    NEXT;
11389
0
    SKIP_BLANKS;
11390
11391
0
    xmlXPathCompileExpr(ctxt, 1);
11392
    /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11393
0
    CHECK_ERROR;
11394
11395
0
    SKIP_BLANKS;
11396
0
    if (CUR != ')') {
11397
0
        XP_ERROR(XPATH_EXPR_ERROR);
11398
0
    }
11399
0
    NEXT;
11400
0
    rangeto = 1;
11401
0
    goto eval_predicates;
11402
0
      }
11403
0
  }
11404
0
#endif
11405
0
  if (CUR == '*') {
11406
0
      axis = AXIS_CHILD;
11407
0
  } else {
11408
0
      if (name == NULL)
11409
0
    name = xmlXPathParseNCName(ctxt);
11410
0
      if (name != NULL) {
11411
0
    axis = xmlXPathIsAxisName(name);
11412
0
    if (axis != 0) {
11413
0
        SKIP_BLANKS;
11414
0
        if ((CUR == ':') && (NXT(1) == ':')) {
11415
0
      SKIP(2);
11416
0
      xmlFree(name);
11417
0
      name = NULL;
11418
0
        } else {
11419
      /* an element name can conflict with an axis one :-\ */
11420
0
      axis = AXIS_CHILD;
11421
0
        }
11422
0
    } else {
11423
0
        axis = AXIS_CHILD;
11424
0
    }
11425
0
      } else if (CUR == '@') {
11426
0
    NEXT;
11427
0
    axis = AXIS_ATTRIBUTE;
11428
0
      } else {
11429
0
    axis = AXIS_CHILD;
11430
0
      }
11431
0
  }
11432
11433
0
        if (ctxt->error != XPATH_EXPRESSION_OK) {
11434
0
            xmlFree(name);
11435
0
            return;
11436
0
        }
11437
11438
0
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11439
0
  if (test == 0)
11440
0
      return;
11441
11442
0
        if ((prefix != NULL) && (ctxt->context != NULL) &&
11443
0
      (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11444
0
      if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11445
0
    xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11446
0
      }
11447
0
  }
11448
#ifdef DEBUG_STEP
11449
  xmlGenericError(xmlGenericErrorContext,
11450
    "Basis : computing new set\n");
11451
#endif
11452
11453
#ifdef DEBUG_STEP
11454
  xmlGenericError(xmlGenericErrorContext, "Basis : ");
11455
  if (ctxt->value == NULL)
11456
      xmlGenericError(xmlGenericErrorContext, "no value\n");
11457
  else if (ctxt->value->nodesetval == NULL)
11458
      xmlGenericError(xmlGenericErrorContext, "Empty\n");
11459
  else
11460
      xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11461
#endif
11462
11463
0
#ifdef LIBXML_XPTR_ENABLED
11464
0
eval_predicates:
11465
0
#endif
11466
0
  op1 = ctxt->comp->last;
11467
0
  ctxt->comp->last = -1;
11468
11469
0
  SKIP_BLANKS;
11470
0
  while (CUR == '[') {
11471
0
      xmlXPathCompPredicate(ctxt, 0);
11472
0
  }
11473
11474
0
#ifdef LIBXML_XPTR_ENABLED
11475
0
  if (rangeto) {
11476
0
      PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11477
0
  } else
11478
0
#endif
11479
0
      PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11480
0
         test, type, (void *)prefix, (void *)name);
11481
11482
0
    }
11483
#ifdef DEBUG_STEP
11484
    xmlGenericError(xmlGenericErrorContext, "Step : ");
11485
    if (ctxt->value == NULL)
11486
  xmlGenericError(xmlGenericErrorContext, "no value\n");
11487
    else if (ctxt->value->nodesetval == NULL)
11488
  xmlGenericError(xmlGenericErrorContext, "Empty\n");
11489
    else
11490
  xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11491
    ctxt->value->nodesetval);
11492
#endif
11493
0
}
11494
11495
/**
11496
 * xmlXPathCompRelativeLocationPath:
11497
 * @ctxt:  the XPath Parser context
11498
 *
11499
 *  [3]   RelativeLocationPath ::=   Step
11500
 *                     | RelativeLocationPath '/' Step
11501
 *                     | AbbreviatedRelativeLocationPath
11502
 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11503
 *
11504
 * Compile a relative location path.
11505
 */
11506
static void
11507
xmlXPathCompRelativeLocationPath
11508
0
(xmlXPathParserContextPtr ctxt) {
11509
0
    SKIP_BLANKS;
11510
0
    if ((CUR == '/') && (NXT(1) == '/')) {
11511
0
  SKIP(2);
11512
0
  SKIP_BLANKS;
11513
0
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11514
0
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11515
0
    } else if (CUR == '/') {
11516
0
      NEXT;
11517
0
  SKIP_BLANKS;
11518
0
    }
11519
0
    xmlXPathCompStep(ctxt);
11520
0
    CHECK_ERROR;
11521
0
    SKIP_BLANKS;
11522
0
    while (CUR == '/') {
11523
0
  if ((CUR == '/') && (NXT(1) == '/')) {
11524
0
      SKIP(2);
11525
0
      SKIP_BLANKS;
11526
0
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11527
0
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11528
0
      xmlXPathCompStep(ctxt);
11529
0
  } else if (CUR == '/') {
11530
0
      NEXT;
11531
0
      SKIP_BLANKS;
11532
0
      xmlXPathCompStep(ctxt);
11533
0
  }
11534
0
  SKIP_BLANKS;
11535
0
    }
11536
0
}
11537
11538
/**
11539
 * xmlXPathCompLocationPath:
11540
 * @ctxt:  the XPath Parser context
11541
 *
11542
 *  [1]   LocationPath ::=   RelativeLocationPath
11543
 *                     | AbsoluteLocationPath
11544
 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11545
 *                     | AbbreviatedAbsoluteLocationPath
11546
 *  [10]   AbbreviatedAbsoluteLocationPath ::=
11547
 *                           '//' RelativeLocationPath
11548
 *
11549
 * Compile a location path
11550
 *
11551
 * // is short for /descendant-or-self::node()/. For example,
11552
 * //para is short for /descendant-or-self::node()/child::para and
11553
 * so will select any para element in the document (even a para element
11554
 * that is a document element will be selected by //para since the
11555
 * document element node is a child of the root node); div//para is
11556
 * short for div/descendant-or-self::node()/child::para and so will
11557
 * select all para descendants of div children.
11558
 */
11559
static void
11560
0
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11561
0
    SKIP_BLANKS;
11562
0
    if (CUR != '/') {
11563
0
        xmlXPathCompRelativeLocationPath(ctxt);
11564
0
    } else {
11565
0
  while (CUR == '/') {
11566
0
      if ((CUR == '/') && (NXT(1) == '/')) {
11567
0
    SKIP(2);
11568
0
    SKIP_BLANKS;
11569
0
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11570
0
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11571
0
    xmlXPathCompRelativeLocationPath(ctxt);
11572
0
      } else if (CUR == '/') {
11573
0
    NEXT;
11574
0
    SKIP_BLANKS;
11575
0
    if ((CUR != 0 ) &&
11576
0
        ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11577
0
         (CUR == '@') || (CUR == '*')))
11578
0
        xmlXPathCompRelativeLocationPath(ctxt);
11579
0
      }
11580
0
      CHECK_ERROR;
11581
0
  }
11582
0
    }
11583
0
}
11584
11585
/************************************************************************
11586
 *                  *
11587
 *    XPath precompiled expression evaluation     *
11588
 *                  *
11589
 ************************************************************************/
11590
11591
static int
11592
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11593
11594
#ifdef DEBUG_STEP
11595
static void
11596
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11597
        int nbNodes)
11598
{
11599
    xmlGenericError(xmlGenericErrorContext, "new step : ");
11600
    switch (op->value) {
11601
        case AXIS_ANCESTOR:
11602
            xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11603
            break;
11604
        case AXIS_ANCESTOR_OR_SELF:
11605
            xmlGenericError(xmlGenericErrorContext,
11606
                            "axis 'ancestors-or-self' ");
11607
            break;
11608
        case AXIS_ATTRIBUTE:
11609
            xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11610
            break;
11611
        case AXIS_CHILD:
11612
            xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11613
            break;
11614
        case AXIS_DESCENDANT:
11615
            xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11616
            break;
11617
        case AXIS_DESCENDANT_OR_SELF:
11618
            xmlGenericError(xmlGenericErrorContext,
11619
                            "axis 'descendant-or-self' ");
11620
            break;
11621
        case AXIS_FOLLOWING:
11622
            xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11623
            break;
11624
        case AXIS_FOLLOWING_SIBLING:
11625
            xmlGenericError(xmlGenericErrorContext,
11626
                            "axis 'following-siblings' ");
11627
            break;
11628
        case AXIS_NAMESPACE:
11629
            xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11630
            break;
11631
        case AXIS_PARENT:
11632
            xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11633
            break;
11634
        case AXIS_PRECEDING:
11635
            xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11636
            break;
11637
        case AXIS_PRECEDING_SIBLING:
11638
            xmlGenericError(xmlGenericErrorContext,
11639
                            "axis 'preceding-sibling' ");
11640
            break;
11641
        case AXIS_SELF:
11642
            xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11643
            break;
11644
    }
11645
    xmlGenericError(xmlGenericErrorContext,
11646
  " context contains %d nodes\n", nbNodes);
11647
    switch (op->value2) {
11648
        case NODE_TEST_NONE:
11649
            xmlGenericError(xmlGenericErrorContext,
11650
                            "           searching for none !!!\n");
11651
            break;
11652
        case NODE_TEST_TYPE:
11653
            xmlGenericError(xmlGenericErrorContext,
11654
                            "           searching for type %d\n", op->value3);
11655
            break;
11656
        case NODE_TEST_PI:
11657
            xmlGenericError(xmlGenericErrorContext,
11658
                            "           searching for PI !!!\n");
11659
            break;
11660
        case NODE_TEST_ALL:
11661
            xmlGenericError(xmlGenericErrorContext,
11662
                            "           searching for *\n");
11663
            break;
11664
        case NODE_TEST_NS:
11665
            xmlGenericError(xmlGenericErrorContext,
11666
                            "           searching for namespace %s\n",
11667
                            op->value5);
11668
            break;
11669
        case NODE_TEST_NAME:
11670
            xmlGenericError(xmlGenericErrorContext,
11671
                            "           searching for name %s\n", op->value5);
11672
            if (op->value4)
11673
                xmlGenericError(xmlGenericErrorContext,
11674
                                "           with namespace %s\n", op->value4);
11675
            break;
11676
    }
11677
    xmlGenericError(xmlGenericErrorContext, "Testing : ");
11678
}
11679
#endif /* DEBUG_STEP */
11680
11681
static int
11682
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11683
          xmlXPathStepOpPtr op,
11684
          xmlNodeSetPtr set,
11685
          int contextSize,
11686
          int hasNsNodes)
11687
0
{
11688
0
    if (op->ch1 != -1) {
11689
0
  xmlXPathCompExprPtr comp = ctxt->comp;
11690
  /*
11691
  * Process inner predicates first.
11692
  */
11693
0
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11694
      /*
11695
      * TODO: raise an internal error.
11696
      */
11697
0
  }
11698
0
  contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11699
0
      &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11700
0
  CHECK_ERROR0;
11701
0
  if (contextSize <= 0)
11702
0
      return(0);
11703
0
    }
11704
0
    if (op->ch2 != -1) {
11705
0
  xmlXPathContextPtr xpctxt = ctxt->context;
11706
0
  xmlNodePtr contextNode, oldContextNode;
11707
0
  xmlDocPtr oldContextDoc;
11708
0
  int i, res, contextPos = 0, newContextSize;
11709
0
  xmlXPathStepOpPtr exprOp;
11710
0
  xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11711
11712
0
#ifdef LIBXML_XPTR_ENABLED
11713
  /*
11714
  * URGENT TODO: Check the following:
11715
  *  We don't expect location sets if evaluating prediates, right?
11716
  *  Only filters should expect location sets, right?
11717
  */
11718
0
#endif
11719
  /*
11720
  * SPEC XPath 1.0:
11721
  *  "For each node in the node-set to be filtered, the
11722
  *  PredicateExpr is evaluated with that node as the
11723
  *  context node, with the number of nodes in the
11724
  *  node-set as the context size, and with the proximity
11725
  *  position of the node in the node-set with respect to
11726
  *  the axis as the context position;"
11727
  * @oldset is the node-set" to be filtered.
11728
  *
11729
  * SPEC XPath 1.0:
11730
  *  "only predicates change the context position and
11731
  *  context size (see [2.4 Predicates])."
11732
  * Example:
11733
  *   node-set  context pos
11734
  *    nA         1
11735
  *    nB         2
11736
  *    nC         3
11737
  *   After applying predicate [position() > 1] :
11738
  *   node-set  context pos
11739
  *    nB         1
11740
  *    nC         2
11741
  */
11742
0
  oldContextNode = xpctxt->node;
11743
0
  oldContextDoc = xpctxt->doc;
11744
  /*
11745
  * Get the expression of this predicate.
11746
  */
11747
0
  exprOp = &ctxt->comp->steps[op->ch2];
11748
0
  newContextSize = 0;
11749
0
  for (i = 0; i < set->nodeNr; i++) {
11750
0
      if (set->nodeTab[i] == NULL)
11751
0
    continue;
11752
11753
0
      contextNode = set->nodeTab[i];
11754
0
      xpctxt->node = contextNode;
11755
0
      xpctxt->contextSize = contextSize;
11756
0
      xpctxt->proximityPosition = ++contextPos;
11757
11758
      /*
11759
      * Also set the xpath document in case things like
11760
      * key() are evaluated in the predicate.
11761
      */
11762
0
      if ((contextNode->type != XML_NAMESPACE_DECL) &&
11763
0
    (contextNode->doc != NULL))
11764
0
    xpctxt->doc = contextNode->doc;
11765
      /*
11766
      * Evaluate the predicate expression with 1 context node
11767
      * at a time; this node is packaged into a node set; this
11768
      * node set is handed over to the evaluation mechanism.
11769
      */
11770
0
      if (contextObj == NULL)
11771
0
    contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11772
0
      else {
11773
0
    if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11774
0
        contextNode) < 0) {
11775
0
        ctxt->error = XPATH_MEMORY_ERROR;
11776
0
        goto evaluation_exit;
11777
0
    }
11778
0
      }
11779
11780
0
      valuePush(ctxt, contextObj);
11781
11782
0
      res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11783
11784
0
      if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11785
0
    xmlXPathNodeSetClear(set, hasNsNodes);
11786
0
    newContextSize = 0;
11787
0
    goto evaluation_exit;
11788
0
      }
11789
11790
0
      if (res != 0) {
11791
0
    newContextSize++;
11792
0
      } else {
11793
    /*
11794
    * Remove the entry from the initial node set.
11795
    */
11796
0
    set->nodeTab[i] = NULL;
11797
0
    if (contextNode->type == XML_NAMESPACE_DECL)
11798
0
        xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11799
0
      }
11800
0
      if (ctxt->value == contextObj) {
11801
    /*
11802
    * Don't free the temporary XPath object holding the
11803
    * context node, in order to avoid massive recreation
11804
    * inside this loop.
11805
    */
11806
0
    valuePop(ctxt);
11807
0
    xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11808
0
      } else {
11809
    /*
11810
    * TODO: The object was lost in the evaluation machinery.
11811
    *  Can this happen? Maybe in internal-error cases.
11812
    */
11813
0
    contextObj = NULL;
11814
0
      }
11815
0
  }
11816
11817
0
  if (contextObj != NULL) {
11818
0
      if (ctxt->value == contextObj)
11819
0
    valuePop(ctxt);
11820
0
      xmlXPathReleaseObject(xpctxt, contextObj);
11821
0
  }
11822
0
evaluation_exit:
11823
0
  if (exprRes != NULL)
11824
0
      xmlXPathReleaseObject(ctxt->context, exprRes);
11825
  /*
11826
  * Reset/invalidate the context.
11827
  */
11828
0
  xpctxt->node = oldContextNode;
11829
0
  xpctxt->doc = oldContextDoc;
11830
0
  xpctxt->contextSize = -1;
11831
0
  xpctxt->proximityPosition = -1;
11832
0
  return(newContextSize);
11833
0
    }
11834
0
    return(contextSize);
11835
0
}
11836
11837
static int
11838
xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11839
              xmlXPathStepOpPtr op,
11840
              xmlNodeSetPtr set,
11841
              int contextSize,
11842
              int minPos,
11843
              int maxPos,
11844
              int hasNsNodes)
11845
0
{
11846
0
    if (op->ch1 != -1) {
11847
0
  xmlXPathCompExprPtr comp = ctxt->comp;
11848
0
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11849
      /*
11850
      * TODO: raise an internal error.
11851
      */
11852
0
  }
11853
0
  contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11854
0
      &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11855
0
  CHECK_ERROR0;
11856
0
  if (contextSize <= 0)
11857
0
      return(0);
11858
0
    }
11859
    /*
11860
    * Check if the node set contains a sufficient number of nodes for
11861
    * the requested range.
11862
    */
11863
0
    if (contextSize < minPos) {
11864
0
  xmlXPathNodeSetClear(set, hasNsNodes);
11865
0
  return(0);
11866
0
    }
11867
0
    if (op->ch2 == -1) {
11868
  /*
11869
  * TODO: Can this ever happen?
11870
  */
11871
0
  return (contextSize);
11872
0
    } else {
11873
0
  xmlDocPtr oldContextDoc;
11874
0
  int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11875
0
  xmlXPathStepOpPtr exprOp;
11876
0
  xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11877
0
  xmlNodePtr oldContextNode, contextNode = NULL;
11878
0
  xmlXPathContextPtr xpctxt = ctxt->context;
11879
0
        int frame;
11880
11881
0
#ifdef LIBXML_XPTR_ENABLED
11882
      /*
11883
      * URGENT TODO: Check the following:
11884
      *  We don't expect location sets if evaluating prediates, right?
11885
      *  Only filters should expect location sets, right?
11886
  */
11887
0
#endif /* LIBXML_XPTR_ENABLED */
11888
11889
  /*
11890
  * Save old context.
11891
  */
11892
0
  oldContextNode = xpctxt->node;
11893
0
  oldContextDoc = xpctxt->doc;
11894
  /*
11895
  * Get the expression of this predicate.
11896
  */
11897
0
  exprOp = &ctxt->comp->steps[op->ch2];
11898
0
  for (i = 0; i < set->nodeNr; i++) {
11899
0
            xmlXPathObjectPtr tmp;
11900
11901
0
      if (set->nodeTab[i] == NULL)
11902
0
    continue;
11903
11904
0
      contextNode = set->nodeTab[i];
11905
0
      xpctxt->node = contextNode;
11906
0
      xpctxt->contextSize = contextSize;
11907
0
      xpctxt->proximityPosition = ++contextPos;
11908
11909
      /*
11910
      * Initialize the new set.
11911
      * Also set the xpath document in case things like
11912
      * key() evaluation are attempted on the predicate
11913
      */
11914
0
      if ((contextNode->type != XML_NAMESPACE_DECL) &&
11915
0
    (contextNode->doc != NULL))
11916
0
    xpctxt->doc = contextNode->doc;
11917
      /*
11918
      * Evaluate the predicate expression with 1 context node
11919
      * at a time; this node is packaged into a node set; this
11920
      * node set is handed over to the evaluation mechanism.
11921
      */
11922
0
      if (contextObj == NULL)
11923
0
    contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11924
0
      else {
11925
0
    if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11926
0
        contextNode) < 0) {
11927
0
        ctxt->error = XPATH_MEMORY_ERROR;
11928
0
        goto evaluation_exit;
11929
0
    }
11930
0
      }
11931
11932
0
      valuePush(ctxt, contextObj);
11933
0
            frame = xmlXPathSetFrame(ctxt);
11934
0
      res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11935
0
            xmlXPathPopFrame(ctxt, frame);
11936
0
            tmp = valuePop(ctxt);
11937
11938
0
      if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11939
0
                while (tmp != contextObj) {
11940
                    /*
11941
                     * Free up the result
11942
                     * then pop off contextObj, which will be freed later
11943
                     */
11944
0
                    xmlXPathReleaseObject(xpctxt, tmp);
11945
0
                    tmp = valuePop(ctxt);
11946
0
                }
11947
0
    goto evaluation_error;
11948
0
      }
11949
            /* push the result back onto the stack */
11950
0
            valuePush(ctxt, tmp);
11951
11952
0
      if (res)
11953
0
    pos++;
11954
11955
0
      if (res && (pos >= minPos) && (pos <= maxPos)) {
11956
    /*
11957
    * Fits in the requested range.
11958
    */
11959
0
    newContextSize++;
11960
0
    if (minPos == maxPos) {
11961
        /*
11962
        * Only 1 node was requested.
11963
        */
11964
0
        if (contextNode->type == XML_NAMESPACE_DECL) {
11965
      /*
11966
      * As always: take care of those nasty
11967
      * namespace nodes.
11968
      */
11969
0
      set->nodeTab[i] = NULL;
11970
0
        }
11971
0
        xmlXPathNodeSetClear(set, hasNsNodes);
11972
0
        set->nodeNr = 1;
11973
0
        set->nodeTab[0] = contextNode;
11974
0
        goto evaluation_exit;
11975
0
    }
11976
0
    if (pos == maxPos) {
11977
        /*
11978
        * We are done.
11979
        */
11980
0
        xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11981
0
        goto evaluation_exit;
11982
0
    }
11983
0
      } else {
11984
    /*
11985
    * Remove the entry from the initial node set.
11986
    */
11987
0
    set->nodeTab[i] = NULL;
11988
0
    if (contextNode->type == XML_NAMESPACE_DECL)
11989
0
        xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11990
0
      }
11991
0
      if (exprRes != NULL) {
11992
0
    xmlXPathReleaseObject(ctxt->context, exprRes);
11993
0
    exprRes = NULL;
11994
0
      }
11995
0
      if (ctxt->value == contextObj) {
11996
    /*
11997
    * Don't free the temporary XPath object holding the
11998
    * context node, in order to avoid massive recreation
11999
    * inside this loop.
12000
    */
12001
0
    valuePop(ctxt);
12002
0
    xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
12003
0
      } else {
12004
    /*
12005
    * The object was lost in the evaluation machinery.
12006
    * Can this happen? Maybe in case of internal-errors.
12007
    */
12008
0
    contextObj = NULL;
12009
0
      }
12010
0
  }
12011
0
  goto evaluation_exit;
12012
12013
0
evaluation_error:
12014
0
  xmlXPathNodeSetClear(set, hasNsNodes);
12015
0
  newContextSize = 0;
12016
12017
0
evaluation_exit:
12018
0
  if (contextObj != NULL) {
12019
0
      if (ctxt->value == contextObj)
12020
0
    valuePop(ctxt);
12021
0
      xmlXPathReleaseObject(xpctxt, contextObj);
12022
0
  }
12023
0
  if (exprRes != NULL)
12024
0
      xmlXPathReleaseObject(ctxt->context, exprRes);
12025
  /*
12026
  * Reset/invalidate the context.
12027
  */
12028
0
  xpctxt->node = oldContextNode;
12029
0
  xpctxt->doc = oldContextDoc;
12030
0
  xpctxt->contextSize = -1;
12031
0
  xpctxt->proximityPosition = -1;
12032
0
  return(newContextSize);
12033
0
    }
12034
0
    return(contextSize);
12035
0
}
12036
12037
static int
12038
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
12039
          xmlXPathStepOpPtr op,
12040
          int *maxPos)
12041
0
{
12042
12043
0
    xmlXPathStepOpPtr exprOp;
12044
12045
    /*
12046
    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12047
    */
12048
12049
    /*
12050
    * If not -1, then ch1 will point to:
12051
    * 1) For predicates (XPATH_OP_PREDICATE):
12052
    *    - an inner predicate operator
12053
    * 2) For filters (XPATH_OP_FILTER):
12054
    *    - an inner filter operater OR
12055
    *    - an expression selecting the node set.
12056
    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
12057
    */
12058
0
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12059
0
  return(0);
12060
12061
0
    if (op->ch2 != -1) {
12062
0
  exprOp = &ctxt->comp->steps[op->ch2];
12063
0
    } else
12064
0
  return(0);
12065
12066
0
    if ((exprOp != NULL) &&
12067
0
  (exprOp->op == XPATH_OP_VALUE) &&
12068
0
  (exprOp->value4 != NULL) &&
12069
0
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12070
0
    {
12071
0
        double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
12072
12073
  /*
12074
  * We have a "[n]" predicate here.
12075
  * TODO: Unfortunately this simplistic test here is not
12076
  * able to detect a position() predicate in compound
12077
  * expressions like "[@attr = 'a" and position() = 1],
12078
  * and even not the usage of position() in
12079
  * "[position() = 1]"; thus - obviously - a position-range,
12080
  * like it "[position() < 5]", is also not detected.
12081
  * Maybe we could rewrite the AST to ease the optimization.
12082
  */
12083
12084
0
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
12085
0
      *maxPos = (int) floatval;
12086
0
            if (floatval == (double) *maxPos)
12087
0
                return(1);
12088
0
        }
12089
0
    }
12090
0
    return(0);
12091
0
}
12092
12093
static int
12094
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12095
                           xmlXPathStepOpPtr op,
12096
         xmlNodePtr * first, xmlNodePtr * last,
12097
         int toBool)
12098
0
{
12099
12100
0
#define XP_TEST_HIT \
12101
0
    if (hasAxisRange != 0) { \
12102
0
  if (++pos == maxPos) { \
12103
0
      if (addNode(seq, cur) < 0) \
12104
0
          ctxt->error = XPATH_MEMORY_ERROR; \
12105
0
      goto axis_range_end; } \
12106
0
    } else { \
12107
0
  if (addNode(seq, cur) < 0) \
12108
0
      ctxt->error = XPATH_MEMORY_ERROR; \
12109
0
  if (breakOnFirstHit) goto first_hit; }
12110
12111
0
#define XP_TEST_HIT_NS \
12112
0
    if (hasAxisRange != 0) { \
12113
0
  if (++pos == maxPos) { \
12114
0
      hasNsNodes = 1; \
12115
0
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12116
0
          ctxt->error = XPATH_MEMORY_ERROR; \
12117
0
  goto axis_range_end; } \
12118
0
    } else { \
12119
0
  hasNsNodes = 1; \
12120
0
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12121
0
      ctxt->error = XPATH_MEMORY_ERROR; \
12122
0
  if (breakOnFirstHit) goto first_hit; }
12123
12124
0
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12125
0
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12126
0
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12127
0
    const xmlChar *prefix = op->value4;
12128
0
    const xmlChar *name = op->value5;
12129
0
    const xmlChar *URI = NULL;
12130
12131
#ifdef DEBUG_STEP
12132
    int nbMatches = 0, prevMatches = 0;
12133
#endif
12134
0
    int total = 0, hasNsNodes = 0;
12135
    /* The popped object holding the context nodes */
12136
0
    xmlXPathObjectPtr obj;
12137
    /* The set of context nodes for the node tests */
12138
0
    xmlNodeSetPtr contextSeq;
12139
0
    int contextIdx;
12140
0
    xmlNodePtr contextNode;
12141
    /* The final resulting node set wrt to all context nodes */
12142
0
    xmlNodeSetPtr outSeq;
12143
    /*
12144
    * The temporary resulting node set wrt 1 context node.
12145
    * Used to feed predicate evaluation.
12146
    */
12147
0
    xmlNodeSetPtr seq;
12148
0
    xmlNodePtr cur;
12149
    /* First predicate operator */
12150
0
    xmlXPathStepOpPtr predOp;
12151
0
    int maxPos; /* The requested position() (when a "[n]" predicate) */
12152
0
    int hasPredicateRange, hasAxisRange, pos, size, newSize;
12153
0
    int breakOnFirstHit;
12154
12155
0
    xmlXPathTraversalFunction next = NULL;
12156
0
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12157
0
    xmlXPathNodeSetMergeFunction mergeAndClear;
12158
0
    xmlNodePtr oldContextNode;
12159
0
    xmlXPathContextPtr xpctxt = ctxt->context;
12160
12161
12162
0
    CHECK_TYPE0(XPATH_NODESET);
12163
0
    obj = valuePop(ctxt);
12164
    /*
12165
    * Setup namespaces.
12166
    */
12167
0
    if (prefix != NULL) {
12168
0
        URI = xmlXPathNsLookup(xpctxt, prefix);
12169
0
        if (URI == NULL) {
12170
0
      xmlXPathReleaseObject(xpctxt, obj);
12171
0
            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12172
0
  }
12173
0
    }
12174
    /*
12175
    * Setup axis.
12176
    *
12177
    * MAYBE FUTURE TODO: merging optimizations:
12178
    * - If the nodes to be traversed wrt to the initial nodes and
12179
    *   the current axis cannot overlap, then we could avoid searching
12180
    *   for duplicates during the merge.
12181
    *   But the question is how/when to evaluate if they cannot overlap.
12182
    *   Example: if we know that for two initial nodes, the one is
12183
    *   not in the ancestor-or-self axis of the other, then we could safely
12184
    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12185
    *   the descendant-or-self axis.
12186
    */
12187
0
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
12188
0
    switch (axis) {
12189
0
        case AXIS_ANCESTOR:
12190
0
            first = NULL;
12191
0
            next = xmlXPathNextAncestor;
12192
0
            break;
12193
0
        case AXIS_ANCESTOR_OR_SELF:
12194
0
            first = NULL;
12195
0
            next = xmlXPathNextAncestorOrSelf;
12196
0
            break;
12197
0
        case AXIS_ATTRIBUTE:
12198
0
            first = NULL;
12199
0
      last = NULL;
12200
0
            next = xmlXPathNextAttribute;
12201
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12202
0
            break;
12203
0
        case AXIS_CHILD:
12204
0
      last = NULL;
12205
0
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12206
0
    (type == NODE_TYPE_NODE))
12207
0
      {
12208
    /*
12209
    * Optimization if an element node type is 'element'.
12210
    */
12211
0
    next = xmlXPathNextChildElement;
12212
0
      } else
12213
0
    next = xmlXPathNextChild;
12214
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12215
0
            break;
12216
0
        case AXIS_DESCENDANT:
12217
0
      last = NULL;
12218
0
            next = xmlXPathNextDescendant;
12219
0
            break;
12220
0
        case AXIS_DESCENDANT_OR_SELF:
12221
0
      last = NULL;
12222
0
            next = xmlXPathNextDescendantOrSelf;
12223
0
            break;
12224
0
        case AXIS_FOLLOWING:
12225
0
      last = NULL;
12226
0
            next = xmlXPathNextFollowing;
12227
0
            break;
12228
0
        case AXIS_FOLLOWING_SIBLING:
12229
0
      last = NULL;
12230
0
            next = xmlXPathNextFollowingSibling;
12231
0
            break;
12232
0
        case AXIS_NAMESPACE:
12233
0
            first = NULL;
12234
0
      last = NULL;
12235
0
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12236
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12237
0
            break;
12238
0
        case AXIS_PARENT:
12239
0
            first = NULL;
12240
0
            next = xmlXPathNextParent;
12241
0
            break;
12242
0
        case AXIS_PRECEDING:
12243
0
            first = NULL;
12244
0
            next = xmlXPathNextPrecedingInternal;
12245
0
            break;
12246
0
        case AXIS_PRECEDING_SIBLING:
12247
0
            first = NULL;
12248
0
            next = xmlXPathNextPrecedingSibling;
12249
0
            break;
12250
0
        case AXIS_SELF:
12251
0
            first = NULL;
12252
0
      last = NULL;
12253
0
            next = xmlXPathNextSelf;
12254
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12255
0
            break;
12256
0
    }
12257
12258
#ifdef DEBUG_STEP
12259
    xmlXPathDebugDumpStepAxis(op,
12260
  (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12261
#endif
12262
12263
0
    if (next == NULL) {
12264
0
  xmlXPathReleaseObject(xpctxt, obj);
12265
0
        return(0);
12266
0
    }
12267
0
    contextSeq = obj->nodesetval;
12268
0
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12269
0
  xmlXPathReleaseObject(xpctxt, obj);
12270
0
        valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12271
0
        return(0);
12272
0
    }
12273
    /*
12274
    * Predicate optimization ---------------------------------------------
12275
    * If this step has a last predicate, which contains a position(),
12276
    * then we'll optimize (although not exactly "position()", but only
12277
    * the  short-hand form, i.e., "[n]".
12278
    *
12279
    * Example - expression "/foo[parent::bar][1]":
12280
    *
12281
    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12282
    *   ROOT                               -- op->ch1
12283
    *   PREDICATE                          -- op->ch2 (predOp)
12284
    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12285
    *       SORT
12286
    *         COLLECT  'parent' 'name' 'node' bar
12287
    *           NODE
12288
    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12289
    *
12290
    */
12291
0
    maxPos = 0;
12292
0
    predOp = NULL;
12293
0
    hasPredicateRange = 0;
12294
0
    hasAxisRange = 0;
12295
0
    if (op->ch2 != -1) {
12296
  /*
12297
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12298
  */
12299
0
  predOp = &ctxt->comp->steps[op->ch2];
12300
0
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12301
0
      if (predOp->ch1 != -1) {
12302
    /*
12303
    * Use the next inner predicate operator.
12304
    */
12305
0
    predOp = &ctxt->comp->steps[predOp->ch1];
12306
0
    hasPredicateRange = 1;
12307
0
      } else {
12308
    /*
12309
    * There's no other predicate than the [n] predicate.
12310
    */
12311
0
    predOp = NULL;
12312
0
    hasAxisRange = 1;
12313
0
      }
12314
0
  }
12315
0
    }
12316
0
    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12317
    /*
12318
    * Axis traversal -----------------------------------------------------
12319
    */
12320
    /*
12321
     * 2.3 Node Tests
12322
     *  - For the attribute axis, the principal node type is attribute.
12323
     *  - For the namespace axis, the principal node type is namespace.
12324
     *  - For other axes, the principal node type is element.
12325
     *
12326
     * A node test * is true for any node of the
12327
     * principal node type. For example, child::* will
12328
     * select all element children of the context node
12329
     */
12330
0
    oldContextNode = xpctxt->node;
12331
0
    addNode = xmlXPathNodeSetAddUnique;
12332
0
    outSeq = NULL;
12333
0
    seq = NULL;
12334
0
    contextNode = NULL;
12335
0
    contextIdx = 0;
12336
12337
12338
0
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12339
0
           (ctxt->error == XPATH_EXPRESSION_OK)) {
12340
0
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
12341
12342
0
  if (seq == NULL) {
12343
0
      seq = xmlXPathNodeSetCreate(NULL);
12344
0
      if (seq == NULL) {
12345
0
    total = 0;
12346
0
    goto error;
12347
0
      }
12348
0
  }
12349
  /*
12350
  * Traverse the axis and test the nodes.
12351
  */
12352
0
  pos = 0;
12353
0
  cur = NULL;
12354
0
  hasNsNodes = 0;
12355
0
        do {
12356
0
            cur = next(ctxt, cur);
12357
0
            if (cur == NULL)
12358
0
                break;
12359
12360
      /*
12361
      * QUESTION TODO: What does the "first" and "last" stuff do?
12362
      */
12363
0
            if ((first != NULL) && (*first != NULL)) {
12364
0
    if (*first == cur)
12365
0
        break;
12366
0
    if (((total % 256) == 0) &&
12367
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12368
0
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
12369
#else
12370
        (xmlXPathCmpNodes(*first, cur) >= 0))
12371
#endif
12372
0
    {
12373
0
        break;
12374
0
    }
12375
0
      }
12376
0
      if ((last != NULL) && (*last != NULL)) {
12377
0
    if (*last == cur)
12378
0
        break;
12379
0
    if (((total % 256) == 0) &&
12380
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12381
0
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
12382
#else
12383
        (xmlXPathCmpNodes(cur, *last) >= 0))
12384
#endif
12385
0
    {
12386
0
        break;
12387
0
    }
12388
0
      }
12389
12390
0
            total++;
12391
12392
#ifdef DEBUG_STEP
12393
            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12394
#endif
12395
12396
0
      switch (test) {
12397
0
                case NODE_TEST_NONE:
12398
0
        total = 0;
12399
0
                    STRANGE
12400
0
        goto error;
12401
0
                case NODE_TEST_TYPE:
12402
0
        if (type == NODE_TYPE_NODE) {
12403
0
      switch (cur->type) {
12404
0
          case XML_DOCUMENT_NODE:
12405
0
          case XML_HTML_DOCUMENT_NODE:
12406
0
#ifdef LIBXML_DOCB_ENABLED
12407
0
          case XML_DOCB_DOCUMENT_NODE:
12408
0
#endif
12409
0
          case XML_ELEMENT_NODE:
12410
0
          case XML_ATTRIBUTE_NODE:
12411
0
          case XML_PI_NODE:
12412
0
          case XML_COMMENT_NODE:
12413
0
          case XML_CDATA_SECTION_NODE:
12414
0
          case XML_TEXT_NODE:
12415
0
        XP_TEST_HIT
12416
0
        break;
12417
0
          case XML_NAMESPACE_DECL: {
12418
0
        if (axis == AXIS_NAMESPACE) {
12419
0
            XP_TEST_HIT_NS
12420
0
        } else {
12421
0
                              hasNsNodes = 1;
12422
0
            XP_TEST_HIT
12423
0
        }
12424
0
        break;
12425
0
                            }
12426
0
          default:
12427
0
        break;
12428
0
      }
12429
0
        } else if (cur->type == type) {
12430
0
      if (cur->type == XML_NAMESPACE_DECL)
12431
0
          XP_TEST_HIT_NS
12432
0
      else
12433
0
          XP_TEST_HIT
12434
0
        } else if ((type == NODE_TYPE_TEXT) &&
12435
0
       (cur->type == XML_CDATA_SECTION_NODE))
12436
0
        {
12437
0
      XP_TEST_HIT
12438
0
        }
12439
0
        break;
12440
0
                case NODE_TEST_PI:
12441
0
                    if ((cur->type == XML_PI_NODE) &&
12442
0
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
12443
0
        {
12444
0
      XP_TEST_HIT
12445
0
                    }
12446
0
                    break;
12447
0
                case NODE_TEST_ALL:
12448
0
                    if (axis == AXIS_ATTRIBUTE) {
12449
0
                        if (cur->type == XML_ATTRIBUTE_NODE)
12450
0
      {
12451
0
                            if (prefix == NULL)
12452
0
          {
12453
0
        XP_TEST_HIT
12454
0
                            } else if ((cur->ns != NULL) &&
12455
0
        (xmlStrEqual(URI, cur->ns->href)))
12456
0
          {
12457
0
        XP_TEST_HIT
12458
0
                            }
12459
0
                        }
12460
0
                    } else if (axis == AXIS_NAMESPACE) {
12461
0
                        if (cur->type == XML_NAMESPACE_DECL)
12462
0
      {
12463
0
          XP_TEST_HIT_NS
12464
0
                        }
12465
0
                    } else {
12466
0
                        if (cur->type == XML_ELEMENT_NODE) {
12467
0
                            if (prefix == NULL)
12468
0
          {
12469
0
        XP_TEST_HIT
12470
12471
0
                            } else if ((cur->ns != NULL) &&
12472
0
        (xmlStrEqual(URI, cur->ns->href)))
12473
0
          {
12474
0
        XP_TEST_HIT
12475
0
                            }
12476
0
                        }
12477
0
                    }
12478
0
                    break;
12479
0
                case NODE_TEST_NS:{
12480
0
                        TODO;
12481
0
                        break;
12482
0
                    }
12483
0
                case NODE_TEST_NAME:
12484
0
                    if (axis == AXIS_ATTRIBUTE) {
12485
0
                        if (cur->type != XML_ATTRIBUTE_NODE)
12486
0
          break;
12487
0
        } else if (axis == AXIS_NAMESPACE) {
12488
0
                        if (cur->type != XML_NAMESPACE_DECL)
12489
0
          break;
12490
0
        } else {
12491
0
            if (cur->type != XML_ELEMENT_NODE)
12492
0
          break;
12493
0
        }
12494
0
                    switch (cur->type) {
12495
0
                        case XML_ELEMENT_NODE:
12496
0
                            if (xmlStrEqual(name, cur->name)) {
12497
0
                                if (prefix == NULL) {
12498
0
                                    if (cur->ns == NULL)
12499
0
            {
12500
0
          XP_TEST_HIT
12501
0
                                    }
12502
0
                                } else {
12503
0
                                    if ((cur->ns != NULL) &&
12504
0
                                        (xmlStrEqual(URI, cur->ns->href)))
12505
0
            {
12506
0
          XP_TEST_HIT
12507
0
                                    }
12508
0
                                }
12509
0
                            }
12510
0
                            break;
12511
0
                        case XML_ATTRIBUTE_NODE:{
12512
0
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
12513
12514
0
                                if (xmlStrEqual(name, attr->name)) {
12515
0
                                    if (prefix == NULL) {
12516
0
                                        if ((attr->ns == NULL) ||
12517
0
                                            (attr->ns->prefix == NULL))
12518
0
          {
12519
0
              XP_TEST_HIT
12520
0
                                        }
12521
0
                                    } else {
12522
0
                                        if ((attr->ns != NULL) &&
12523
0
                                            (xmlStrEqual(URI,
12524
0
                attr->ns->href)))
12525
0
          {
12526
0
              XP_TEST_HIT
12527
0
                                        }
12528
0
                                    }
12529
0
                                }
12530
0
                                break;
12531
0
                            }
12532
0
                        case XML_NAMESPACE_DECL:
12533
0
                            if (cur->type == XML_NAMESPACE_DECL) {
12534
0
                                xmlNsPtr ns = (xmlNsPtr) cur;
12535
12536
0
                                if ((ns->prefix != NULL) && (name != NULL)
12537
0
                                    && (xmlStrEqual(ns->prefix, name)))
12538
0
        {
12539
0
            XP_TEST_HIT_NS
12540
0
                                }
12541
0
                            }
12542
0
                            break;
12543
0
                        default:
12544
0
                            break;
12545
0
                    }
12546
0
                    break;
12547
0
      } /* switch(test) */
12548
0
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12549
12550
0
  goto apply_predicates;
12551
12552
0
axis_range_end: /* ----------------------------------------------------- */
12553
  /*
12554
  * We have a "/foo[n]", and position() = n was reached.
12555
  * Note that we can have as well "/foo/::parent::foo[1]", so
12556
  * a duplicate-aware merge is still needed.
12557
  * Merge with the result.
12558
  */
12559
0
  if (outSeq == NULL) {
12560
0
      outSeq = seq;
12561
0
      seq = NULL;
12562
0
  } else
12563
0
      outSeq = mergeAndClear(outSeq, seq, 0);
12564
  /*
12565
  * Break if only a true/false result was requested.
12566
  */
12567
0
  if (toBool)
12568
0
      break;
12569
0
  continue;
12570
12571
0
first_hit: /* ---------------------------------------------------------- */
12572
  /*
12573
  * Break if only a true/false result was requested and
12574
  * no predicates existed and a node test succeeded.
12575
  */
12576
0
  if (outSeq == NULL) {
12577
0
      outSeq = seq;
12578
0
      seq = NULL;
12579
0
  } else
12580
0
      outSeq = mergeAndClear(outSeq, seq, 0);
12581
0
  break;
12582
12583
#ifdef DEBUG_STEP
12584
  if (seq != NULL)
12585
      nbMatches += seq->nodeNr;
12586
#endif
12587
12588
0
apply_predicates: /* --------------------------------------------------- */
12589
0
        if (ctxt->error != XPATH_EXPRESSION_OK)
12590
0
      goto error;
12591
12592
        /*
12593
  * Apply predicates.
12594
  */
12595
0
        if ((predOp != NULL) && (seq->nodeNr > 0)) {
12596
      /*
12597
      * E.g. when we have a "/foo[some expression][n]".
12598
      */
12599
      /*
12600
      * QUESTION TODO: The old predicate evaluation took into
12601
      *  account location-sets.
12602
      *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12603
      *  Do we expect such a set here?
12604
      *  All what I learned now from the evaluation semantics
12605
      *  does not indicate that a location-set will be processed
12606
      *  here, so this looks OK.
12607
      */
12608
      /*
12609
      * Iterate over all predicates, starting with the outermost
12610
      * predicate.
12611
      * TODO: Problem: we cannot execute the inner predicates first
12612
      *  since we cannot go back *up* the operator tree!
12613
      *  Options we have:
12614
      *  1) Use of recursive functions (like is it currently done
12615
      *     via xmlXPathCompOpEval())
12616
      *  2) Add a predicate evaluation information stack to the
12617
      *     context struct
12618
      *  3) Change the way the operators are linked; we need a
12619
      *     "parent" field on xmlXPathStepOp
12620
      *
12621
      * For the moment, I'll try to solve this with a recursive
12622
      * function: xmlXPathCompOpEvalPredicate().
12623
      */
12624
0
      size = seq->nodeNr;
12625
0
      if (hasPredicateRange != 0)
12626
0
    newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12627
0
        predOp, seq, size, maxPos, maxPos, hasNsNodes);
12628
0
      else
12629
0
    newSize = xmlXPathCompOpEvalPredicate(ctxt,
12630
0
        predOp, seq, size, hasNsNodes);
12631
12632
0
      if (ctxt->error != XPATH_EXPRESSION_OK) {
12633
0
    total = 0;
12634
0
    goto error;
12635
0
      }
12636
      /*
12637
      * Add the filtered set of nodes to the result node set.
12638
      */
12639
0
      if (newSize == 0) {
12640
    /*
12641
    * The predicates filtered all nodes out.
12642
    */
12643
0
    xmlXPathNodeSetClear(seq, hasNsNodes);
12644
0
      } else if (seq->nodeNr > 0) {
12645
    /*
12646
    * Add to result set.
12647
    */
12648
0
    if (outSeq == NULL) {
12649
0
        if (size != newSize) {
12650
      /*
12651
      * We need to merge and clear here, since
12652
      * the sequence will contained NULLed entries.
12653
      */
12654
0
      outSeq = mergeAndClear(NULL, seq, 1);
12655
0
        } else {
12656
0
      outSeq = seq;
12657
0
      seq = NULL;
12658
0
        }
12659
0
    } else
12660
0
        outSeq = mergeAndClear(outSeq, seq,
12661
0
      (size != newSize) ? 1: 0);
12662
    /*
12663
    * Break if only a true/false result was requested.
12664
    */
12665
0
    if (toBool)
12666
0
        break;
12667
0
      }
12668
0
        } else if (seq->nodeNr > 0) {
12669
      /*
12670
      * Add to result set.
12671
      */
12672
0
      if (outSeq == NULL) {
12673
0
    outSeq = seq;
12674
0
    seq = NULL;
12675
0
      } else {
12676
0
    outSeq = mergeAndClear(outSeq, seq, 0);
12677
0
      }
12678
0
  }
12679
0
    }
12680
12681
0
error:
12682
0
    if ((obj->boolval) && (obj->user != NULL)) {
12683
  /*
12684
  * QUESTION TODO: What does this do and why?
12685
  * TODO: Do we have to do this also for the "error"
12686
  * cleanup further down?
12687
  */
12688
0
  ctxt->value->boolval = 1;
12689
0
  ctxt->value->user = obj->user;
12690
0
  obj->user = NULL;
12691
0
  obj->boolval = 0;
12692
0
    }
12693
0
    xmlXPathReleaseObject(xpctxt, obj);
12694
12695
    /*
12696
    * Ensure we return at least an emtpy set.
12697
    */
12698
0
    if (outSeq == NULL) {
12699
0
  if ((seq != NULL) && (seq->nodeNr == 0))
12700
0
      outSeq = seq;
12701
0
  else
12702
0
      outSeq = xmlXPathNodeSetCreate(NULL);
12703
        /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12704
0
    }
12705
0
    if ((seq != NULL) && (seq != outSeq)) {
12706
0
   xmlXPathFreeNodeSet(seq);
12707
0
    }
12708
    /*
12709
    * Hand over the result. Better to push the set also in
12710
    * case of errors.
12711
    */
12712
0
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12713
    /*
12714
    * Reset the context node.
12715
    */
12716
0
    xpctxt->node = oldContextNode;
12717
    /*
12718
    * When traversing the namespace axis in "toBool" mode, it's
12719
    * possible that tmpNsList wasn't freed.
12720
    */
12721
0
    if (xpctxt->tmpNsList != NULL) {
12722
0
        xmlFree(xpctxt->tmpNsList);
12723
0
        xpctxt->tmpNsList = NULL;
12724
0
    }
12725
12726
#ifdef DEBUG_STEP
12727
    xmlGenericError(xmlGenericErrorContext,
12728
  "\nExamined %d nodes, found %d nodes at that step\n",
12729
  total, nbMatches);
12730
#endif
12731
12732
0
    return(total);
12733
0
}
12734
12735
static int
12736
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12737
            xmlXPathStepOpPtr op, xmlNodePtr * first);
12738
12739
/**
12740
 * xmlXPathCompOpEvalFirst:
12741
 * @ctxt:  the XPath parser context with the compiled expression
12742
 * @op:  an XPath compiled operation
12743
 * @first:  the first elem found so far
12744
 *
12745
 * Evaluate the Precompiled XPath operation searching only the first
12746
 * element in document order
12747
 *
12748
 * Returns the number of examined objects.
12749
 */
12750
static int
12751
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12752
                        xmlXPathStepOpPtr op, xmlNodePtr * first)
12753
0
{
12754
0
    int total = 0, cur;
12755
0
    xmlXPathCompExprPtr comp;
12756
0
    xmlXPathObjectPtr arg1, arg2;
12757
12758
0
    CHECK_ERROR0;
12759
0
    comp = ctxt->comp;
12760
0
    switch (op->op) {
12761
0
        case XPATH_OP_END:
12762
0
            return (0);
12763
0
        case XPATH_OP_UNION:
12764
0
            total =
12765
0
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12766
0
                                        first);
12767
0
      CHECK_ERROR0;
12768
0
            if ((ctxt->value != NULL)
12769
0
                && (ctxt->value->type == XPATH_NODESET)
12770
0
                && (ctxt->value->nodesetval != NULL)
12771
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12772
                /*
12773
                 * limit tree traversing to first node in the result
12774
                 */
12775
    /*
12776
    * OPTIMIZE TODO: This implicitely sorts
12777
    *  the result, even if not needed. E.g. if the argument
12778
    *  of the count() function, no sorting is needed.
12779
    * OPTIMIZE TODO: How do we know if the node-list wasn't
12780
    *  aready sorted?
12781
    */
12782
0
    if (ctxt->value->nodesetval->nodeNr > 1)
12783
0
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12784
0
                *first = ctxt->value->nodesetval->nodeTab[0];
12785
0
            }
12786
0
            cur =
12787
0
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12788
0
                                        first);
12789
0
      CHECK_ERROR0;
12790
12791
0
            arg2 = valuePop(ctxt);
12792
0
            arg1 = valuePop(ctxt);
12793
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12794
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12795
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12796
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12797
0
                XP_ERROR0(XPATH_INVALID_TYPE);
12798
0
            }
12799
12800
0
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12801
0
                                                    arg2->nodesetval);
12802
0
            valuePush(ctxt, arg1);
12803
0
      xmlXPathReleaseObject(ctxt->context, arg2);
12804
            /* optimizer */
12805
0
      if (total > cur)
12806
0
    xmlXPathCompSwap(op);
12807
0
            return (total + cur);
12808
0
        case XPATH_OP_ROOT:
12809
0
            xmlXPathRoot(ctxt);
12810
0
            return (0);
12811
0
        case XPATH_OP_NODE:
12812
0
            if (op->ch1 != -1)
12813
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12814
0
      CHECK_ERROR0;
12815
0
            if (op->ch2 != -1)
12816
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12817
0
      CHECK_ERROR0;
12818
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12819
0
    ctxt->context->node));
12820
0
            return (total);
12821
0
        case XPATH_OP_RESET:
12822
0
            if (op->ch1 != -1)
12823
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12824
0
      CHECK_ERROR0;
12825
0
            if (op->ch2 != -1)
12826
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12827
0
      CHECK_ERROR0;
12828
0
            ctxt->context->node = NULL;
12829
0
            return (total);
12830
0
        case XPATH_OP_COLLECT:{
12831
0
                if (op->ch1 == -1)
12832
0
                    return (total);
12833
12834
0
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12835
0
    CHECK_ERROR0;
12836
12837
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12838
0
                return (total);
12839
0
            }
12840
0
        case XPATH_OP_VALUE:
12841
0
            valuePush(ctxt,
12842
0
                      xmlXPathCacheObjectCopy(ctxt->context,
12843
0
      (xmlXPathObjectPtr) op->value4));
12844
0
            return (0);
12845
0
        case XPATH_OP_SORT:
12846
0
            if (op->ch1 != -1)
12847
0
                total +=
12848
0
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12849
0
                                            first);
12850
0
      CHECK_ERROR0;
12851
0
            if ((ctxt->value != NULL)
12852
0
                && (ctxt->value->type == XPATH_NODESET)
12853
0
                && (ctxt->value->nodesetval != NULL)
12854
0
    && (ctxt->value->nodesetval->nodeNr > 1))
12855
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12856
0
            return (total);
12857
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
12858
0
  case XPATH_OP_FILTER:
12859
0
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12860
0
            return (total);
12861
0
#endif
12862
0
        default:
12863
0
            return (xmlXPathCompOpEval(ctxt, op));
12864
0
    }
12865
0
}
12866
12867
/**
12868
 * xmlXPathCompOpEvalLast:
12869
 * @ctxt:  the XPath parser context with the compiled expression
12870
 * @op:  an XPath compiled operation
12871
 * @last:  the last elem found so far
12872
 *
12873
 * Evaluate the Precompiled XPath operation searching only the last
12874
 * element in document order
12875
 *
12876
 * Returns the number of nodes traversed
12877
 */
12878
static int
12879
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12880
                       xmlNodePtr * last)
12881
0
{
12882
0
    int total = 0, cur;
12883
0
    xmlXPathCompExprPtr comp;
12884
0
    xmlXPathObjectPtr arg1, arg2;
12885
0
    xmlNodePtr bak;
12886
0
    xmlDocPtr bakd;
12887
0
    int pp;
12888
0
    int cs;
12889
12890
0
    CHECK_ERROR0;
12891
0
    comp = ctxt->comp;
12892
0
    switch (op->op) {
12893
0
        case XPATH_OP_END:
12894
0
            return (0);
12895
0
        case XPATH_OP_UNION:
12896
0
      bakd = ctxt->context->doc;
12897
0
      bak = ctxt->context->node;
12898
0
      pp = ctxt->context->proximityPosition;
12899
0
      cs = ctxt->context->contextSize;
12900
0
            total =
12901
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12902
0
      CHECK_ERROR0;
12903
0
            if ((ctxt->value != NULL)
12904
0
                && (ctxt->value->type == XPATH_NODESET)
12905
0
                && (ctxt->value->nodesetval != NULL)
12906
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12907
                /*
12908
                 * limit tree traversing to first node in the result
12909
                 */
12910
0
    if (ctxt->value->nodesetval->nodeNr > 1)
12911
0
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12912
0
                *last =
12913
0
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
12914
0
                                                     nodesetval->nodeNr -
12915
0
                                                     1];
12916
0
            }
12917
0
      ctxt->context->doc = bakd;
12918
0
      ctxt->context->node = bak;
12919
0
      ctxt->context->proximityPosition = pp;
12920
0
      ctxt->context->contextSize = cs;
12921
0
            cur =
12922
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12923
0
      CHECK_ERROR0;
12924
0
            if ((ctxt->value != NULL)
12925
0
                && (ctxt->value->type == XPATH_NODESET)
12926
0
                && (ctxt->value->nodesetval != NULL)
12927
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12928
0
            }
12929
12930
0
            arg2 = valuePop(ctxt);
12931
0
            arg1 = valuePop(ctxt);
12932
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12933
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12934
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12935
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12936
0
                XP_ERROR0(XPATH_INVALID_TYPE);
12937
0
            }
12938
12939
0
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12940
0
                                                    arg2->nodesetval);
12941
0
            valuePush(ctxt, arg1);
12942
0
      xmlXPathReleaseObject(ctxt->context, arg2);
12943
            /* optimizer */
12944
0
      if (total > cur)
12945
0
    xmlXPathCompSwap(op);
12946
0
            return (total + cur);
12947
0
        case XPATH_OP_ROOT:
12948
0
            xmlXPathRoot(ctxt);
12949
0
            return (0);
12950
0
        case XPATH_OP_NODE:
12951
0
            if (op->ch1 != -1)
12952
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12953
0
      CHECK_ERROR0;
12954
0
            if (op->ch2 != -1)
12955
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12956
0
      CHECK_ERROR0;
12957
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12958
0
    ctxt->context->node));
12959
0
            return (total);
12960
0
        case XPATH_OP_RESET:
12961
0
            if (op->ch1 != -1)
12962
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12963
0
      CHECK_ERROR0;
12964
0
            if (op->ch2 != -1)
12965
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12966
0
      CHECK_ERROR0;
12967
0
            ctxt->context->node = NULL;
12968
0
            return (total);
12969
0
        case XPATH_OP_COLLECT:{
12970
0
                if (op->ch1 == -1)
12971
0
                    return (0);
12972
12973
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12974
0
    CHECK_ERROR0;
12975
12976
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12977
0
                return (total);
12978
0
            }
12979
0
        case XPATH_OP_VALUE:
12980
0
            valuePush(ctxt,
12981
0
                      xmlXPathCacheObjectCopy(ctxt->context,
12982
0
      (xmlXPathObjectPtr) op->value4));
12983
0
            return (0);
12984
0
        case XPATH_OP_SORT:
12985
0
            if (op->ch1 != -1)
12986
0
                total +=
12987
0
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12988
0
                                           last);
12989
0
      CHECK_ERROR0;
12990
0
            if ((ctxt->value != NULL)
12991
0
                && (ctxt->value->type == XPATH_NODESET)
12992
0
                && (ctxt->value->nodesetval != NULL)
12993
0
    && (ctxt->value->nodesetval->nodeNr > 1))
12994
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12995
0
            return (total);
12996
0
        default:
12997
0
            return (xmlXPathCompOpEval(ctxt, op));
12998
0
    }
12999
0
}
13000
13001
#ifdef XP_OPTIMIZED_FILTER_FIRST
13002
static int
13003
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
13004
            xmlXPathStepOpPtr op, xmlNodePtr * first)
13005
0
{
13006
0
    int total = 0;
13007
0
    xmlXPathCompExprPtr comp;
13008
0
    xmlXPathObjectPtr res;
13009
0
    xmlXPathObjectPtr obj;
13010
0
    xmlNodeSetPtr oldset;
13011
0
    xmlNodePtr oldnode;
13012
0
    xmlDocPtr oldDoc;
13013
0
    int i;
13014
13015
0
    CHECK_ERROR0;
13016
0
    comp = ctxt->comp;
13017
    /*
13018
    * Optimization for ()[last()] selection i.e. the last elem
13019
    */
13020
0
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
13021
0
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13022
0
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13023
0
  int f = comp->steps[op->ch2].ch1;
13024
13025
0
  if ((f != -1) &&
13026
0
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13027
0
      (comp->steps[f].value5 == NULL) &&
13028
0
      (comp->steps[f].value == 0) &&
13029
0
      (comp->steps[f].value4 != NULL) &&
13030
0
      (xmlStrEqual
13031
0
      (comp->steps[f].value4, BAD_CAST "last"))) {
13032
0
      xmlNodePtr last = NULL;
13033
13034
0
      total +=
13035
0
    xmlXPathCompOpEvalLast(ctxt,
13036
0
        &comp->steps[op->ch1],
13037
0
        &last);
13038
0
      CHECK_ERROR0;
13039
      /*
13040
      * The nodeset should be in document order,
13041
      * Keep only the last value
13042
      */
13043
0
      if ((ctxt->value != NULL) &&
13044
0
    (ctxt->value->type == XPATH_NODESET) &&
13045
0
    (ctxt->value->nodesetval != NULL) &&
13046
0
    (ctxt->value->nodesetval->nodeTab != NULL) &&
13047
0
    (ctxt->value->nodesetval->nodeNr > 1)) {
13048
0
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13049
0
    *first = *(ctxt->value->nodesetval->nodeTab);
13050
0
      }
13051
0
      return (total);
13052
0
  }
13053
0
    }
13054
13055
0
    if (op->ch1 != -1)
13056
0
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13057
0
    CHECK_ERROR0;
13058
0
    if (op->ch2 == -1)
13059
0
  return (total);
13060
0
    if (ctxt->value == NULL)
13061
0
  return (total);
13062
13063
0
#ifdef LIBXML_XPTR_ENABLED
13064
0
    oldnode = ctxt->context->node;
13065
    /*
13066
    * Hum are we filtering the result of an XPointer expression
13067
    */
13068
0
    if (ctxt->value->type == XPATH_LOCATIONSET) {
13069
0
  xmlXPathObjectPtr tmp = NULL;
13070
0
  xmlLocationSetPtr newlocset = NULL;
13071
0
  xmlLocationSetPtr oldlocset;
13072
13073
  /*
13074
  * Extract the old locset, and then evaluate the result of the
13075
  * expression for all the element in the locset. use it to grow
13076
  * up a new locset.
13077
  */
13078
0
  CHECK_TYPE0(XPATH_LOCATIONSET);
13079
0
  obj = valuePop(ctxt);
13080
0
  oldlocset = obj->user;
13081
0
  ctxt->context->node = NULL;
13082
13083
0
  if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13084
0
      ctxt->context->contextSize = 0;
13085
0
      ctxt->context->proximityPosition = 0;
13086
0
      if (op->ch2 != -1)
13087
0
    total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13088
0
      res = valuePop(ctxt);
13089
0
      if (res != NULL) {
13090
0
    xmlXPathReleaseObject(ctxt->context, res);
13091
0
      }
13092
0
      valuePush(ctxt, obj);
13093
0
      CHECK_ERROR0;
13094
0
      return (total);
13095
0
  }
13096
0
  newlocset = xmlXPtrLocationSetCreate(NULL);
13097
13098
0
  for (i = 0; i < oldlocset->locNr; i++) {
13099
      /*
13100
      * Run the evaluation with a node list made of a
13101
      * single item in the nodelocset.
13102
      */
13103
0
      ctxt->context->node = oldlocset->locTab[i]->user;
13104
0
      ctxt->context->contextSize = oldlocset->locNr;
13105
0
      ctxt->context->proximityPosition = i + 1;
13106
0
      if (tmp == NULL) {
13107
0
    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13108
0
        ctxt->context->node);
13109
0
      } else {
13110
0
    if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13111
0
                                 ctxt->context->node) < 0) {
13112
0
        ctxt->error = XPATH_MEMORY_ERROR;
13113
0
    }
13114
0
      }
13115
0
      valuePush(ctxt, tmp);
13116
0
      if (op->ch2 != -1)
13117
0
    total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13118
0
      if (ctxt->error != XPATH_EXPRESSION_OK) {
13119
0
    xmlXPathFreeObject(obj);
13120
0
    return(0);
13121
0
      }
13122
      /*
13123
      * The result of the evaluation need to be tested to
13124
      * decided whether the filter succeeded or not
13125
      */
13126
0
      res = valuePop(ctxt);
13127
0
      if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13128
0
    xmlXPtrLocationSetAdd(newlocset,
13129
0
        xmlXPathCacheObjectCopy(ctxt->context,
13130
0
      oldlocset->locTab[i]));
13131
0
      }
13132
      /*
13133
      * Cleanup
13134
      */
13135
0
      if (res != NULL) {
13136
0
    xmlXPathReleaseObject(ctxt->context, res);
13137
0
      }
13138
0
      if (ctxt->value == tmp) {
13139
0
    valuePop(ctxt);
13140
0
    xmlXPathNodeSetClear(tmp->nodesetval, 1);
13141
    /*
13142
    * REVISIT TODO: Don't create a temporary nodeset
13143
    * for everly iteration.
13144
    */
13145
    /* OLD: xmlXPathFreeObject(res); */
13146
0
      } else
13147
0
    tmp = NULL;
13148
0
      ctxt->context->node = NULL;
13149
      /*
13150
      * Only put the first node in the result, then leave.
13151
      */
13152
0
      if (newlocset->locNr > 0) {
13153
0
    *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13154
0
    break;
13155
0
      }
13156
0
  }
13157
0
  if (tmp != NULL) {
13158
0
      xmlXPathReleaseObject(ctxt->context, tmp);
13159
0
  }
13160
  /*
13161
  * The result is used as the new evaluation locset.
13162
  */
13163
0
  xmlXPathReleaseObject(ctxt->context, obj);
13164
0
  ctxt->context->node = NULL;
13165
0
  ctxt->context->contextSize = -1;
13166
0
  ctxt->context->proximityPosition = -1;
13167
0
  valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13168
0
  ctxt->context->node = oldnode;
13169
0
  return (total);
13170
0
    }
13171
0
#endif /* LIBXML_XPTR_ENABLED */
13172
13173
    /*
13174
    * Extract the old set, and then evaluate the result of the
13175
    * expression for all the element in the set. use it to grow
13176
    * up a new set.
13177
    */
13178
0
    CHECK_TYPE0(XPATH_NODESET);
13179
0
    obj = valuePop(ctxt);
13180
0
    oldset = obj->nodesetval;
13181
13182
0
    oldnode = ctxt->context->node;
13183
0
    oldDoc = ctxt->context->doc;
13184
0
    ctxt->context->node = NULL;
13185
13186
0
    if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13187
0
  ctxt->context->contextSize = 0;
13188
0
  ctxt->context->proximityPosition = 0;
13189
  /* QUESTION TODO: Why was this code commented out?
13190
      if (op->ch2 != -1)
13191
    total +=
13192
        xmlXPathCompOpEval(ctxt,
13193
      &comp->steps[op->ch2]);
13194
      CHECK_ERROR0;
13195
      res = valuePop(ctxt);
13196
      if (res != NULL)
13197
    xmlXPathFreeObject(res);
13198
  */
13199
0
  valuePush(ctxt, obj);
13200
0
  ctxt->context->node = oldnode;
13201
0
  CHECK_ERROR0;
13202
0
    } else {
13203
0
  xmlNodeSetPtr newset;
13204
0
  xmlXPathObjectPtr tmp = NULL;
13205
  /*
13206
  * Initialize the new set.
13207
  * Also set the xpath document in case things like
13208
  * key() evaluation are attempted on the predicate
13209
  */
13210
0
  newset = xmlXPathNodeSetCreate(NULL);
13211
        /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13212
13213
0
  for (i = 0; i < oldset->nodeNr; i++) {
13214
      /*
13215
      * Run the evaluation with a node list made of
13216
      * a single item in the nodeset.
13217
      */
13218
0
      ctxt->context->node = oldset->nodeTab[i];
13219
0
      if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13220
0
    (oldset->nodeTab[i]->doc != NULL))
13221
0
    ctxt->context->doc = oldset->nodeTab[i]->doc;
13222
0
      if (tmp == NULL) {
13223
0
    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13224
0
        ctxt->context->node);
13225
0
      } else {
13226
0
    if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13227
0
                                 ctxt->context->node) < 0) {
13228
0
        ctxt->error = XPATH_MEMORY_ERROR;
13229
0
    }
13230
0
      }
13231
0
      valuePush(ctxt, tmp);
13232
0
      ctxt->context->contextSize = oldset->nodeNr;
13233
0
      ctxt->context->proximityPosition = i + 1;
13234
0
      if (op->ch2 != -1)
13235
0
    total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13236
0
      if (ctxt->error != XPATH_EXPRESSION_OK) {
13237
0
    xmlXPathFreeNodeSet(newset);
13238
0
    xmlXPathFreeObject(obj);
13239
0
    return(0);
13240
0
      }
13241
      /*
13242
      * The result of the evaluation needs to be tested to
13243
      * decide whether the filter succeeded or not
13244
      */
13245
0
      res = valuePop(ctxt);
13246
0
      if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13247
0
    if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13248
0
        ctxt->error = XPATH_MEMORY_ERROR;
13249
0
      }
13250
      /*
13251
      * Cleanup
13252
      */
13253
0
      if (res != NULL) {
13254
0
    xmlXPathReleaseObject(ctxt->context, res);
13255
0
      }
13256
0
      if (ctxt->value == tmp) {
13257
0
    valuePop(ctxt);
13258
    /*
13259
    * Don't free the temporary nodeset
13260
    * in order to avoid massive recreation inside this
13261
    * loop.
13262
    */
13263
0
    xmlXPathNodeSetClear(tmp->nodesetval, 1);
13264
0
      } else
13265
0
    tmp = NULL;
13266
0
      ctxt->context->node = NULL;
13267
      /*
13268
      * Only put the first node in the result, then leave.
13269
      */
13270
0
      if (newset->nodeNr > 0) {
13271
0
    *first = *(newset->nodeTab);
13272
0
    break;
13273
0
      }
13274
0
  }
13275
0
  if (tmp != NULL) {
13276
0
      xmlXPathReleaseObject(ctxt->context, tmp);
13277
0
  }
13278
  /*
13279
  * The result is used as the new evaluation set.
13280
  */
13281
0
  xmlXPathReleaseObject(ctxt->context, obj);
13282
0
  ctxt->context->node = NULL;
13283
0
  ctxt->context->contextSize = -1;
13284
0
  ctxt->context->proximityPosition = -1;
13285
  /* may want to move this past the '}' later */
13286
0
  ctxt->context->doc = oldDoc;
13287
0
  valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13288
0
    }
13289
0
    ctxt->context->node = oldnode;
13290
0
    return(total);
13291
0
}
13292
#endif /* XP_OPTIMIZED_FILTER_FIRST */
13293
13294
/**
13295
 * xmlXPathCompOpEval:
13296
 * @ctxt:  the XPath parser context with the compiled expression
13297
 * @op:  an XPath compiled operation
13298
 *
13299
 * Evaluate the Precompiled XPath operation
13300
 * Returns the number of nodes traversed
13301
 */
13302
static int
13303
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13304
0
{
13305
0
    int total = 0;
13306
0
    int equal, ret;
13307
0
    xmlXPathCompExprPtr comp;
13308
0
    xmlXPathObjectPtr arg1, arg2;
13309
0
    xmlNodePtr bak;
13310
0
    xmlDocPtr bakd;
13311
0
    int pp;
13312
0
    int cs;
13313
13314
0
    CHECK_ERROR0;
13315
0
    comp = ctxt->comp;
13316
0
    switch (op->op) {
13317
0
        case XPATH_OP_END:
13318
0
            return (0);
13319
0
        case XPATH_OP_AND:
13320
0
      bakd = ctxt->context->doc;
13321
0
      bak = ctxt->context->node;
13322
0
      pp = ctxt->context->proximityPosition;
13323
0
      cs = ctxt->context->contextSize;
13324
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13325
0
      CHECK_ERROR0;
13326
0
            xmlXPathBooleanFunction(ctxt, 1);
13327
0
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13328
0
                return (total);
13329
0
            arg2 = valuePop(ctxt);
13330
0
      ctxt->context->doc = bakd;
13331
0
      ctxt->context->node = bak;
13332
0
      ctxt->context->proximityPosition = pp;
13333
0
      ctxt->context->contextSize = cs;
13334
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13335
0
      if (ctxt->error) {
13336
0
    xmlXPathFreeObject(arg2);
13337
0
    return(0);
13338
0
      }
13339
0
            xmlXPathBooleanFunction(ctxt, 1);
13340
0
            arg1 = valuePop(ctxt);
13341
0
            arg1->boolval &= arg2->boolval;
13342
0
            valuePush(ctxt, arg1);
13343
0
      xmlXPathReleaseObject(ctxt->context, arg2);
13344
0
            return (total);
13345
0
        case XPATH_OP_OR:
13346
0
      bakd = ctxt->context->doc;
13347
0
      bak = ctxt->context->node;
13348
0
      pp = ctxt->context->proximityPosition;
13349
0
      cs = ctxt->context->contextSize;
13350
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13351
0
      CHECK_ERROR0;
13352
0
            xmlXPathBooleanFunction(ctxt, 1);
13353
0
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13354
0
                return (total);
13355
0
            arg2 = valuePop(ctxt);
13356
0
      ctxt->context->doc = bakd;
13357
0
      ctxt->context->node = bak;
13358
0
      ctxt->context->proximityPosition = pp;
13359
0
      ctxt->context->contextSize = cs;
13360
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13361
0
      if (ctxt->error) {
13362
0
    xmlXPathFreeObject(arg2);
13363
0
    return(0);
13364
0
      }
13365
0
            xmlXPathBooleanFunction(ctxt, 1);
13366
0
            arg1 = valuePop(ctxt);
13367
0
            arg1->boolval |= arg2->boolval;
13368
0
            valuePush(ctxt, arg1);
13369
0
      xmlXPathReleaseObject(ctxt->context, arg2);
13370
0
            return (total);
13371
0
        case XPATH_OP_EQUAL:
13372
0
      bakd = ctxt->context->doc;
13373
0
      bak = ctxt->context->node;
13374
0
      pp = ctxt->context->proximityPosition;
13375
0
      cs = ctxt->context->contextSize;
13376
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13377
0
      CHECK_ERROR0;
13378
0
      ctxt->context->doc = bakd;
13379
0
      ctxt->context->node = bak;
13380
0
      ctxt->context->proximityPosition = pp;
13381
0
      ctxt->context->contextSize = cs;
13382
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13383
0
      CHECK_ERROR0;
13384
0
      if (op->value)
13385
0
    equal = xmlXPathEqualValues(ctxt);
13386
0
      else
13387
0
    equal = xmlXPathNotEqualValues(ctxt);
13388
0
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13389
0
            return (total);
13390
0
        case XPATH_OP_CMP:
13391
0
      bakd = ctxt->context->doc;
13392
0
      bak = ctxt->context->node;
13393
0
      pp = ctxt->context->proximityPosition;
13394
0
      cs = ctxt->context->contextSize;
13395
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13396
0
      CHECK_ERROR0;
13397
0
      ctxt->context->doc = bakd;
13398
0
      ctxt->context->node = bak;
13399
0
      ctxt->context->proximityPosition = pp;
13400
0
      ctxt->context->contextSize = cs;
13401
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13402
0
      CHECK_ERROR0;
13403
0
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13404
0
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13405
0
            return (total);
13406
0
        case XPATH_OP_PLUS:
13407
0
      bakd = ctxt->context->doc;
13408
0
      bak = ctxt->context->node;
13409
0
      pp = ctxt->context->proximityPosition;
13410
0
      cs = ctxt->context->contextSize;
13411
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13412
0
      CHECK_ERROR0;
13413
0
            if (op->ch2 != -1) {
13414
0
    ctxt->context->doc = bakd;
13415
0
    ctxt->context->node = bak;
13416
0
    ctxt->context->proximityPosition = pp;
13417
0
    ctxt->context->contextSize = cs;
13418
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13419
0
      }
13420
0
      CHECK_ERROR0;
13421
0
            if (op->value == 0)
13422
0
                xmlXPathSubValues(ctxt);
13423
0
            else if (op->value == 1)
13424
0
                xmlXPathAddValues(ctxt);
13425
0
            else if (op->value == 2)
13426
0
                xmlXPathValueFlipSign(ctxt);
13427
0
            else if (op->value == 3) {
13428
0
                CAST_TO_NUMBER;
13429
0
                CHECK_TYPE0(XPATH_NUMBER);
13430
0
            }
13431
0
            return (total);
13432
0
        case XPATH_OP_MULT:
13433
0
      bakd = ctxt->context->doc;
13434
0
      bak = ctxt->context->node;
13435
0
      pp = ctxt->context->proximityPosition;
13436
0
      cs = ctxt->context->contextSize;
13437
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13438
0
      CHECK_ERROR0;
13439
0
      ctxt->context->doc = bakd;
13440
0
      ctxt->context->node = bak;
13441
0
      ctxt->context->proximityPosition = pp;
13442
0
      ctxt->context->contextSize = cs;
13443
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13444
0
      CHECK_ERROR0;
13445
0
            if (op->value == 0)
13446
0
                xmlXPathMultValues(ctxt);
13447
0
            else if (op->value == 1)
13448
0
                xmlXPathDivValues(ctxt);
13449
0
            else if (op->value == 2)
13450
0
                xmlXPathModValues(ctxt);
13451
0
            return (total);
13452
0
        case XPATH_OP_UNION:
13453
0
      bakd = ctxt->context->doc;
13454
0
      bak = ctxt->context->node;
13455
0
      pp = ctxt->context->proximityPosition;
13456
0
      cs = ctxt->context->contextSize;
13457
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13458
0
      CHECK_ERROR0;
13459
0
      ctxt->context->doc = bakd;
13460
0
      ctxt->context->node = bak;
13461
0
      ctxt->context->proximityPosition = pp;
13462
0
      ctxt->context->contextSize = cs;
13463
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13464
0
      CHECK_ERROR0;
13465
13466
0
            arg2 = valuePop(ctxt);
13467
0
            arg1 = valuePop(ctxt);
13468
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13469
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13470
0
          xmlXPathReleaseObject(ctxt->context, arg1);
13471
0
          xmlXPathReleaseObject(ctxt->context, arg2);
13472
0
                XP_ERROR0(XPATH_INVALID_TYPE);
13473
0
            }
13474
13475
0
      if ((arg1->nodesetval == NULL) ||
13476
0
    ((arg2->nodesetval != NULL) &&
13477
0
     (arg2->nodesetval->nodeNr != 0)))
13478
0
      {
13479
0
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13480
0
              arg2->nodesetval);
13481
0
      }
13482
13483
0
            valuePush(ctxt, arg1);
13484
0
      xmlXPathReleaseObject(ctxt->context, arg2);
13485
0
            return (total);
13486
0
        case XPATH_OP_ROOT:
13487
0
            xmlXPathRoot(ctxt);
13488
0
            return (total);
13489
0
        case XPATH_OP_NODE:
13490
0
            if (op->ch1 != -1)
13491
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13492
0
      CHECK_ERROR0;
13493
0
            if (op->ch2 != -1)
13494
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13495
0
      CHECK_ERROR0;
13496
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13497
0
    ctxt->context->node));
13498
0
            return (total);
13499
0
        case XPATH_OP_RESET:
13500
0
            if (op->ch1 != -1)
13501
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13502
0
      CHECK_ERROR0;
13503
0
            if (op->ch2 != -1)
13504
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13505
0
      CHECK_ERROR0;
13506
0
            ctxt->context->node = NULL;
13507
0
            return (total);
13508
0
        case XPATH_OP_COLLECT:{
13509
0
                if (op->ch1 == -1)
13510
0
                    return (total);
13511
13512
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13513
0
    CHECK_ERROR0;
13514
13515
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13516
0
                return (total);
13517
0
            }
13518
0
        case XPATH_OP_VALUE:
13519
0
            valuePush(ctxt,
13520
0
                      xmlXPathCacheObjectCopy(ctxt->context,
13521
0
      (xmlXPathObjectPtr) op->value4));
13522
0
            return (total);
13523
0
        case XPATH_OP_VARIABLE:{
13524
0
    xmlXPathObjectPtr val;
13525
13526
0
                if (op->ch1 != -1)
13527
0
                    total +=
13528
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13529
0
                if (op->value5 == NULL) {
13530
0
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
13531
0
        if (val == NULL)
13532
0
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13533
0
                    valuePush(ctxt, val);
13534
0
    } else {
13535
0
                    const xmlChar *URI;
13536
13537
0
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
13538
0
                    if (URI == NULL) {
13539
0
                        xmlGenericError(xmlGenericErrorContext,
13540
0
            "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13541
0
                                    (char *) op->value4, (char *)op->value5);
13542
0
                        ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13543
0
                        return (total);
13544
0
                    }
13545
0
        val = xmlXPathVariableLookupNS(ctxt->context,
13546
0
                                                       op->value4, URI);
13547
0
        if (val == NULL)
13548
0
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13549
0
                    valuePush(ctxt, val);
13550
0
                }
13551
0
                return (total);
13552
0
            }
13553
0
        case XPATH_OP_FUNCTION:{
13554
0
                xmlXPathFunction func;
13555
0
                const xmlChar *oldFunc, *oldFuncURI;
13556
0
    int i;
13557
0
                int frame;
13558
13559
0
                frame = xmlXPathSetFrame(ctxt);
13560
0
                if (op->ch1 != -1) {
13561
0
                    total +=
13562
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13563
0
                    if (ctxt->error != XPATH_EXPRESSION_OK) {
13564
0
                        xmlXPathPopFrame(ctxt, frame);
13565
0
                        return (total);
13566
0
                    }
13567
0
                }
13568
0
    if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13569
0
        xmlGenericError(xmlGenericErrorContext,
13570
0
          "xmlXPathCompOpEval: parameter error\n");
13571
0
        ctxt->error = XPATH_INVALID_OPERAND;
13572
0
                    xmlXPathPopFrame(ctxt, frame);
13573
0
        return (total);
13574
0
    }
13575
0
    for (i = 0; i < op->value; i++) {
13576
0
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13577
0
      xmlGenericError(xmlGenericErrorContext,
13578
0
        "xmlXPathCompOpEval: parameter error\n");
13579
0
      ctxt->error = XPATH_INVALID_OPERAND;
13580
0
                        xmlXPathPopFrame(ctxt, frame);
13581
0
      return (total);
13582
0
        }
13583
0
                }
13584
0
                if (op->cache != NULL)
13585
0
                    func = op->cache;
13586
0
                else {
13587
0
                    const xmlChar *URI = NULL;
13588
13589
0
                    if (op->value5 == NULL)
13590
0
                        func =
13591
0
                            xmlXPathFunctionLookup(ctxt->context,
13592
0
                                                   op->value4);
13593
0
                    else {
13594
0
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
13595
0
                        if (URI == NULL) {
13596
0
                            xmlGenericError(xmlGenericErrorContext,
13597
0
            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13598
0
                                    (char *)op->value4, (char *)op->value5);
13599
0
                            xmlXPathPopFrame(ctxt, frame);
13600
0
                            ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13601
0
                            return (total);
13602
0
                        }
13603
0
                        func = xmlXPathFunctionLookupNS(ctxt->context,
13604
0
                                                        op->value4, URI);
13605
0
                    }
13606
0
                    if (func == NULL) {
13607
0
                        xmlGenericError(xmlGenericErrorContext,
13608
0
                                "xmlXPathCompOpEval: function %s not found\n",
13609
0
                                        (char *)op->value4);
13610
0
                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13611
0
                    }
13612
0
                    op->cache = func;
13613
0
                    op->cacheURI = (void *) URI;
13614
0
                }
13615
0
                oldFunc = ctxt->context->function;
13616
0
                oldFuncURI = ctxt->context->functionURI;
13617
0
                ctxt->context->function = op->value4;
13618
0
                ctxt->context->functionURI = op->cacheURI;
13619
0
                func(ctxt, op->value);
13620
0
                ctxt->context->function = oldFunc;
13621
0
                ctxt->context->functionURI = oldFuncURI;
13622
0
                xmlXPathPopFrame(ctxt, frame);
13623
0
                return (total);
13624
0
            }
13625
0
        case XPATH_OP_ARG:
13626
0
      bakd = ctxt->context->doc;
13627
0
      bak = ctxt->context->node;
13628
0
      pp = ctxt->context->proximityPosition;
13629
0
      cs = ctxt->context->contextSize;
13630
0
            if (op->ch1 != -1) {
13631
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13632
0
                ctxt->context->contextSize = cs;
13633
0
                ctxt->context->proximityPosition = pp;
13634
0
                ctxt->context->node = bak;
13635
0
                ctxt->context->doc = bakd;
13636
0
          CHECK_ERROR0;
13637
0
            }
13638
0
            if (op->ch2 != -1) {
13639
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13640
0
                ctxt->context->contextSize = cs;
13641
0
                ctxt->context->proximityPosition = pp;
13642
0
                ctxt->context->node = bak;
13643
0
                ctxt->context->doc = bakd;
13644
0
          CHECK_ERROR0;
13645
0
      }
13646
0
            return (total);
13647
0
        case XPATH_OP_PREDICATE:
13648
0
        case XPATH_OP_FILTER:{
13649
0
                xmlXPathObjectPtr res;
13650
0
                xmlXPathObjectPtr obj, tmp;
13651
0
                xmlNodeSetPtr newset = NULL;
13652
0
                xmlNodeSetPtr oldset;
13653
0
                xmlNodePtr oldnode;
13654
0
    xmlDocPtr oldDoc;
13655
0
                int i;
13656
13657
                /*
13658
                 * Optimization for ()[1] selection i.e. the first elem
13659
                 */
13660
0
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13661
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
13662
        /*
13663
        * FILTER TODO: Can we assume that the inner processing
13664
        *  will result in an ordered list if we have an
13665
        *  XPATH_OP_FILTER?
13666
        *  What about an additional field or flag on
13667
        *  xmlXPathObject like @sorted ? This way we wouln'd need
13668
        *  to assume anything, so it would be more robust and
13669
        *  easier to optimize.
13670
        */
13671
0
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13672
0
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13673
#else
13674
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13675
#endif
13676
0
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13677
0
                    xmlXPathObjectPtr val;
13678
13679
0
                    val = comp->steps[op->ch2].value4;
13680
0
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13681
0
                        (val->floatval == 1.0)) {
13682
0
                        xmlNodePtr first = NULL;
13683
13684
0
                        total +=
13685
0
                            xmlXPathCompOpEvalFirst(ctxt,
13686
0
                                                    &comp->steps[op->ch1],
13687
0
                                                    &first);
13688
0
      CHECK_ERROR0;
13689
                        /*
13690
                         * The nodeset should be in document order,
13691
                         * Keep only the first value
13692
                         */
13693
0
                        if ((ctxt->value != NULL) &&
13694
0
                            (ctxt->value->type == XPATH_NODESET) &&
13695
0
                            (ctxt->value->nodesetval != NULL) &&
13696
0
                            (ctxt->value->nodesetval->nodeNr > 1))
13697
0
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13698
0
                                                        1, 1);
13699
0
                        return (total);
13700
0
                    }
13701
0
                }
13702
                /*
13703
                 * Optimization for ()[last()] selection i.e. the last elem
13704
                 */
13705
0
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13706
0
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13707
0
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13708
0
                    int f = comp->steps[op->ch2].ch1;
13709
13710
0
                    if ((f != -1) &&
13711
0
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13712
0
                        (comp->steps[f].value5 == NULL) &&
13713
0
                        (comp->steps[f].value == 0) &&
13714
0
                        (comp->steps[f].value4 != NULL) &&
13715
0
                        (xmlStrEqual
13716
0
                         (comp->steps[f].value4, BAD_CAST "last"))) {
13717
0
                        xmlNodePtr last = NULL;
13718
13719
0
                        total +=
13720
0
                            xmlXPathCompOpEvalLast(ctxt,
13721
0
                                                   &comp->steps[op->ch1],
13722
0
                                                   &last);
13723
0
      CHECK_ERROR0;
13724
                        /*
13725
                         * The nodeset should be in document order,
13726
                         * Keep only the last value
13727
                         */
13728
0
                        if ((ctxt->value != NULL) &&
13729
0
                            (ctxt->value->type == XPATH_NODESET) &&
13730
0
                            (ctxt->value->nodesetval != NULL) &&
13731
0
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
13732
0
                            (ctxt->value->nodesetval->nodeNr > 1))
13733
0
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13734
0
                        return (total);
13735
0
                    }
13736
0
                }
13737
    /*
13738
    * Process inner predicates first.
13739
    * Example "index[parent::book][1]":
13740
    * ...
13741
    *   PREDICATE   <-- we are here "[1]"
13742
    *     PREDICATE <-- process "[parent::book]" first
13743
    *       SORT
13744
    *         COLLECT  'parent' 'name' 'node' book
13745
    *           NODE
13746
    *     ELEM Object is a number : 1
13747
    */
13748
0
                if (op->ch1 != -1)
13749
0
                    total +=
13750
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13751
0
    CHECK_ERROR0;
13752
0
                if (op->ch2 == -1)
13753
0
                    return (total);
13754
0
                if (ctxt->value == NULL)
13755
0
                    return (total);
13756
13757
0
                oldnode = ctxt->context->node;
13758
13759
0
#ifdef LIBXML_XPTR_ENABLED
13760
                /*
13761
                 * Hum are we filtering the result of an XPointer expression
13762
                 */
13763
0
                if (ctxt->value->type == XPATH_LOCATIONSET) {
13764
0
                    xmlLocationSetPtr newlocset = NULL;
13765
0
                    xmlLocationSetPtr oldlocset;
13766
13767
                    /*
13768
                     * Extract the old locset, and then evaluate the result of the
13769
                     * expression for all the element in the locset. use it to grow
13770
                     * up a new locset.
13771
                     */
13772
0
                    CHECK_TYPE0(XPATH_LOCATIONSET);
13773
0
                    obj = valuePop(ctxt);
13774
0
                    oldlocset = obj->user;
13775
0
                    ctxt->context->node = NULL;
13776
13777
0
                    if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13778
0
                        ctxt->context->contextSize = 0;
13779
0
                        ctxt->context->proximityPosition = 0;
13780
0
                        if (op->ch2 != -1)
13781
0
                            total +=
13782
0
                                xmlXPathCompOpEval(ctxt,
13783
0
                                                   &comp->steps[op->ch2]);
13784
0
                        res = valuePop(ctxt);
13785
0
                        if (res != NULL) {
13786
0
          xmlXPathReleaseObject(ctxt->context, res);
13787
0
      }
13788
0
                        valuePush(ctxt, obj);
13789
0
                        CHECK_ERROR0;
13790
0
                        return (total);
13791
0
                    }
13792
0
                    newlocset = xmlXPtrLocationSetCreate(NULL);
13793
13794
0
                    for (i = 0; i < oldlocset->locNr; i++) {
13795
                        /*
13796
                         * Run the evaluation with a node list made of a
13797
                         * single item in the nodelocset.
13798
                         */
13799
0
                        ctxt->context->node = oldlocset->locTab[i]->user;
13800
0
                        ctxt->context->contextSize = oldlocset->locNr;
13801
0
                        ctxt->context->proximityPosition = i + 1;
13802
0
      tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13803
0
          ctxt->context->node);
13804
0
                        valuePush(ctxt, tmp);
13805
13806
0
                        if (op->ch2 != -1)
13807
0
                            total +=
13808
0
                                xmlXPathCompOpEval(ctxt,
13809
0
                                                   &comp->steps[op->ch2]);
13810
0
      if (ctxt->error != XPATH_EXPRESSION_OK) {
13811
0
          xmlXPathFreeObject(obj);
13812
0
          return(0);
13813
0
      }
13814
13815
                        /*
13816
                         * The result of the evaluation need to be tested to
13817
                         * decided whether the filter succeeded or not
13818
                         */
13819
0
                        res = valuePop(ctxt);
13820
0
                        if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13821
0
                            xmlXPtrLocationSetAdd(newlocset,
13822
0
                                                  xmlXPathObjectCopy
13823
0
                                                  (oldlocset->locTab[i]));
13824
0
                        }
13825
13826
                        /*
13827
                         * Cleanup
13828
                         */
13829
0
                        if (res != NULL) {
13830
0
          xmlXPathReleaseObject(ctxt->context, res);
13831
0
      }
13832
0
                        if (ctxt->value == tmp) {
13833
0
                            res = valuePop(ctxt);
13834
0
          xmlXPathReleaseObject(ctxt->context, res);
13835
0
                        }
13836
13837
0
                        ctxt->context->node = NULL;
13838
0
                    }
13839
13840
                    /*
13841
                     * The result is used as the new evaluation locset.
13842
                     */
13843
0
        xmlXPathReleaseObject(ctxt->context, obj);
13844
0
                    ctxt->context->node = NULL;
13845
0
                    ctxt->context->contextSize = -1;
13846
0
                    ctxt->context->proximityPosition = -1;
13847
0
                    valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13848
0
                    ctxt->context->node = oldnode;
13849
0
                    return (total);
13850
0
                }
13851
0
#endif /* LIBXML_XPTR_ENABLED */
13852
13853
                /*
13854
                 * Extract the old set, and then evaluate the result of the
13855
                 * expression for all the element in the set. use it to grow
13856
                 * up a new set.
13857
                 */
13858
0
                CHECK_TYPE0(XPATH_NODESET);
13859
0
                obj = valuePop(ctxt);
13860
0
                oldset = obj->nodesetval;
13861
13862
0
                oldnode = ctxt->context->node;
13863
0
    oldDoc = ctxt->context->doc;
13864
0
                ctxt->context->node = NULL;
13865
13866
0
                if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13867
0
                    ctxt->context->contextSize = 0;
13868
0
                    ctxt->context->proximityPosition = 0;
13869
/*
13870
                    if (op->ch2 != -1)
13871
                        total +=
13872
                            xmlXPathCompOpEval(ctxt,
13873
                                               &comp->steps[op->ch2]);
13874
        CHECK_ERROR0;
13875
                    res = valuePop(ctxt);
13876
                    if (res != NULL)
13877
                        xmlXPathFreeObject(res);
13878
*/
13879
0
                    valuePush(ctxt, obj);
13880
0
                    ctxt->context->node = oldnode;
13881
0
                    CHECK_ERROR0;
13882
0
                } else {
13883
0
        tmp = NULL;
13884
                    /*
13885
                     * Initialize the new set.
13886
         * Also set the xpath document in case things like
13887
         * key() evaluation are attempted on the predicate
13888
                     */
13889
0
                    newset = xmlXPathNodeSetCreate(NULL);
13890
        /*
13891
        * SPEC XPath 1.0:
13892
        *  "For each node in the node-set to be filtered, the
13893
        *  PredicateExpr is evaluated with that node as the
13894
        *  context node, with the number of nodes in the
13895
        *  node-set as the context size, and with the proximity
13896
        *  position of the node in the node-set with respect to
13897
        *  the axis as the context position;"
13898
        * @oldset is the node-set" to be filtered.
13899
        *
13900
        * SPEC XPath 1.0:
13901
        *  "only predicates change the context position and
13902
        *  context size (see [2.4 Predicates])."
13903
        * Example:
13904
        *   node-set  context pos
13905
        *    nA         1
13906
        *    nB         2
13907
        *    nC         3
13908
        *   After applying predicate [position() > 1] :
13909
        *   node-set  context pos
13910
        *    nB         1
13911
        *    nC         2
13912
        *
13913
        * removed the first node in the node-set, then
13914
        * the context position of the
13915
        */
13916
0
                    for (i = 0; i < oldset->nodeNr; i++) {
13917
                        /*
13918
                         * Run the evaluation with a node list made of
13919
                         * a single item in the nodeset.
13920
                         */
13921
0
                        ctxt->context->node = oldset->nodeTab[i];
13922
0
      if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13923
0
          (oldset->nodeTab[i]->doc != NULL))
13924
0
                ctxt->context->doc = oldset->nodeTab[i]->doc;
13925
0
      if (tmp == NULL) {
13926
0
          tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13927
0
        ctxt->context->node);
13928
0
      } else {
13929
0
          if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13930
0
                       ctxt->context->node) < 0) {
13931
0
        ctxt->error = XPATH_MEMORY_ERROR;
13932
0
          }
13933
0
      }
13934
0
                        valuePush(ctxt, tmp);
13935
0
                        ctxt->context->contextSize = oldset->nodeNr;
13936
0
                        ctxt->context->proximityPosition = i + 1;
13937
      /*
13938
      * Evaluate the predicate against the context node.
13939
      * Can/should we optimize position() predicates
13940
      * here (e.g. "[1]")?
13941
      */
13942
0
                        if (op->ch2 != -1)
13943
0
                            total +=
13944
0
                                xmlXPathCompOpEval(ctxt,
13945
0
                                                   &comp->steps[op->ch2]);
13946
0
      if (ctxt->error != XPATH_EXPRESSION_OK) {
13947
0
          xmlXPathFreeNodeSet(newset);
13948
0
          xmlXPathFreeObject(obj);
13949
0
          return(0);
13950
0
      }
13951
13952
                        /*
13953
                         * The result of the evaluation needs to be tested to
13954
                         * decide whether the filter succeeded or not
13955
                         */
13956
      /*
13957
      * OPTIMIZE TODO: Can we use
13958
      * xmlXPathNodeSetAdd*Unique()* instead?
13959
      */
13960
0
                        res = valuePop(ctxt);
13961
0
                        if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13962
0
                            if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
13963
0
              < 0)
13964
0
        ctxt->error = XPATH_MEMORY_ERROR;
13965
0
                        }
13966
13967
                        /*
13968
                         * Cleanup
13969
                         */
13970
0
                        if (res != NULL) {
13971
0
          xmlXPathReleaseObject(ctxt->context, res);
13972
0
      }
13973
0
                        if (ctxt->value == tmp) {
13974
0
                            valuePop(ctxt);
13975
0
          xmlXPathNodeSetClear(tmp->nodesetval, 1);
13976
          /*
13977
          * Don't free the temporary nodeset
13978
          * in order to avoid massive recreation inside this
13979
          * loop.
13980
          */
13981
0
                        } else
13982
0
          tmp = NULL;
13983
0
                        ctxt->context->node = NULL;
13984
0
                    }
13985
0
        if (tmp != NULL)
13986
0
      xmlXPathReleaseObject(ctxt->context, tmp);
13987
                    /*
13988
                     * The result is used as the new evaluation set.
13989
                     */
13990
0
        xmlXPathReleaseObject(ctxt->context, obj);
13991
0
                    ctxt->context->node = NULL;
13992
0
                    ctxt->context->contextSize = -1;
13993
0
                    ctxt->context->proximityPosition = -1;
13994
        /* may want to move this past the '}' later */
13995
0
        ctxt->context->doc = oldDoc;
13996
0
        valuePush(ctxt,
13997
0
      xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13998
0
                }
13999
0
                ctxt->context->node = oldnode;
14000
0
                return (total);
14001
0
            }
14002
0
        case XPATH_OP_SORT:
14003
0
            if (op->ch1 != -1)
14004
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
14005
0
      CHECK_ERROR0;
14006
0
            if ((ctxt->value != NULL) &&
14007
0
                (ctxt->value->type == XPATH_NODESET) &&
14008
0
                (ctxt->value->nodesetval != NULL) &&
14009
0
    (ctxt->value->nodesetval->nodeNr > 1))
14010
0
      {
14011
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
14012
0
      }
14013
0
            return (total);
14014
0
#ifdef LIBXML_XPTR_ENABLED
14015
0
        case XPATH_OP_RANGETO:{
14016
0
                xmlXPathObjectPtr range;
14017
0
                xmlXPathObjectPtr res, obj;
14018
0
                xmlXPathObjectPtr tmp;
14019
0
                xmlLocationSetPtr newlocset = NULL;
14020
0
        xmlLocationSetPtr oldlocset;
14021
0
                xmlNodeSetPtr oldset;
14022
0
                int i, j;
14023
14024
0
                if (op->ch1 != -1) {
14025
0
                    total +=
14026
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
14027
0
                    CHECK_ERROR0;
14028
0
                }
14029
0
                if (ctxt->value == NULL) {
14030
0
                    XP_ERROR0(XPATH_INVALID_OPERAND);
14031
0
                }
14032
0
                if (op->ch2 == -1)
14033
0
                    return (total);
14034
14035
0
                if (ctxt->value->type == XPATH_LOCATIONSET) {
14036
                    /*
14037
                     * Extract the old locset, and then evaluate the result of the
14038
                     * expression for all the element in the locset. use it to grow
14039
                     * up a new locset.
14040
                     */
14041
0
                    CHECK_TYPE0(XPATH_LOCATIONSET);
14042
0
                    obj = valuePop(ctxt);
14043
0
                    oldlocset = obj->user;
14044
14045
0
                    if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
14046
0
            ctxt->context->node = NULL;
14047
0
                        ctxt->context->contextSize = 0;
14048
0
                        ctxt->context->proximityPosition = 0;
14049
0
                        total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
14050
0
                        res = valuePop(ctxt);
14051
0
                        if (res != NULL) {
14052
0
          xmlXPathReleaseObject(ctxt->context, res);
14053
0
      }
14054
0
                        valuePush(ctxt, obj);
14055
0
                        CHECK_ERROR0;
14056
0
                        return (total);
14057
0
                    }
14058
0
                    newlocset = xmlXPtrLocationSetCreate(NULL);
14059
14060
0
                    for (i = 0; i < oldlocset->locNr; i++) {
14061
                        /*
14062
                         * Run the evaluation with a node list made of a
14063
                         * single item in the nodelocset.
14064
                         */
14065
0
                        ctxt->context->node = oldlocset->locTab[i]->user;
14066
0
                        ctxt->context->contextSize = oldlocset->locNr;
14067
0
                        ctxt->context->proximityPosition = i + 1;
14068
0
      tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14069
0
          ctxt->context->node);
14070
0
                        valuePush(ctxt, tmp);
14071
14072
0
                        if (op->ch2 != -1)
14073
0
                            total +=
14074
0
                                xmlXPathCompOpEval(ctxt,
14075
0
                                                   &comp->steps[op->ch2]);
14076
0
      if (ctxt->error != XPATH_EXPRESSION_OK) {
14077
0
          xmlXPathFreeObject(obj);
14078
0
          return(0);
14079
0
      }
14080
14081
0
                        res = valuePop(ctxt);
14082
0
      if (res->type == XPATH_LOCATIONSET) {
14083
0
          xmlLocationSetPtr rloc =
14084
0
              (xmlLocationSetPtr)res->user;
14085
0
          for (j=0; j<rloc->locNr; j++) {
14086
0
              range = xmlXPtrNewRange(
14087
0
          oldlocset->locTab[i]->user,
14088
0
          oldlocset->locTab[i]->index,
14089
0
          rloc->locTab[j]->user2,
14090
0
          rloc->locTab[j]->index2);
14091
0
        if (range != NULL) {
14092
0
            xmlXPtrLocationSetAdd(newlocset, range);
14093
0
        }
14094
0
          }
14095
0
      } else {
14096
0
          range = xmlXPtrNewRangeNodeObject(
14097
0
        (xmlNodePtr)oldlocset->locTab[i]->user, res);
14098
0
                            if (range != NULL) {
14099
0
                                xmlXPtrLocationSetAdd(newlocset,range);
14100
0
          }
14101
0
                        }
14102
14103
                        /*
14104
                         * Cleanup
14105
                         */
14106
0
                        if (res != NULL) {
14107
0
          xmlXPathReleaseObject(ctxt->context, res);
14108
0
      }
14109
0
                        if (ctxt->value == tmp) {
14110
0
                            res = valuePop(ctxt);
14111
0
          xmlXPathReleaseObject(ctxt->context, res);
14112
0
                        }
14113
14114
0
                        ctxt->context->node = NULL;
14115
0
                    }
14116
0
    } else { /* Not a location set */
14117
0
                    CHECK_TYPE0(XPATH_NODESET);
14118
0
                    obj = valuePop(ctxt);
14119
0
                    oldset = obj->nodesetval;
14120
0
                    ctxt->context->node = NULL;
14121
14122
0
                    newlocset = xmlXPtrLocationSetCreate(NULL);
14123
14124
0
                    if (oldset != NULL) {
14125
0
                        for (i = 0; i < oldset->nodeNr; i++) {
14126
                            /*
14127
                             * Run the evaluation with a node list made of a single item
14128
                             * in the nodeset.
14129
                             */
14130
0
                            ctxt->context->node = oldset->nodeTab[i];
14131
          /*
14132
          * OPTIMIZE TODO: Avoid recreation for every iteration.
14133
          */
14134
0
          tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14135
0
        ctxt->context->node);
14136
0
                            valuePush(ctxt, tmp);
14137
14138
0
                            if (op->ch2 != -1)
14139
0
                                total +=
14140
0
                                    xmlXPathCompOpEval(ctxt,
14141
0
                                                   &comp->steps[op->ch2]);
14142
0
          if (ctxt->error != XPATH_EXPRESSION_OK) {
14143
0
        xmlXPathFreeObject(obj);
14144
0
        return(0);
14145
0
          }
14146
14147
0
                            res = valuePop(ctxt);
14148
0
                            range =
14149
0
                                xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14150
0
                                                      res);
14151
0
                            if (range != NULL) {
14152
0
                                xmlXPtrLocationSetAdd(newlocset, range);
14153
0
                            }
14154
14155
                            /*
14156
                             * Cleanup
14157
                             */
14158
0
                            if (res != NULL) {
14159
0
        xmlXPathReleaseObject(ctxt->context, res);
14160
0
          }
14161
0
                            if (ctxt->value == tmp) {
14162
0
                                res = valuePop(ctxt);
14163
0
        xmlXPathReleaseObject(ctxt->context, res);
14164
0
                            }
14165
14166
0
                            ctxt->context->node = NULL;
14167
0
                        }
14168
0
                    }
14169
0
                }
14170
14171
                /*
14172
                 * The result is used as the new evaluation set.
14173
                 */
14174
0
    xmlXPathReleaseObject(ctxt->context, obj);
14175
0
                ctxt->context->node = NULL;
14176
0
                ctxt->context->contextSize = -1;
14177
0
                ctxt->context->proximityPosition = -1;
14178
0
                valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
14179
0
                return (total);
14180
0
            }
14181
0
#endif /* LIBXML_XPTR_ENABLED */
14182
0
    }
14183
0
    xmlGenericError(xmlGenericErrorContext,
14184
0
                    "XPath: unknown precompiled operation %d\n", op->op);
14185
0
    ctxt->error = XPATH_INVALID_OPERAND;
14186
0
    return (total);
14187
0
}
14188
14189
/**
14190
 * xmlXPathCompOpEvalToBoolean:
14191
 * @ctxt:  the XPath parser context
14192
 *
14193
 * Evaluates if the expression evaluates to true.
14194
 *
14195
 * Returns 1 if true, 0 if false and -1 on API or internal errors.
14196
 */
14197
static int
14198
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
14199
          xmlXPathStepOpPtr op,
14200
          int isPredicate)
14201
0
{
14202
0
    xmlXPathObjectPtr resObj = NULL;
14203
14204
0
start:
14205
    /* comp = ctxt->comp; */
14206
0
    switch (op->op) {
14207
0
        case XPATH_OP_END:
14208
0
            return (0);
14209
0
  case XPATH_OP_VALUE:
14210
0
      resObj = (xmlXPathObjectPtr) op->value4;
14211
0
      if (isPredicate)
14212
0
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14213
0
      return(xmlXPathCastToBoolean(resObj));
14214
0
  case XPATH_OP_SORT:
14215
      /*
14216
      * We don't need sorting for boolean results. Skip this one.
14217
      */
14218
0
            if (op->ch1 != -1) {
14219
0
    op = &ctxt->comp->steps[op->ch1];
14220
0
    goto start;
14221
0
      }
14222
0
      return(0);
14223
0
  case XPATH_OP_COLLECT:
14224
0
      if (op->ch1 == -1)
14225
0
    return(0);
14226
14227
0
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14228
0
      if (ctxt->error != XPATH_EXPRESSION_OK)
14229
0
    return(-1);
14230
14231
0
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14232
0
      if (ctxt->error != XPATH_EXPRESSION_OK)
14233
0
    return(-1);
14234
14235
0
      resObj = valuePop(ctxt);
14236
0
      if (resObj == NULL)
14237
0
    return(-1);
14238
0
      break;
14239
0
  default:
14240
      /*
14241
      * Fallback to call xmlXPathCompOpEval().
14242
      */
14243
0
      xmlXPathCompOpEval(ctxt, op);
14244
0
      if (ctxt->error != XPATH_EXPRESSION_OK)
14245
0
    return(-1);
14246
14247
0
      resObj = valuePop(ctxt);
14248
0
      if (resObj == NULL)
14249
0
    return(-1);
14250
0
      break;
14251
0
    }
14252
14253
0
    if (resObj) {
14254
0
  int res;
14255
14256
0
  if (resObj->type == XPATH_BOOLEAN) {
14257
0
      res = resObj->boolval;
14258
0
  } else if (isPredicate) {
14259
      /*
14260
      * For predicates a result of type "number" is handled
14261
      * differently:
14262
      * SPEC XPath 1.0:
14263
      * "If the result is a number, the result will be converted
14264
      *  to true if the number is equal to the context position
14265
      *  and will be converted to false otherwise;"
14266
      */
14267
0
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14268
0
  } else {
14269
0
      res = xmlXPathCastToBoolean(resObj);
14270
0
  }
14271
0
  xmlXPathReleaseObject(ctxt->context, resObj);
14272
0
  return(res);
14273
0
    }
14274
14275
0
    return(0);
14276
0
}
14277
14278
#ifdef XPATH_STREAMING
14279
/**
14280
 * xmlXPathRunStreamEval:
14281
 * @ctxt:  the XPath parser context with the compiled expression
14282
 *
14283
 * Evaluate the Precompiled Streamable XPath expression in the given context.
14284
 */
14285
static int
14286
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14287
          xmlXPathObjectPtr *resultSeq, int toBool)
14288
0
{
14289
0
    int max_depth, min_depth;
14290
0
    int from_root;
14291
0
    int ret, depth;
14292
0
    int eval_all_nodes;
14293
0
    xmlNodePtr cur = NULL, limit = NULL;
14294
0
    xmlStreamCtxtPtr patstream = NULL;
14295
14296
0
    int nb_nodes = 0;
14297
14298
0
    if ((ctxt == NULL) || (comp == NULL))
14299
0
        return(-1);
14300
0
    max_depth = xmlPatternMaxDepth(comp);
14301
0
    if (max_depth == -1)
14302
0
        return(-1);
14303
0
    if (max_depth == -2)
14304
0
        max_depth = 10000;
14305
0
    min_depth = xmlPatternMinDepth(comp);
14306
0
    if (min_depth == -1)
14307
0
        return(-1);
14308
0
    from_root = xmlPatternFromRoot(comp);
14309
0
    if (from_root < 0)
14310
0
        return(-1);
14311
#if 0
14312
    printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14313
#endif
14314
14315
0
    if (! toBool) {
14316
0
  if (resultSeq == NULL)
14317
0
      return(-1);
14318
0
  *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14319
0
  if (*resultSeq == NULL)
14320
0
      return(-1);
14321
0
    }
14322
14323
    /*
14324
     * handle the special cases of "/" amd "." being matched
14325
     */
14326
0
    if (min_depth == 0) {
14327
0
  if (from_root) {
14328
      /* Select "/" */
14329
0
      if (toBool)
14330
0
    return(1);
14331
0
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14332
0
                         (xmlNodePtr) ctxt->doc);
14333
0
  } else {
14334
      /* Select "self::node()" */
14335
0
      if (toBool)
14336
0
    return(1);
14337
0
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14338
0
  }
14339
0
    }
14340
0
    if (max_depth == 0) {
14341
0
  return(0);
14342
0
    }
14343
14344
0
    if (from_root) {
14345
0
        cur = (xmlNodePtr)ctxt->doc;
14346
0
    } else if (ctxt->node != NULL) {
14347
0
        switch (ctxt->node->type) {
14348
0
            case XML_ELEMENT_NODE:
14349
0
            case XML_DOCUMENT_NODE:
14350
0
            case XML_DOCUMENT_FRAG_NODE:
14351
0
            case XML_HTML_DOCUMENT_NODE:
14352
0
#ifdef LIBXML_DOCB_ENABLED
14353
0
            case XML_DOCB_DOCUMENT_NODE:
14354
0
#endif
14355
0
          cur = ctxt->node;
14356
0
    break;
14357
0
            case XML_ATTRIBUTE_NODE:
14358
0
            case XML_TEXT_NODE:
14359
0
            case XML_CDATA_SECTION_NODE:
14360
0
            case XML_ENTITY_REF_NODE:
14361
0
            case XML_ENTITY_NODE:
14362
0
            case XML_PI_NODE:
14363
0
            case XML_COMMENT_NODE:
14364
0
            case XML_NOTATION_NODE:
14365
0
            case XML_DTD_NODE:
14366
0
            case XML_DOCUMENT_TYPE_NODE:
14367
0
            case XML_ELEMENT_DECL:
14368
0
            case XML_ATTRIBUTE_DECL:
14369
0
            case XML_ENTITY_DECL:
14370
0
            case XML_NAMESPACE_DECL:
14371
0
            case XML_XINCLUDE_START:
14372
0
            case XML_XINCLUDE_END:
14373
0
    break;
14374
0
  }
14375
0
  limit = cur;
14376
0
    }
14377
0
    if (cur == NULL) {
14378
0
        return(0);
14379
0
    }
14380
14381
0
    patstream = xmlPatternGetStreamCtxt(comp);
14382
0
    if (patstream == NULL) {
14383
  /*
14384
  * QUESTION TODO: Is this an error?
14385
  */
14386
0
  return(0);
14387
0
    }
14388
14389
0
    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14390
14391
0
    if (from_root) {
14392
0
  ret = xmlStreamPush(patstream, NULL, NULL);
14393
0
  if (ret < 0) {
14394
0
  } else if (ret == 1) {
14395
0
      if (toBool)
14396
0
    goto return_1;
14397
0
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14398
0
  }
14399
0
    }
14400
0
    depth = 0;
14401
0
    goto scan_children;
14402
0
next_node:
14403
0
    do {
14404
0
        nb_nodes++;
14405
14406
0
  switch (cur->type) {
14407
0
      case XML_ELEMENT_NODE:
14408
0
      case XML_TEXT_NODE:
14409
0
      case XML_CDATA_SECTION_NODE:
14410
0
      case XML_COMMENT_NODE:
14411
0
      case XML_PI_NODE:
14412
0
    if (cur->type == XML_ELEMENT_NODE) {
14413
0
        ret = xmlStreamPush(patstream, cur->name,
14414
0
        (cur->ns ? cur->ns->href : NULL));
14415
0
    } else if (eval_all_nodes)
14416
0
        ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14417
0
    else
14418
0
        break;
14419
14420
0
    if (ret < 0) {
14421
        /* NOP. */
14422
0
    } else if (ret == 1) {
14423
0
        if (toBool)
14424
0
      goto return_1;
14425
0
        if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
14426
0
            < 0) {
14427
0
      ctxt->lastError.domain = XML_FROM_XPATH;
14428
0
      ctxt->lastError.code = XML_ERR_NO_MEMORY;
14429
0
        }
14430
0
    }
14431
0
    if ((cur->children == NULL) || (depth >= max_depth)) {
14432
0
        ret = xmlStreamPop(patstream);
14433
0
        while (cur->next != NULL) {
14434
0
      cur = cur->next;
14435
0
      if ((cur->type != XML_ENTITY_DECL) &&
14436
0
          (cur->type != XML_DTD_NODE))
14437
0
          goto next_node;
14438
0
        }
14439
0
    }
14440
0
      default:
14441
0
    break;
14442
0
  }
14443
14444
0
scan_children:
14445
0
  if (cur->type == XML_NAMESPACE_DECL) break;
14446
0
  if ((cur->children != NULL) && (depth < max_depth)) {
14447
      /*
14448
       * Do not descend on entities declarations
14449
       */
14450
0
      if (cur->children->type != XML_ENTITY_DECL) {
14451
0
    cur = cur->children;
14452
0
    depth++;
14453
    /*
14454
     * Skip DTDs
14455
     */
14456
0
    if (cur->type != XML_DTD_NODE)
14457
0
        continue;
14458
0
      }
14459
0
  }
14460
14461
0
  if (cur == limit)
14462
0
      break;
14463
14464
0
  while (cur->next != NULL) {
14465
0
      cur = cur->next;
14466
0
      if ((cur->type != XML_ENTITY_DECL) &&
14467
0
    (cur->type != XML_DTD_NODE))
14468
0
    goto next_node;
14469
0
  }
14470
14471
0
  do {
14472
0
      cur = cur->parent;
14473
0
      depth--;
14474
0
      if ((cur == NULL) || (cur == limit))
14475
0
          goto done;
14476
0
      if (cur->type == XML_ELEMENT_NODE) {
14477
0
    ret = xmlStreamPop(patstream);
14478
0
      } else if ((eval_all_nodes) &&
14479
0
    ((cur->type == XML_TEXT_NODE) ||
14480
0
     (cur->type == XML_CDATA_SECTION_NODE) ||
14481
0
     (cur->type == XML_COMMENT_NODE) ||
14482
0
     (cur->type == XML_PI_NODE)))
14483
0
      {
14484
0
    ret = xmlStreamPop(patstream);
14485
0
      }
14486
0
      if (cur->next != NULL) {
14487
0
    cur = cur->next;
14488
0
    break;
14489
0
      }
14490
0
  } while (cur != NULL);
14491
14492
0
    } while ((cur != NULL) && (depth >= 0));
14493
14494
0
done:
14495
14496
#if 0
14497
    printf("stream eval: checked %d nodes selected %d\n",
14498
           nb_nodes, retObj->nodesetval->nodeNr);
14499
#endif
14500
14501
0
    if (patstream)
14502
0
  xmlFreeStreamCtxt(patstream);
14503
0
    return(0);
14504
14505
0
return_1:
14506
0
    if (patstream)
14507
0
  xmlFreeStreamCtxt(patstream);
14508
0
    return(1);
14509
0
}
14510
#endif /* XPATH_STREAMING */
14511
14512
/**
14513
 * xmlXPathRunEval:
14514
 * @ctxt:  the XPath parser context with the compiled expression
14515
 * @toBool:  evaluate to a boolean result
14516
 *
14517
 * Evaluate the Precompiled XPath expression in the given context.
14518
 */
14519
static int
14520
xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14521
0
{
14522
0
    xmlXPathCompExprPtr comp;
14523
14524
0
    if ((ctxt == NULL) || (ctxt->comp == NULL))
14525
0
  return(-1);
14526
14527
0
    if (ctxt->valueTab == NULL) {
14528
  /* Allocate the value stack */
14529
0
  ctxt->valueTab = (xmlXPathObjectPtr *)
14530
0
       xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14531
0
  if (ctxt->valueTab == NULL) {
14532
0
      xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14533
0
      xmlFree(ctxt);
14534
0
  }
14535
0
  ctxt->valueNr = 0;
14536
0
  ctxt->valueMax = 10;
14537
0
  ctxt->value = NULL;
14538
0
        ctxt->valueFrame = 0;
14539
0
    }
14540
0
#ifdef XPATH_STREAMING
14541
0
    if (ctxt->comp->stream) {
14542
0
  int res;
14543
14544
0
  if (toBool) {
14545
      /*
14546
      * Evaluation to boolean result.
14547
      */
14548
0
      res = xmlXPathRunStreamEval(ctxt->context,
14549
0
    ctxt->comp->stream, NULL, 1);
14550
0
      if (res != -1)
14551
0
    return(res);
14552
0
  } else {
14553
0
      xmlXPathObjectPtr resObj = NULL;
14554
14555
      /*
14556
      * Evaluation to a sequence.
14557
      */
14558
0
      res = xmlXPathRunStreamEval(ctxt->context,
14559
0
    ctxt->comp->stream, &resObj, 0);
14560
14561
0
      if ((res != -1) && (resObj != NULL)) {
14562
0
    valuePush(ctxt, resObj);
14563
0
    return(0);
14564
0
      }
14565
0
      if (resObj != NULL)
14566
0
    xmlXPathReleaseObject(ctxt->context, resObj);
14567
0
  }
14568
  /*
14569
  * QUESTION TODO: This falls back to normal XPath evaluation
14570
  * if res == -1. Is this intended?
14571
  */
14572
0
    }
14573
0
#endif
14574
0
    comp = ctxt->comp;
14575
0
    if (comp->last < 0) {
14576
0
  xmlGenericError(xmlGenericErrorContext,
14577
0
      "xmlXPathRunEval: last is less than zero\n");
14578
0
  return(-1);
14579
0
    }
14580
0
    if (toBool)
14581
0
  return(xmlXPathCompOpEvalToBoolean(ctxt,
14582
0
      &comp->steps[comp->last], 0));
14583
0
    else
14584
0
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14585
14586
0
    return(0);
14587
0
}
14588
14589
/************************************************************************
14590
 *                  *
14591
 *      Public interfaces       *
14592
 *                  *
14593
 ************************************************************************/
14594
14595
/**
14596
 * xmlXPathEvalPredicate:
14597
 * @ctxt:  the XPath context
14598
 * @res:  the Predicate Expression evaluation result
14599
 *
14600
 * Evaluate a predicate result for the current node.
14601
 * A PredicateExpr is evaluated by evaluating the Expr and converting
14602
 * the result to a boolean. If the result is a number, the result will
14603
 * be converted to true if the number is equal to the position of the
14604
 * context node in the context node list (as returned by the position
14605
 * function) and will be converted to false otherwise; if the result
14606
 * is not a number, then the result will be converted as if by a call
14607
 * to the boolean function.
14608
 *
14609
 * Returns 1 if predicate is true, 0 otherwise
14610
 */
14611
int
14612
0
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14613
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
14614
0
    switch (res->type) {
14615
0
        case XPATH_BOOLEAN:
14616
0
      return(res->boolval);
14617
0
        case XPATH_NUMBER:
14618
0
      return(res->floatval == ctxt->proximityPosition);
14619
0
        case XPATH_NODESET:
14620
0
        case XPATH_XSLT_TREE:
14621
0
      if (res->nodesetval == NULL)
14622
0
    return(0);
14623
0
      return(res->nodesetval->nodeNr != 0);
14624
0
        case XPATH_STRING:
14625
0
      return((res->stringval != NULL) &&
14626
0
             (xmlStrlen(res->stringval) != 0));
14627
0
        default:
14628
0
      STRANGE
14629
0
    }
14630
0
    return(0);
14631
0
}
14632
14633
/**
14634
 * xmlXPathEvaluatePredicateResult:
14635
 * @ctxt:  the XPath Parser context
14636
 * @res:  the Predicate Expression evaluation result
14637
 *
14638
 * Evaluate a predicate result for the current node.
14639
 * A PredicateExpr is evaluated by evaluating the Expr and converting
14640
 * the result to a boolean. If the result is a number, the result will
14641
 * be converted to true if the number is equal to the position of the
14642
 * context node in the context node list (as returned by the position
14643
 * function) and will be converted to false otherwise; if the result
14644
 * is not a number, then the result will be converted as if by a call
14645
 * to the boolean function.
14646
 *
14647
 * Returns 1 if predicate is true, 0 otherwise
14648
 */
14649
int
14650
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14651
0
                                xmlXPathObjectPtr res) {
14652
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
14653
0
    switch (res->type) {
14654
0
        case XPATH_BOOLEAN:
14655
0
      return(res->boolval);
14656
0
        case XPATH_NUMBER:
14657
#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14658
      return((res->floatval == ctxt->context->proximityPosition) &&
14659
             (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14660
#else
14661
0
      return(res->floatval == ctxt->context->proximityPosition);
14662
0
#endif
14663
0
        case XPATH_NODESET:
14664
0
        case XPATH_XSLT_TREE:
14665
0
      if (res->nodesetval == NULL)
14666
0
    return(0);
14667
0
      return(res->nodesetval->nodeNr != 0);
14668
0
        case XPATH_STRING:
14669
0
      return((res->stringval != NULL) && (res->stringval[0] != 0));
14670
0
#ifdef LIBXML_XPTR_ENABLED
14671
0
  case XPATH_LOCATIONSET:{
14672
0
      xmlLocationSetPtr ptr = res->user;
14673
0
      if (ptr == NULL)
14674
0
          return(0);
14675
0
      return (ptr->locNr != 0);
14676
0
      }
14677
0
#endif
14678
0
        default:
14679
0
      STRANGE
14680
0
    }
14681
0
    return(0);
14682
0
}
14683
14684
#ifdef XPATH_STREAMING
14685
/**
14686
 * xmlXPathTryStreamCompile:
14687
 * @ctxt: an XPath context
14688
 * @str:  the XPath expression
14689
 *
14690
 * Try to compile the XPath expression as a streamable subset.
14691
 *
14692
 * Returns the compiled expression or NULL if failed to compile.
14693
 */
14694
static xmlXPathCompExprPtr
14695
0
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14696
    /*
14697
     * Optimization: use streaming patterns when the XPath expression can
14698
     * be compiled to a stream lookup
14699
     */
14700
0
    xmlPatternPtr stream;
14701
0
    xmlXPathCompExprPtr comp;
14702
0
    xmlDictPtr dict = NULL;
14703
0
    const xmlChar **namespaces = NULL;
14704
0
    xmlNsPtr ns;
14705
0
    int i, j;
14706
14707
0
    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14708
0
        (!xmlStrchr(str, '@'))) {
14709
0
  const xmlChar *tmp;
14710
14711
  /*
14712
   * We don't try to handle expressions using the verbose axis
14713
   * specifiers ("::"), just the simplied form at this point.
14714
   * Additionally, if there is no list of namespaces available and
14715
   *  there's a ":" in the expression, indicating a prefixed QName,
14716
   *  then we won't try to compile either. xmlPatterncompile() needs
14717
   *  to have a list of namespaces at compilation time in order to
14718
   *  compile prefixed name tests.
14719
   */
14720
0
  tmp = xmlStrchr(str, ':');
14721
0
  if ((tmp != NULL) &&
14722
0
      ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14723
0
      return(NULL);
14724
14725
0
  if (ctxt != NULL) {
14726
0
      dict = ctxt->dict;
14727
0
      if (ctxt->nsNr > 0) {
14728
0
    namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14729
0
    if (namespaces == NULL) {
14730
0
        xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14731
0
        return(NULL);
14732
0
    }
14733
0
    for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14734
0
        ns = ctxt->namespaces[j];
14735
0
        namespaces[i++] = ns->href;
14736
0
        namespaces[i++] = ns->prefix;
14737
0
    }
14738
0
    namespaces[i++] = NULL;
14739
0
    namespaces[i] = NULL;
14740
0
      }
14741
0
  }
14742
14743
0
  stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14744
0
      &namespaces[0]);
14745
0
  if (namespaces != NULL) {
14746
0
      xmlFree((xmlChar **)namespaces);
14747
0
  }
14748
0
  if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14749
0
      comp = xmlXPathNewCompExpr();
14750
0
      if (comp == NULL) {
14751
0
    xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14752
0
    return(NULL);
14753
0
      }
14754
0
      comp->stream = stream;
14755
0
      comp->dict = dict;
14756
0
      if (comp->dict)
14757
0
    xmlDictReference(comp->dict);
14758
0
      return(comp);
14759
0
  }
14760
0
  xmlFreePattern(stream);
14761
0
    }
14762
0
    return(NULL);
14763
0
}
14764
#endif /* XPATH_STREAMING */
14765
14766
static void
14767
xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14768
0
{
14769
    /*
14770
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14771
    * internal representation.
14772
    */
14773
14774
0
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14775
0
        (op->ch1 != -1) &&
14776
0
        (op->ch2 == -1 /* no predicate */))
14777
0
    {
14778
0
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14779
14780
0
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14781
0
            ((xmlXPathAxisVal) prevop->value ==
14782
0
                AXIS_DESCENDANT_OR_SELF) &&
14783
0
            (prevop->ch2 == -1) &&
14784
0
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14785
0
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14786
0
        {
14787
            /*
14788
            * This is a "descendant-or-self::node()" without predicates.
14789
            * Try to eliminate it.
14790
            */
14791
14792
0
            switch ((xmlXPathAxisVal) op->value) {
14793
0
                case AXIS_CHILD:
14794
0
                case AXIS_DESCENDANT:
14795
                    /*
14796
                    * Convert "descendant-or-self::node()/child::" or
14797
                    * "descendant-or-self::node()/descendant::" to
14798
                    * "descendant::"
14799
                    */
14800
0
                    op->ch1   = prevop->ch1;
14801
0
                    op->value = AXIS_DESCENDANT;
14802
0
                    break;
14803
0
                case AXIS_SELF:
14804
0
                case AXIS_DESCENDANT_OR_SELF:
14805
                    /*
14806
                    * Convert "descendant-or-self::node()/self::" or
14807
                    * "descendant-or-self::node()/descendant-or-self::" to
14808
                    * to "descendant-or-self::"
14809
                    */
14810
0
                    op->ch1   = prevop->ch1;
14811
0
                    op->value = AXIS_DESCENDANT_OR_SELF;
14812
0
                    break;
14813
0
                default:
14814
0
                    break;
14815
0
            }
14816
0
  }
14817
0
    }
14818
14819
    /* OP_VALUE has invalid ch1. */
14820
0
    if (op->op == XPATH_OP_VALUE)
14821
0
        return;
14822
14823
    /* Recurse */
14824
0
    if (op->ch1 != -1)
14825
0
        xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
14826
0
    if (op->ch2 != -1)
14827
0
  xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
14828
0
}
14829
14830
/**
14831
 * xmlXPathCtxtCompile:
14832
 * @ctxt: an XPath context
14833
 * @str:  the XPath expression
14834
 *
14835
 * Compile an XPath expression
14836
 *
14837
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14838
 *         the caller has to free the object.
14839
 */
14840
xmlXPathCompExprPtr
14841
0
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14842
0
    xmlXPathParserContextPtr pctxt;
14843
0
    xmlXPathCompExprPtr comp;
14844
14845
0
#ifdef XPATH_STREAMING
14846
0
    comp = xmlXPathTryStreamCompile(ctxt, str);
14847
0
    if (comp != NULL)
14848
0
        return(comp);
14849
0
#endif
14850
14851
0
    xmlXPathInit();
14852
14853
0
    pctxt = xmlXPathNewParserContext(str, ctxt);
14854
0
    if (pctxt == NULL)
14855
0
        return NULL;
14856
0
    xmlXPathCompileExpr(pctxt, 1);
14857
14858
0
    if( pctxt->error != XPATH_EXPRESSION_OK )
14859
0
    {
14860
0
        xmlXPathFreeParserContext(pctxt);
14861
0
        return(NULL);
14862
0
    }
14863
14864
0
    if (*pctxt->cur != 0) {
14865
  /*
14866
   * aleksey: in some cases this line prints *second* error message
14867
   * (see bug #78858) and probably this should be fixed.
14868
   * However, we are not sure that all error messages are printed
14869
   * out in other places. It's not critical so we leave it as-is for now
14870
   */
14871
0
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14872
0
  comp = NULL;
14873
0
    } else {
14874
0
  comp = pctxt->comp;
14875
0
  pctxt->comp = NULL;
14876
0
    }
14877
0
    xmlXPathFreeParserContext(pctxt);
14878
14879
0
    if (comp != NULL) {
14880
0
  comp->expr = xmlStrdup(str);
14881
#ifdef DEBUG_EVAL_COUNTS
14882
  comp->string = xmlStrdup(str);
14883
  comp->nb = 0;
14884
#endif
14885
0
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
14886
0
      xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
14887
0
  }
14888
0
    }
14889
0
    return(comp);
14890
0
}
14891
14892
/**
14893
 * xmlXPathCompile:
14894
 * @str:  the XPath expression
14895
 *
14896
 * Compile an XPath expression
14897
 *
14898
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14899
 *         the caller has to free the object.
14900
 */
14901
xmlXPathCompExprPtr
14902
0
xmlXPathCompile(const xmlChar *str) {
14903
0
    return(xmlXPathCtxtCompile(NULL, str));
14904
0
}
14905
14906
/**
14907
 * xmlXPathCompiledEvalInternal:
14908
 * @comp:  the compiled XPath expression
14909
 * @ctxt:  the XPath context
14910
 * @resObj: the resulting XPath object or NULL
14911
 * @toBool: 1 if only a boolean result is requested
14912
 *
14913
 * Evaluate the Precompiled XPath expression in the given context.
14914
 * The caller has to free @resObj.
14915
 *
14916
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14917
 *         the caller has to free the object.
14918
 */
14919
static int
14920
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14921
           xmlXPathContextPtr ctxt,
14922
           xmlXPathObjectPtr *resObjPtr,
14923
           int toBool)
14924
0
{
14925
0
    xmlXPathParserContextPtr pctxt;
14926
0
    xmlXPathObjectPtr resObj;
14927
#ifndef LIBXML_THREAD_ENABLED
14928
    static int reentance = 0;
14929
#endif
14930
0
    int res;
14931
14932
0
    CHECK_CTXT_NEG(ctxt)
14933
14934
0
    if (comp == NULL)
14935
0
  return(-1);
14936
0
    xmlXPathInit();
14937
14938
#ifndef LIBXML_THREAD_ENABLED
14939
    reentance++;
14940
    if (reentance > 1)
14941
  xmlXPathDisableOptimizer = 1;
14942
#endif
14943
14944
#ifdef DEBUG_EVAL_COUNTS
14945
    comp->nb++;
14946
    if ((comp->string != NULL) && (comp->nb > 100)) {
14947
  fprintf(stderr, "100 x %s\n", comp->string);
14948
  comp->nb = 0;
14949
    }
14950
#endif
14951
0
    pctxt = xmlXPathCompParserContext(comp, ctxt);
14952
0
    res = xmlXPathRunEval(pctxt, toBool);
14953
14954
0
    if (pctxt->error != XPATH_EXPRESSION_OK) {
14955
0
        resObj = NULL;
14956
0
    } else {
14957
0
        resObj = valuePop(pctxt);
14958
0
        if (resObj == NULL) {
14959
0
            if (!toBool)
14960
0
                xmlGenericError(xmlGenericErrorContext,
14961
0
                    "xmlXPathCompiledEval: No result on the stack.\n");
14962
0
        } else if (pctxt->valueNr > 0) {
14963
0
            xmlGenericError(xmlGenericErrorContext,
14964
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14965
0
                pctxt->valueNr);
14966
0
        }
14967
0
    }
14968
14969
0
    if (resObjPtr)
14970
0
        *resObjPtr = resObj;
14971
0
    else
14972
0
        xmlXPathReleaseObject(ctxt, resObj);
14973
14974
0
    pctxt->comp = NULL;
14975
0
    xmlXPathFreeParserContext(pctxt);
14976
#ifndef LIBXML_THREAD_ENABLED
14977
    reentance--;
14978
#endif
14979
14980
0
    return(res);
14981
0
}
14982
14983
/**
14984
 * xmlXPathCompiledEval:
14985
 * @comp:  the compiled XPath expression
14986
 * @ctx:  the XPath context
14987
 *
14988
 * Evaluate the Precompiled XPath expression in the given context.
14989
 *
14990
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14991
 *         the caller has to free the object.
14992
 */
14993
xmlXPathObjectPtr
14994
xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14995
0
{
14996
0
    xmlXPathObjectPtr res = NULL;
14997
14998
0
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14999
0
    return(res);
15000
0
}
15001
15002
/**
15003
 * xmlXPathCompiledEvalToBoolean:
15004
 * @comp:  the compiled XPath expression
15005
 * @ctxt:  the XPath context
15006
 *
15007
 * Applies the XPath boolean() function on the result of the given
15008
 * compiled expression.
15009
 *
15010
 * Returns 1 if the expression evaluated to true, 0 if to false and
15011
 *         -1 in API and internal errors.
15012
 */
15013
int
15014
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
15015
            xmlXPathContextPtr ctxt)
15016
0
{
15017
0
    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
15018
0
}
15019
15020
/**
15021
 * xmlXPathEvalExpr:
15022
 * @ctxt:  the XPath Parser context
15023
 *
15024
 * Parse and evaluate an XPath expression in the given context,
15025
 * then push the result on the context stack
15026
 */
15027
void
15028
0
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
15029
0
#ifdef XPATH_STREAMING
15030
0
    xmlXPathCompExprPtr comp;
15031
0
#endif
15032
15033
0
    if (ctxt == NULL) return;
15034
15035
0
#ifdef XPATH_STREAMING
15036
0
    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
15037
0
    if (comp != NULL) {
15038
0
        if (ctxt->comp != NULL)
15039
0
      xmlXPathFreeCompExpr(ctxt->comp);
15040
0
        ctxt->comp = comp;
15041
0
    } else
15042
0
#endif
15043
0
    {
15044
0
  xmlXPathCompileExpr(ctxt, 1);
15045
0
        CHECK_ERROR;
15046
15047
        /* Check for trailing characters. */
15048
0
        if (*ctxt->cur != 0)
15049
0
            XP_ERROR(XPATH_EXPR_ERROR);
15050
15051
0
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0))
15052
0
      xmlXPathOptimizeExpression(ctxt->comp,
15053
0
    &ctxt->comp->steps[ctxt->comp->last]);
15054
0
    }
15055
15056
0
    xmlXPathRunEval(ctxt, 0);
15057
0
}
15058
15059
/**
15060
 * xmlXPathEval:
15061
 * @str:  the XPath expression
15062
 * @ctx:  the XPath context
15063
 *
15064
 * Evaluate the XPath Location Path in the given context.
15065
 *
15066
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15067
 *         the caller has to free the object.
15068
 */
15069
xmlXPathObjectPtr
15070
0
xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
15071
0
    xmlXPathParserContextPtr ctxt;
15072
0
    xmlXPathObjectPtr res;
15073
15074
0
    CHECK_CTXT(ctx)
15075
15076
0
    xmlXPathInit();
15077
15078
0
    ctxt = xmlXPathNewParserContext(str, ctx);
15079
0
    if (ctxt == NULL)
15080
0
        return NULL;
15081
0
    xmlXPathEvalExpr(ctxt);
15082
15083
0
    if (ctxt->error != XPATH_EXPRESSION_OK) {
15084
0
  res = NULL;
15085
0
    } else {
15086
0
  res = valuePop(ctxt);
15087
0
        if (res == NULL) {
15088
0
            xmlGenericError(xmlGenericErrorContext,
15089
0
                "xmlXPathCompiledEval: No result on the stack.\n");
15090
0
        } else if (ctxt->valueNr > 0) {
15091
0
            xmlGenericError(xmlGenericErrorContext,
15092
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
15093
0
                ctxt->valueNr);
15094
0
        }
15095
0
    }
15096
15097
0
    xmlXPathFreeParserContext(ctxt);
15098
0
    return(res);
15099
0
}
15100
15101
/**
15102
 * xmlXPathSetContextNode:
15103
 * @node: the node to to use as the context node
15104
 * @ctx:  the XPath context
15105
 *
15106
 * Sets 'node' as the context node. The node must be in the same
15107
 * document as that associated with the context.
15108
 *
15109
 * Returns -1 in case of error or 0 if successful
15110
 */
15111
int
15112
0
xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
15113
0
    if ((node == NULL) || (ctx == NULL))
15114
0
        return(-1);
15115
15116
0
    if (node->doc == ctx->doc) {
15117
0
        ctx->node = node;
15118
0
  return(0);
15119
0
    }
15120
0
    return(-1);
15121
0
}
15122
15123
/**
15124
 * xmlXPathNodeEval:
15125
 * @node: the node to to use as the context node
15126
 * @str:  the XPath expression
15127
 * @ctx:  the XPath context
15128
 *
15129
 * Evaluate the XPath Location Path in the given context. The node 'node'
15130
 * is set as the context node. The context node is not restored.
15131
 *
15132
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15133
 *         the caller has to free the object.
15134
 */
15135
xmlXPathObjectPtr
15136
0
xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
15137
0
    if (str == NULL)
15138
0
        return(NULL);
15139
0
    if (xmlXPathSetContextNode(node, ctx) < 0)
15140
0
        return(NULL);
15141
0
    return(xmlXPathEval(str, ctx));
15142
0
}
15143
15144
/**
15145
 * xmlXPathEvalExpression:
15146
 * @str:  the XPath expression
15147
 * @ctxt:  the XPath context
15148
 *
15149
 * Alias for xmlXPathEval().
15150
 *
15151
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15152
 *         the caller has to free the object.
15153
 */
15154
xmlXPathObjectPtr
15155
0
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15156
0
    return(xmlXPathEval(str, ctxt));
15157
0
}
15158
15159
/************************************************************************
15160
 *                  *
15161
 *  Extra functions not pertaining to the XPath spec    *
15162
 *                  *
15163
 ************************************************************************/
15164
/**
15165
 * xmlXPathEscapeUriFunction:
15166
 * @ctxt:  the XPath Parser context
15167
 * @nargs:  the number of arguments
15168
 *
15169
 * Implement the escape-uri() XPath function
15170
 *    string escape-uri(string $str, bool $escape-reserved)
15171
 *
15172
 * This function applies the URI escaping rules defined in section 2 of [RFC
15173
 * 2396] to the string supplied as $uri-part, which typically represents all
15174
 * or part of a URI. The effect of the function is to replace any special
15175
 * character in the string by an escape sequence of the form %xx%yy...,
15176
 * where xxyy... is the hexadecimal representation of the octets used to
15177
 * represent the character in UTF-8.
15178
 *
15179
 * The set of characters that are escaped depends on the setting of the
15180
 * boolean argument $escape-reserved.
15181
 *
15182
 * If $escape-reserved is true, all characters are escaped other than lower
15183
 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15184
 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15185
 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15186
 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15187
 * A-F).
15188
 *
15189
 * If $escape-reserved is false, the behavior differs in that characters
15190
 * referred to in [RFC 2396] as reserved characters are not escaped. These
15191
 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15192
 *
15193
 * [RFC 2396] does not define whether escaped URIs should use lower case or
15194
 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15195
 * compared using string comparison functions, this function must always use
15196
 * the upper-case letters A-F.
15197
 *
15198
 * Generally, $escape-reserved should be set to true when escaping a string
15199
 * that is to form a single part of a URI, and to false when escaping an
15200
 * entire URI or URI reference.
15201
 *
15202
 * In the case of non-ascii characters, the string is encoded according to
15203
 * utf-8 and then converted according to RFC 2396.
15204
 *
15205
 * Examples
15206
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15207
 *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15208
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15209
 *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15210
 *
15211
 */
15212
static void
15213
0
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15214
0
    xmlXPathObjectPtr str;
15215
0
    int escape_reserved;
15216
0
    xmlBufPtr target;
15217
0
    xmlChar *cptr;
15218
0
    xmlChar escape[4];
15219
15220
0
    CHECK_ARITY(2);
15221
15222
0
    escape_reserved = xmlXPathPopBoolean(ctxt);
15223
15224
0
    CAST_TO_STRING;
15225
0
    str = valuePop(ctxt);
15226
15227
0
    target = xmlBufCreate();
15228
15229
0
    escape[0] = '%';
15230
0
    escape[3] = 0;
15231
15232
0
    if (target) {
15233
0
  for (cptr = str->stringval; *cptr; cptr++) {
15234
0
      if ((*cptr >= 'A' && *cptr <= 'Z') ||
15235
0
    (*cptr >= 'a' && *cptr <= 'z') ||
15236
0
    (*cptr >= '0' && *cptr <= '9') ||
15237
0
    *cptr == '-' || *cptr == '_' || *cptr == '.' ||
15238
0
    *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15239
0
    *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15240
0
    (*cptr == '%' &&
15241
0
     ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15242
0
      (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15243
0
      (cptr[1] >= '0' && cptr[1] <= '9')) &&
15244
0
     ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15245
0
      (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15246
0
      (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15247
0
    (!escape_reserved &&
15248
0
     (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15249
0
      *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15250
0
      *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15251
0
      *cptr == ','))) {
15252
0
    xmlBufAdd(target, cptr, 1);
15253
0
      } else {
15254
0
    if ((*cptr >> 4) < 10)
15255
0
        escape[1] = '0' + (*cptr >> 4);
15256
0
    else
15257
0
        escape[1] = 'A' - 10 + (*cptr >> 4);
15258
0
    if ((*cptr & 0xF) < 10)
15259
0
        escape[2] = '0' + (*cptr & 0xF);
15260
0
    else
15261
0
        escape[2] = 'A' - 10 + (*cptr & 0xF);
15262
15263
0
    xmlBufAdd(target, &escape[0], 3);
15264
0
      }
15265
0
  }
15266
0
    }
15267
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15268
0
  xmlBufContent(target)));
15269
0
    xmlBufFree(target);
15270
0
    xmlXPathReleaseObject(ctxt->context, str);
15271
0
}
15272
15273
/**
15274
 * xmlXPathRegisterAllFunctions:
15275
 * @ctxt:  the XPath context
15276
 *
15277
 * Registers all default XPath functions in this context
15278
 */
15279
void
15280
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15281
0
{
15282
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15283
0
                         xmlXPathBooleanFunction);
15284
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15285
0
                         xmlXPathCeilingFunction);
15286
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15287
0
                         xmlXPathCountFunction);
15288
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15289
0
                         xmlXPathConcatFunction);
15290
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15291
0
                         xmlXPathContainsFunction);
15292
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15293
0
                         xmlXPathIdFunction);
15294
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15295
0
                         xmlXPathFalseFunction);
15296
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15297
0
                         xmlXPathFloorFunction);
15298
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15299
0
                         xmlXPathLastFunction);
15300
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15301
0
                         xmlXPathLangFunction);
15302
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15303
0
                         xmlXPathLocalNameFunction);
15304
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15305
0
                         xmlXPathNotFunction);
15306
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15307
0
                         xmlXPathNameFunction);
15308
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15309
0
                         xmlXPathNamespaceURIFunction);
15310
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15311
0
                         xmlXPathNormalizeFunction);
15312
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15313
0
                         xmlXPathNumberFunction);
15314
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15315
0
                         xmlXPathPositionFunction);
15316
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15317
0
                         xmlXPathRoundFunction);
15318
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15319
0
                         xmlXPathStringFunction);
15320
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15321
0
                         xmlXPathStringLengthFunction);
15322
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15323
0
                         xmlXPathStartsWithFunction);
15324
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15325
0
                         xmlXPathSubstringFunction);
15326
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15327
0
                         xmlXPathSubstringBeforeFunction);
15328
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15329
0
                         xmlXPathSubstringAfterFunction);
15330
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15331
0
                         xmlXPathSumFunction);
15332
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15333
0
                         xmlXPathTrueFunction);
15334
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15335
0
                         xmlXPathTranslateFunction);
15336
15337
0
    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15338
0
   (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15339
0
                         xmlXPathEscapeUriFunction);
15340
0
}
15341
15342
#endif /* LIBXML_XPATH_ENABLED */
15343
#define bottom_xpath
15344
#include "elfgcchack.h"