~ubuntu-branches/ubuntu/utopic/libxml2/utopic

« back to all changes in this revision

Viewing changes to .pc/0007-Fix-XPath-optimization-with-predicates.patch/xpath.c

  • Committer: Package Import Robot
  • Author(s): Aron Xu, Christian Svensson, Daniel Schepler, Helmut Grohne, Adam Conrad, Matthias Klose, Aron Xu
  • Date: 2014-07-09 05:40:15 UTC
  • mto: This revision was merged to the branch mainline in revision 75.
  • Revision ID: package-import@ubuntu.com-20140709054015-rdnfjxrf3zvmw6l7
[ Christian Svensson ]
* Do not build-depend on readline (Closes: #742350)

[ Daniel Schepler ]
* Patch to bootstrap without python (Closes: #738080)

[ Helmut Grohne ]
* Drop unneeded B-D on perl and binutils (Closes: #753005)

[ Adam Conrad ]
* Actually run dh_autoreconf, which the old/new mixed rules file misses.

[ Matthias Klose ]
* Add patch to fix python multiarch issue
* Allow the package to cross-build by tweaking B-Ds on python
* Set PYTHON_LIBS for cross builds

[ Aron Xu ]
* Use correct $CC
* Configure udeb without python
* New round of cherry-picking upstream fixes
  - Includes fixes for CVE-2014-0191 (Closes: #747309).
* Call prename with -vf
* Require python-all-dev (>= 2.7.5-5~)
* Bump std-ver: 3.9.4 -> 3.9.5, no change

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
#define IN_LIBXML
18
 
#include "libxml.h"
19
 
 
20
 
#include <string.h>
21
 
 
22
 
#ifdef HAVE_SYS_TYPES_H
23
 
#include <sys/types.h>
24
 
#endif
25
 
#ifdef HAVE_MATH_H
26
 
#include <math.h>
27
 
#endif
28
 
#ifdef HAVE_FLOAT_H
29
 
#include <float.h>
30
 
#endif
31
 
#ifdef HAVE_CTYPE_H
32
 
#include <ctype.h>
33
 
#endif
34
 
#ifdef HAVE_SIGNAL_H
35
 
#include <signal.h>
36
 
#endif
37
 
 
38
 
#include <libxml/xmlmemory.h>
39
 
#include <libxml/tree.h>
40
 
#include <libxml/valid.h>
41
 
#include <libxml/xpath.h>
42
 
#include <libxml/xpathInternals.h>
43
 
#include <libxml/parserInternals.h>
44
 
#include <libxml/hash.h>
45
 
#ifdef LIBXML_XPTR_ENABLED
46
 
#include <libxml/xpointer.h>
47
 
#endif
48
 
#ifdef LIBXML_DEBUG_ENABLED
49
 
#include <libxml/debugXML.h>
50
 
#endif
51
 
#include <libxml/xmlerror.h>
52
 
#include <libxml/threads.h>
53
 
#include <libxml/globals.h>
54
 
#ifdef LIBXML_PATTERN_ENABLED
55
 
#include <libxml/pattern.h>
56
 
#endif
57
 
 
58
 
#include "buf.h"
59
 
 
60
 
#ifdef LIBXML_PATTERN_ENABLED
61
 
#define XPATH_STREAMING
62
 
#endif
63
 
 
64
 
#define TODO                                                            \
65
 
    xmlGenericError(xmlGenericErrorContext,                             \
66
 
            "Unimplemented block at %s:%d\n",                           \
67
 
            __FILE__, __LINE__);
68
 
 
69
 
/**
70
 
 * WITH_TIM_SORT:
71
 
 *
72
 
 * Use the Timsort algorithm provided in timsort.h to sort
73
 
 * nodeset as this is a great improvement over the old Shell sort
74
 
 * used in xmlXPathNodeSetSort()
75
 
 */
76
 
#define WITH_TIM_SORT
77
 
 
78
 
/*
79
 
* XP_OPTIMIZED_NON_ELEM_COMPARISON:
80
 
* If defined, this will use xmlXPathCmpNodesExt() instead of
81
 
* xmlXPathCmpNodes(). The new function is optimized comparison of
82
 
* non-element nodes; actually it will speed up comparison only if
83
 
* xmlXPathOrderDocElems() was called in order to index the elements of
84
 
* a tree in document order; Libxslt does such an indexing, thus it will
85
 
* benefit from this optimization.
86
 
*/
87
 
#define XP_OPTIMIZED_NON_ELEM_COMPARISON
88
 
 
89
 
/*
90
 
* XP_OPTIMIZED_FILTER_FIRST:
91
 
* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
92
 
* in a way, that it stop evaluation at the first node.
93
 
*/
94
 
#define XP_OPTIMIZED_FILTER_FIRST
95
 
 
96
 
/*
97
 
* XP_DEBUG_OBJ_USAGE:
98
 
* Internal flag to enable tracking of how much XPath objects have been
99
 
* created.
100
 
*/
101
 
/* #define XP_DEBUG_OBJ_USAGE */
102
 
 
103
 
/*
104
 
 * XPATH_MAX_STEPS:
105
 
 * when compiling an XPath expression we arbitrary limit the maximum
106
 
 * number of step operation in the compiled expression. 1000000 is
107
 
 * an insanely large value which should never be reached under normal
108
 
 * circumstances
109
 
 */
110
 
#define XPATH_MAX_STEPS 1000000
111
 
 
112
 
/*
113
 
 * XPATH_MAX_STACK_DEPTH:
114
 
 * when evaluating an XPath expression we arbitrary limit the maximum
115
 
 * number of object allowed to be pushed on the stack. 1000000 is
116
 
 * an insanely large value which should never be reached under normal
117
 
 * circumstances
118
 
 */
119
 
#define XPATH_MAX_STACK_DEPTH 1000000
120
 
 
121
 
/*
122
 
 * XPATH_MAX_NODESET_LENGTH:
123
 
 * when evaluating an XPath expression nodesets are created and we
124
 
 * arbitrary limit the maximum length of those node set. 10000000 is
125
 
 * an insanely large value which should never be reached under normal
126
 
 * circumstances, one would first need to construct an in memory tree
127
 
 * with more than 10 millions nodes.
128
 
 */
129
 
#define XPATH_MAX_NODESET_LENGTH 10000000
130
 
 
131
 
/*
132
 
 * TODO:
133
 
 * There are a few spots where some tests are done which depend upon ascii
134
 
 * data.  These should be enhanced for full UTF8 support (see particularly
135
 
 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
136
 
 */
137
 
 
138
 
/*
139
 
 * Wrapper for the Timsort argorithm from timsort.h
140
 
 */
141
 
#ifdef WITH_TIM_SORT
142
 
#define SORT_NAME libxml_domnode
143
 
#define SORT_TYPE xmlNodePtr
144
 
/**
145
 
 * wrap_cmp:
146
 
 * @x: a node
147
 
 * @y: another node
148
 
 *
149
 
 * Comparison function for the Timsort implementation
150
 
 *
151
 
 * Returns -2 in case of error -1 if first point < second point, 0 if
152
 
 *         it's the same node, +1 otherwise
153
 
 */
154
 
static
155
 
int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
156
 
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
157
 
    static int xmlXPathCmpNodesExt(xmlNodePtr, xmlNodePtr);
158
 
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
159
 
    {
160
 
        int res = xmlXPathCmpNodesExt(x, y);
161
 
        return res == -2 ? res : -res;
162
 
    }
163
 
#else
164
 
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
165
 
    {
166
 
        int res = xmlXPathCmpNodes(x, y);
167
 
        return res == -2 ? res : -res;
168
 
    }
169
 
#endif
170
 
#define SORT_CMP(x, y)  (wrap_cmp(x, y))
171
 
#include "timsort.h"
172
 
#endif /* WITH_TIM_SORT */
173
 
 
174
 
#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
175
 
 
176
 
/************************************************************************
177
 
 *                                                                      *
178
 
 *                      Floating point stuff                            *
179
 
 *                                                                      *
180
 
 ************************************************************************/
181
 
 
182
 
#ifndef TRIO_REPLACE_STDIO
183
 
#define TRIO_PUBLIC static
184
 
#endif
185
 
#include "trionan.c"
186
 
 
187
 
/*
188
 
 * The lack of portability of this section of the libc is annoying !
189
 
 */
190
 
double xmlXPathNAN = 0;
191
 
double xmlXPathPINF = 1;
192
 
double xmlXPathNINF = -1;
193
 
static double xmlXPathNZERO = 0; /* not exported from headers */
194
 
static int xmlXPathInitialized = 0;
195
 
 
196
 
/**
197
 
 * xmlXPathInit:
198
 
 *
199
 
 * Initialize the XPath environment
200
 
 */
201
 
void
202
 
xmlXPathInit(void) {
203
 
    if (xmlXPathInitialized) return;
204
 
 
205
 
    xmlXPathPINF = trio_pinf();
206
 
    xmlXPathNINF = trio_ninf();
207
 
    xmlXPathNAN = trio_nan();
208
 
    xmlXPathNZERO = trio_nzero();
209
 
 
210
 
    xmlXPathInitialized = 1;
211
 
}
212
 
 
213
 
/**
214
 
 * xmlXPathIsNaN:
215
 
 * @val:  a double value
216
 
 *
217
 
 * Provides a portable isnan() function to detect whether a double
218
 
 * is a NotaNumber. Based on trio code
219
 
 * http://sourceforge.net/projects/ctrio/
220
 
 *
221
 
 * Returns 1 if the value is a NaN, 0 otherwise
222
 
 */
223
 
int
224
 
xmlXPathIsNaN(double val) {
225
 
    return(trio_isnan(val));
226
 
}
227
 
 
228
 
/**
229
 
 * xmlXPathIsInf:
230
 
 * @val:  a double value
231
 
 *
232
 
 * Provides a portable isinf() function to detect whether a double
233
 
 * is a +Infinite or -Infinite. Based on trio code
234
 
 * http://sourceforge.net/projects/ctrio/
235
 
 *
236
 
 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
237
 
 */
238
 
int
239
 
xmlXPathIsInf(double val) {
240
 
    return(trio_isinf(val));
241
 
}
242
 
 
243
 
#endif /* SCHEMAS or XPATH */
244
 
#ifdef LIBXML_XPATH_ENABLED
245
 
/**
246
 
 * xmlXPathGetSign:
247
 
 * @val:  a double value
248
 
 *
249
 
 * Provides a portable function to detect the sign of a double
250
 
 * Modified from trio code
251
 
 * http://sourceforge.net/projects/ctrio/
252
 
 *
253
 
 * Returns 1 if the value is Negative, 0 if positive
254
 
 */
255
 
static int
256
 
xmlXPathGetSign(double val) {
257
 
    return(trio_signbit(val));
258
 
}
259
 
 
260
 
 
261
 
/*
262
 
 * TODO: when compatibility allows remove all "fake node libxslt" strings
263
 
 *       the test should just be name[0] = ' '
264
 
 */
265
 
#ifdef DEBUG_XPATH_EXPRESSION
266
 
#define DEBUG_STEP
267
 
#define DEBUG_EXPR
268
 
#define DEBUG_EVAL_COUNTS
269
 
#endif
270
 
 
271
 
static xmlNs xmlXPathXMLNamespaceStruct = {
272
 
    NULL,
273
 
    XML_NAMESPACE_DECL,
274
 
    XML_XML_NAMESPACE,
275
 
    BAD_CAST "xml",
276
 
    NULL,
277
 
    NULL
278
 
};
279
 
static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
280
 
#ifndef LIBXML_THREAD_ENABLED
281
 
/*
282
 
 * Optimizer is disabled only when threaded apps are detected while
283
 
 * the library ain't compiled for thread safety.
284
 
 */
285
 
static int xmlXPathDisableOptimizer = 0;
286
 
#endif
287
 
 
288
 
/************************************************************************
289
 
 *                                                                      *
290
 
 *                      Error handling routines                         *
291
 
 *                                                                      *
292
 
 ************************************************************************/
293
 
 
294
 
/**
295
 
 * XP_ERRORNULL:
296
 
 * @X:  the error code
297
 
 *
298
 
 * Macro to raise an XPath error and return NULL.
299
 
 */
300
 
#define XP_ERRORNULL(X)                                                 \
301
 
    { xmlXPathErr(ctxt, X); return(NULL); }
302
 
 
303
 
/*
304
 
 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
305
 
 */
306
 
static const char *xmlXPathErrorMessages[] = {
307
 
    "Ok\n",
308
 
    "Number encoding\n",
309
 
    "Unfinished literal\n",
310
 
    "Start of literal\n",
311
 
    "Expected $ for variable reference\n",
312
 
    "Undefined variable\n",
313
 
    "Invalid predicate\n",
314
 
    "Invalid expression\n",
315
 
    "Missing closing curly brace\n",
316
 
    "Unregistered function\n",
317
 
    "Invalid operand\n",
318
 
    "Invalid type\n",
319
 
    "Invalid number of arguments\n",
320
 
    "Invalid context size\n",
321
 
    "Invalid context position\n",
322
 
    "Memory allocation error\n",
323
 
    "Syntax error\n",
324
 
    "Resource error\n",
325
 
    "Sub resource error\n",
326
 
    "Undefined namespace prefix\n",
327
 
    "Encoding error\n",
328
 
    "Char out of XML range\n",
329
 
    "Invalid or incomplete context\n",
330
 
    "Stack usage errror\n",
331
 
    "Forbidden variable\n",
332
 
    "?? Unknown error ??\n"     /* Must be last in the list! */
333
 
};
334
 
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
335
 
                   sizeof(xmlXPathErrorMessages[0])) - 1)
336
 
/**
337
 
 * xmlXPathErrMemory:
338
 
 * @ctxt:  an XPath context
339
 
 * @extra:  extra informations
340
 
 *
341
 
 * Handle a redefinition of attribute error
342
 
 */
343
 
static void
344
 
xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
345
 
{
346
 
    if (ctxt != NULL) {
347
 
        if (extra) {
348
 
            xmlChar buf[200];
349
 
 
350
 
            xmlStrPrintf(buf, 200,
351
 
                         BAD_CAST "Memory allocation failed : %s\n",
352
 
                         extra);
353
 
            ctxt->lastError.message = (char *) xmlStrdup(buf);
354
 
        } else {
355
 
            ctxt->lastError.message = (char *)
356
 
               xmlStrdup(BAD_CAST "Memory allocation failed\n");
357
 
        }
358
 
        ctxt->lastError.domain = XML_FROM_XPATH;
359
 
        ctxt->lastError.code = XML_ERR_NO_MEMORY;
360
 
        if (ctxt->error != NULL)
361
 
            ctxt->error(ctxt->userData, &ctxt->lastError);
362
 
    } else {
363
 
        if (extra)
364
 
            __xmlRaiseError(NULL, NULL, NULL,
365
 
                            NULL, NULL, XML_FROM_XPATH,
366
 
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
367
 
                            extra, NULL, NULL, 0, 0,
368
 
                            "Memory allocation failed : %s\n", extra);
369
 
        else
370
 
            __xmlRaiseError(NULL, NULL, NULL,
371
 
                            NULL, NULL, XML_FROM_XPATH,
372
 
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
373
 
                            NULL, NULL, NULL, 0, 0,
374
 
                            "Memory allocation failed\n");
375
 
    }
376
 
}
377
 
 
378
 
/**
379
 
 * xmlXPathPErrMemory:
380
 
 * @ctxt:  an XPath parser context
381
 
 * @extra:  extra informations
382
 
 *
383
 
 * Handle a redefinition of attribute error
384
 
 */
385
 
static void
386
 
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
387
 
{
388
 
    if (ctxt == NULL)
389
 
        xmlXPathErrMemory(NULL, extra);
390
 
    else {
391
 
        ctxt->error = XPATH_MEMORY_ERROR;
392
 
        xmlXPathErrMemory(ctxt->context, extra);
393
 
    }
394
 
}
395
 
 
396
 
/**
397
 
 * xmlXPathErr:
398
 
 * @ctxt:  a XPath parser context
399
 
 * @error:  the error code
400
 
 *
401
 
 * Handle an XPath error
402
 
 */
403
 
void
404
 
xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
405
 
{
406
 
    if ((error < 0) || (error > MAXERRNO))
407
 
        error = MAXERRNO;
408
 
    if (ctxt == NULL) {
409
 
        __xmlRaiseError(NULL, NULL, NULL,
410
 
                        NULL, NULL, XML_FROM_XPATH,
411
 
                        error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
412
 
                        XML_ERR_ERROR, NULL, 0,
413
 
                        NULL, NULL, NULL, 0, 0,
414
 
                        "%s", xmlXPathErrorMessages[error]);
415
 
        return;
416
 
    }
417
 
    ctxt->error = error;
418
 
    if (ctxt->context == NULL) {
419
 
        __xmlRaiseError(NULL, NULL, NULL,
420
 
                        NULL, NULL, XML_FROM_XPATH,
421
 
                        error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
422
 
                        XML_ERR_ERROR, NULL, 0,
423
 
                        (const char *) ctxt->base, NULL, NULL,
424
 
                        ctxt->cur - ctxt->base, 0,
425
 
                        "%s", xmlXPathErrorMessages[error]);
426
 
        return;
427
 
    }
428
 
 
429
 
    /* cleanup current last error */
430
 
    xmlResetError(&ctxt->context->lastError);
431
 
 
432
 
    ctxt->context->lastError.domain = XML_FROM_XPATH;
433
 
    ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
434
 
                           XPATH_EXPRESSION_OK;
435
 
    ctxt->context->lastError.level = XML_ERR_ERROR;
436
 
    ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
437
 
    ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
438
 
    ctxt->context->lastError.node = ctxt->context->debugNode;
439
 
    if (ctxt->context->error != NULL) {
440
 
        ctxt->context->error(ctxt->context->userData,
441
 
                             &ctxt->context->lastError);
442
 
    } else {
443
 
        __xmlRaiseError(NULL, NULL, NULL,
444
 
                        NULL, ctxt->context->debugNode, XML_FROM_XPATH,
445
 
                        error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
446
 
                        XML_ERR_ERROR, NULL, 0,
447
 
                        (const char *) ctxt->base, NULL, NULL,
448
 
                        ctxt->cur - ctxt->base, 0,
449
 
                        "%s", xmlXPathErrorMessages[error]);
450
 
    }
451
 
 
452
 
}
453
 
 
454
 
/**
455
 
 * xmlXPatherror:
456
 
 * @ctxt:  the XPath Parser context
457
 
 * @file:  the file name
458
 
 * @line:  the line number
459
 
 * @no:  the error number
460
 
 *
461
 
 * Formats an error message.
462
 
 */
463
 
void
464
 
xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
465
 
              int line ATTRIBUTE_UNUSED, int no) {
466
 
    xmlXPathErr(ctxt, no);
467
 
}
468
 
 
469
 
/************************************************************************
470
 
 *                                                                      *
471
 
 *                      Utilities                                       *
472
 
 *                                                                      *
473
 
 ************************************************************************/
474
 
 
475
 
/**
476
 
 * xsltPointerList:
477
 
 *
478
 
 * Pointer-list for various purposes.
479
 
 */
480
 
typedef struct _xmlPointerList xmlPointerList;
481
 
typedef xmlPointerList *xmlPointerListPtr;
482
 
struct _xmlPointerList {
483
 
    void **items;
484
 
    int number;
485
 
    int size;
486
 
};
487
 
/*
488
 
* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
489
 
* and here, we should make the functions public.
490
 
*/
491
 
static int
492
 
xmlPointerListAddSize(xmlPointerListPtr list,
493
 
                       void *item,
494
 
                       int initialSize)
495
 
{
496
 
    if (list->items == NULL) {
497
 
        if (initialSize <= 0)
498
 
            initialSize = 1;
499
 
        list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
500
 
        if (list->items == NULL) {
501
 
            xmlXPathErrMemory(NULL,
502
 
                "xmlPointerListCreate: allocating item\n");
503
 
            return(-1);
504
 
        }
505
 
        list->number = 0;
506
 
        list->size = initialSize;
507
 
    } else if (list->size <= list->number) {
508
 
        if (list->size > 50000000) {
509
 
            xmlXPathErrMemory(NULL,
510
 
                "xmlPointerListAddSize: re-allocating item\n");
511
 
            return(-1);
512
 
        }
513
 
        list->size *= 2;
514
 
        list->items = (void **) xmlRealloc(list->items,
515
 
            list->size * sizeof(void *));
516
 
        if (list->items == NULL) {
517
 
            xmlXPathErrMemory(NULL,
518
 
                "xmlPointerListAddSize: re-allocating item\n");
519
 
            list->size = 0;
520
 
            return(-1);
521
 
        }
522
 
    }
523
 
    list->items[list->number++] = item;
524
 
    return(0);
525
 
}
526
 
 
527
 
/**
528
 
 * xsltPointerListCreate:
529
 
 *
530
 
 * Creates an xsltPointerList structure.
531
 
 *
532
 
 * Returns a xsltPointerList structure or NULL in case of an error.
533
 
 */
534
 
static xmlPointerListPtr
535
 
xmlPointerListCreate(int initialSize)
536
 
{
537
 
    xmlPointerListPtr ret;
538
 
 
539
 
    ret = xmlMalloc(sizeof(xmlPointerList));
540
 
    if (ret == NULL) {
541
 
        xmlXPathErrMemory(NULL,
542
 
            "xmlPointerListCreate: allocating item\n");
543
 
        return (NULL);
544
 
    }
545
 
    memset(ret, 0, sizeof(xmlPointerList));
546
 
    if (initialSize > 0) {
547
 
        xmlPointerListAddSize(ret, NULL, initialSize);
548
 
        ret->number = 0;
549
 
    }
550
 
    return (ret);
551
 
}
552
 
 
553
 
/**
554
 
 * xsltPointerListFree:
555
 
 *
556
 
 * Frees the xsltPointerList structure. This does not free
557
 
 * the content of the list.
558
 
 */
559
 
static void
560
 
xmlPointerListFree(xmlPointerListPtr list)
561
 
{
562
 
    if (list == NULL)
563
 
        return;
564
 
    if (list->items != NULL)
565
 
        xmlFree(list->items);
566
 
    xmlFree(list);
567
 
}
568
 
 
569
 
/************************************************************************
570
 
 *                                                                      *
571
 
 *                      Parser Types                                    *
572
 
 *                                                                      *
573
 
 ************************************************************************/
574
 
 
575
 
/*
576
 
 * Types are private:
577
 
 */
578
 
 
579
 
typedef enum {
580
 
    XPATH_OP_END=0,
581
 
    XPATH_OP_AND,
582
 
    XPATH_OP_OR,
583
 
    XPATH_OP_EQUAL,
584
 
    XPATH_OP_CMP,
585
 
    XPATH_OP_PLUS,
586
 
    XPATH_OP_MULT,
587
 
    XPATH_OP_UNION,
588
 
    XPATH_OP_ROOT,
589
 
    XPATH_OP_NODE,
590
 
    XPATH_OP_RESET, /* 10 */
591
 
    XPATH_OP_COLLECT,
592
 
    XPATH_OP_VALUE, /* 12 */
593
 
    XPATH_OP_VARIABLE,
594
 
    XPATH_OP_FUNCTION,
595
 
    XPATH_OP_ARG,
596
 
    XPATH_OP_PREDICATE,
597
 
    XPATH_OP_FILTER, /* 17 */
598
 
    XPATH_OP_SORT /* 18 */
599
 
#ifdef LIBXML_XPTR_ENABLED
600
 
    ,XPATH_OP_RANGETO
601
 
#endif
602
 
} xmlXPathOp;
603
 
 
604
 
typedef enum {
605
 
    AXIS_ANCESTOR = 1,
606
 
    AXIS_ANCESTOR_OR_SELF,
607
 
    AXIS_ATTRIBUTE,
608
 
    AXIS_CHILD,
609
 
    AXIS_DESCENDANT,
610
 
    AXIS_DESCENDANT_OR_SELF,
611
 
    AXIS_FOLLOWING,
612
 
    AXIS_FOLLOWING_SIBLING,
613
 
    AXIS_NAMESPACE,
614
 
    AXIS_PARENT,
615
 
    AXIS_PRECEDING,
616
 
    AXIS_PRECEDING_SIBLING,
617
 
    AXIS_SELF
618
 
} xmlXPathAxisVal;
619
 
 
620
 
typedef enum {
621
 
    NODE_TEST_NONE = 0,
622
 
    NODE_TEST_TYPE = 1,
623
 
    NODE_TEST_PI = 2,
624
 
    NODE_TEST_ALL = 3,
625
 
    NODE_TEST_NS = 4,
626
 
    NODE_TEST_NAME = 5
627
 
} xmlXPathTestVal;
628
 
 
629
 
typedef enum {
630
 
    NODE_TYPE_NODE = 0,
631
 
    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
632
 
    NODE_TYPE_TEXT = XML_TEXT_NODE,
633
 
    NODE_TYPE_PI = XML_PI_NODE
634
 
} xmlXPathTypeVal;
635
 
 
636
 
typedef struct _xmlXPathStepOp xmlXPathStepOp;
637
 
typedef xmlXPathStepOp *xmlXPathStepOpPtr;
638
 
struct _xmlXPathStepOp {
639
 
    xmlXPathOp op;              /* The identifier of the operation */
640
 
    int ch1;                    /* First child */
641
 
    int ch2;                    /* Second child */
642
 
    int value;
643
 
    int value2;
644
 
    int value3;
645
 
    void *value4;
646
 
    void *value5;
647
 
    void *cache;
648
 
    void *cacheURI;
649
 
};
650
 
 
651
 
struct _xmlXPathCompExpr {
652
 
    int nbStep;                 /* Number of steps in this expression */
653
 
    int maxStep;                /* Maximum number of steps allocated */
654
 
    xmlXPathStepOp *steps;      /* ops for computation of this expression */
655
 
    int last;                   /* index of last step in expression */
656
 
    xmlChar *expr;              /* the expression being computed */
657
 
    xmlDictPtr dict;            /* the dictionnary to use if any */
658
 
#ifdef DEBUG_EVAL_COUNTS
659
 
    int nb;
660
 
    xmlChar *string;
661
 
#endif
662
 
#ifdef XPATH_STREAMING
663
 
    xmlPatternPtr stream;
664
 
#endif
665
 
};
666
 
 
667
 
/************************************************************************
668
 
 *                                                                      *
669
 
 *                      Forward declarations                            *
670
 
 *                                                                      *
671
 
 ************************************************************************/
672
 
static void
673
 
xmlXPathFreeValueTree(xmlNodeSetPtr obj);
674
 
static void
675
 
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
676
 
static int
677
 
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
678
 
                        xmlXPathStepOpPtr op, xmlNodePtr *first);
679
 
static int
680
 
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
681
 
                            xmlXPathStepOpPtr op,
682
 
                            int isPredicate);
683
 
 
684
 
/************************************************************************
685
 
 *                                                                      *
686
 
 *                      Parser Type functions                           *
687
 
 *                                                                      *
688
 
 ************************************************************************/
689
 
 
690
 
/**
691
 
 * xmlXPathNewCompExpr:
692
 
 *
693
 
 * Create a new Xpath component
694
 
 *
695
 
 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
696
 
 */
697
 
static xmlXPathCompExprPtr
698
 
xmlXPathNewCompExpr(void) {
699
 
    xmlXPathCompExprPtr cur;
700
 
 
701
 
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
702
 
    if (cur == NULL) {
703
 
        xmlXPathErrMemory(NULL, "allocating component\n");
704
 
        return(NULL);
705
 
    }
706
 
    memset(cur, 0, sizeof(xmlXPathCompExpr));
707
 
    cur->maxStep = 10;
708
 
    cur->nbStep = 0;
709
 
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
710
 
                                           sizeof(xmlXPathStepOp));
711
 
    if (cur->steps == NULL) {
712
 
        xmlXPathErrMemory(NULL, "allocating steps\n");
713
 
        xmlFree(cur);
714
 
        return(NULL);
715
 
    }
716
 
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
717
 
    cur->last = -1;
718
 
#ifdef DEBUG_EVAL_COUNTS
719
 
    cur->nb = 0;
720
 
#endif
721
 
    return(cur);
722
 
}
723
 
 
724
 
/**
725
 
 * xmlXPathFreeCompExpr:
726
 
 * @comp:  an XPATH comp
727
 
 *
728
 
 * Free up the memory allocated by @comp
729
 
 */
730
 
void
731
 
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
732
 
{
733
 
    xmlXPathStepOpPtr op;
734
 
    int i;
735
 
 
736
 
    if (comp == NULL)
737
 
        return;
738
 
    if (comp->dict == NULL) {
739
 
        for (i = 0; i < comp->nbStep; i++) {
740
 
            op = &comp->steps[i];
741
 
            if (op->value4 != NULL) {
742
 
                if (op->op == XPATH_OP_VALUE)
743
 
                    xmlXPathFreeObject(op->value4);
744
 
                else
745
 
                    xmlFree(op->value4);
746
 
            }
747
 
            if (op->value5 != NULL)
748
 
                xmlFree(op->value5);
749
 
        }
750
 
    } else {
751
 
        for (i = 0; i < comp->nbStep; i++) {
752
 
            op = &comp->steps[i];
753
 
            if (op->value4 != NULL) {
754
 
                if (op->op == XPATH_OP_VALUE)
755
 
                    xmlXPathFreeObject(op->value4);
756
 
            }
757
 
        }
758
 
        xmlDictFree(comp->dict);
759
 
    }
760
 
    if (comp->steps != NULL) {
761
 
        xmlFree(comp->steps);
762
 
    }
763
 
#ifdef DEBUG_EVAL_COUNTS
764
 
    if (comp->string != NULL) {
765
 
        xmlFree(comp->string);
766
 
    }
767
 
#endif
768
 
#ifdef XPATH_STREAMING
769
 
    if (comp->stream != NULL) {
770
 
        xmlFreePatternList(comp->stream);
771
 
    }
772
 
#endif
773
 
    if (comp->expr != NULL) {
774
 
        xmlFree(comp->expr);
775
 
    }
776
 
 
777
 
    xmlFree(comp);
778
 
}
779
 
 
780
 
/**
781
 
 * xmlXPathCompExprAdd:
782
 
 * @comp:  the compiled expression
783
 
 * @ch1: first child index
784
 
 * @ch2: second child index
785
 
 * @op:  an op
786
 
 * @value:  the first int value
787
 
 * @value2:  the second int value
788
 
 * @value3:  the third int value
789
 
 * @value4:  the first string value
790
 
 * @value5:  the second string value
791
 
 *
792
 
 * Add a step to an XPath Compiled Expression
793
 
 *
794
 
 * Returns -1 in case of failure, the index otherwise
795
 
 */
796
 
static int
797
 
xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
798
 
   xmlXPathOp op, int value,
799
 
   int value2, int value3, void *value4, void *value5) {
800
 
    if (comp->nbStep >= comp->maxStep) {
801
 
        xmlXPathStepOp *real;
802
 
 
803
 
        if (comp->maxStep >= XPATH_MAX_STEPS) {
804
 
            xmlXPathErrMemory(NULL, "adding step\n");
805
 
            return(-1);
806
 
        }
807
 
        comp->maxStep *= 2;
808
 
        real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
809
 
                                      comp->maxStep * sizeof(xmlXPathStepOp));
810
 
        if (real == NULL) {
811
 
            comp->maxStep /= 2;
812
 
            xmlXPathErrMemory(NULL, "adding step\n");
813
 
            return(-1);
814
 
        }
815
 
        comp->steps = real;
816
 
    }
817
 
    comp->last = comp->nbStep;
818
 
    comp->steps[comp->nbStep].ch1 = ch1;
819
 
    comp->steps[comp->nbStep].ch2 = ch2;
820
 
    comp->steps[comp->nbStep].op = op;
821
 
    comp->steps[comp->nbStep].value = value;
822
 
    comp->steps[comp->nbStep].value2 = value2;
823
 
    comp->steps[comp->nbStep].value3 = value3;
824
 
    if ((comp->dict != NULL) &&
825
 
        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
826
 
         (op == XPATH_OP_COLLECT))) {
827
 
        if (value4 != NULL) {
828
 
            comp->steps[comp->nbStep].value4 = (xmlChar *)
829
 
                (void *)xmlDictLookup(comp->dict, value4, -1);
830
 
            xmlFree(value4);
831
 
        } else
832
 
            comp->steps[comp->nbStep].value4 = NULL;
833
 
        if (value5 != NULL) {
834
 
            comp->steps[comp->nbStep].value5 = (xmlChar *)
835
 
                (void *)xmlDictLookup(comp->dict, value5, -1);
836
 
            xmlFree(value5);
837
 
        } else
838
 
            comp->steps[comp->nbStep].value5 = NULL;
839
 
    } else {
840
 
        comp->steps[comp->nbStep].value4 = value4;
841
 
        comp->steps[comp->nbStep].value5 = value5;
842
 
    }
843
 
    comp->steps[comp->nbStep].cache = NULL;
844
 
    return(comp->nbStep++);
845
 
}
846
 
 
847
 
/**
848
 
 * xmlXPathCompSwap:
849
 
 * @comp:  the compiled expression
850
 
 * @op: operation index
851
 
 *
852
 
 * Swaps 2 operations in the compiled expression
853
 
 */
854
 
static void
855
 
xmlXPathCompSwap(xmlXPathStepOpPtr op) {
856
 
    int tmp;
857
 
 
858
 
#ifndef LIBXML_THREAD_ENABLED
859
 
    /*
860
 
     * Since this manipulates possibly shared variables, this is
861
 
     * disabled if one detects that the library is used in a multithreaded
862
 
     * application
863
 
     */
864
 
    if (xmlXPathDisableOptimizer)
865
 
        return;
866
 
#endif
867
 
 
868
 
    tmp = op->ch1;
869
 
    op->ch1 = op->ch2;
870
 
    op->ch2 = tmp;
871
 
}
872
 
 
873
 
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)       \
874
 
    xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),                       \
875
 
                        (op), (val), (val2), (val3), (val4), (val5))
876
 
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)                 \
877
 
    xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,               \
878
 
                        (op), (val), (val2), (val3), (val4), (val5))
879
 
 
880
 
#define PUSH_LEAVE_EXPR(op, val, val2)                                  \
881
 
xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
882
 
 
883
 
#define PUSH_UNARY_EXPR(op, ch, val, val2)                              \
884
 
xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
885
 
 
886
 
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)                       \
887
 
xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),                     \
888
 
                        (val), (val2), 0 ,NULL ,NULL)
889
 
 
890
 
/************************************************************************
891
 
 *                                                                      *
892
 
 *              XPath object cache structures                           *
893
 
 *                                                                      *
894
 
 ************************************************************************/
895
 
 
896
 
/* #define XP_DEFAULT_CACHE_ON */
897
 
 
898
 
#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
899
 
 
900
 
typedef struct _xmlXPathContextCache xmlXPathContextCache;
901
 
typedef xmlXPathContextCache *xmlXPathContextCachePtr;
902
 
struct _xmlXPathContextCache {
903
 
    xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
904
 
    xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
905
 
    xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
906
 
    xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
907
 
    xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
908
 
    int maxNodeset;
909
 
    int maxString;
910
 
    int maxBoolean;
911
 
    int maxNumber;
912
 
    int maxMisc;
913
 
#ifdef XP_DEBUG_OBJ_USAGE
914
 
    int dbgCachedAll;
915
 
    int dbgCachedNodeset;
916
 
    int dbgCachedString;
917
 
    int dbgCachedBool;
918
 
    int dbgCachedNumber;
919
 
    int dbgCachedPoint;
920
 
    int dbgCachedRange;
921
 
    int dbgCachedLocset;
922
 
    int dbgCachedUsers;
923
 
    int dbgCachedXSLTTree;
924
 
    int dbgCachedUndefined;
925
 
 
926
 
 
927
 
    int dbgReusedAll;
928
 
    int dbgReusedNodeset;
929
 
    int dbgReusedString;
930
 
    int dbgReusedBool;
931
 
    int dbgReusedNumber;
932
 
    int dbgReusedPoint;
933
 
    int dbgReusedRange;
934
 
    int dbgReusedLocset;
935
 
    int dbgReusedUsers;
936
 
    int dbgReusedXSLTTree;
937
 
    int dbgReusedUndefined;
938
 
 
939
 
#endif
940
 
};
941
 
 
942
 
/************************************************************************
943
 
 *                                                                      *
944
 
 *              Debugging related functions                             *
945
 
 *                                                                      *
946
 
 ************************************************************************/
947
 
 
948
 
#define STRANGE                                                 \
949
 
    xmlGenericError(xmlGenericErrorContext,                             \
950
 
            "Internal error at %s:%d\n",                                \
951
 
            __FILE__, __LINE__);
952
 
 
953
 
#ifdef LIBXML_DEBUG_ENABLED
954
 
static void
955
 
xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
956
 
    int i;
957
 
    char shift[100];
958
 
 
959
 
    for (i = 0;((i < depth) && (i < 25));i++)
960
 
        shift[2 * i] = shift[2 * i + 1] = ' ';
961
 
    shift[2 * i] = shift[2 * i + 1] = 0;
962
 
    if (cur == NULL) {
963
 
        fprintf(output, "%s", shift);
964
 
        fprintf(output, "Node is NULL !\n");
965
 
        return;
966
 
 
967
 
    }
968
 
 
969
 
    if ((cur->type == XML_DOCUMENT_NODE) ||
970
 
             (cur->type == XML_HTML_DOCUMENT_NODE)) {
971
 
        fprintf(output, "%s", shift);
972
 
        fprintf(output, " /\n");
973
 
    } else if (cur->type == XML_ATTRIBUTE_NODE)
974
 
        xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
975
 
    else
976
 
        xmlDebugDumpOneNode(output, cur, depth);
977
 
}
978
 
static void
979
 
xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
980
 
    xmlNodePtr tmp;
981
 
    int i;
982
 
    char shift[100];
983
 
 
984
 
    for (i = 0;((i < depth) && (i < 25));i++)
985
 
        shift[2 * i] = shift[2 * i + 1] = ' ';
986
 
    shift[2 * i] = shift[2 * i + 1] = 0;
987
 
    if (cur == NULL) {
988
 
        fprintf(output, "%s", shift);
989
 
        fprintf(output, "Node is NULL !\n");
990
 
        return;
991
 
 
992
 
    }
993
 
 
994
 
    while (cur != NULL) {
995
 
        tmp = cur;
996
 
        cur = cur->next;
997
 
        xmlDebugDumpOneNode(output, tmp, depth);
998
 
    }
999
 
}
1000
 
 
1001
 
static void
1002
 
xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1003
 
    int i;
1004
 
    char shift[100];
1005
 
 
1006
 
    for (i = 0;((i < depth) && (i < 25));i++)
1007
 
        shift[2 * i] = shift[2 * i + 1] = ' ';
1008
 
    shift[2 * i] = shift[2 * i + 1] = 0;
1009
 
 
1010
 
    if (cur == NULL) {
1011
 
        fprintf(output, "%s", shift);
1012
 
        fprintf(output, "NodeSet is NULL !\n");
1013
 
        return;
1014
 
 
1015
 
    }
1016
 
 
1017
 
    if (cur != NULL) {
1018
 
        fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1019
 
        for (i = 0;i < cur->nodeNr;i++) {
1020
 
            fprintf(output, "%s", shift);
1021
 
            fprintf(output, "%d", i + 1);
1022
 
            xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1023
 
        }
1024
 
    }
1025
 
}
1026
 
 
1027
 
static void
1028
 
xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1029
 
    int i;
1030
 
    char shift[100];
1031
 
 
1032
 
    for (i = 0;((i < depth) && (i < 25));i++)
1033
 
        shift[2 * i] = shift[2 * i + 1] = ' ';
1034
 
    shift[2 * i] = shift[2 * i + 1] = 0;
1035
 
 
1036
 
    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1037
 
        fprintf(output, "%s", shift);
1038
 
        fprintf(output, "Value Tree is NULL !\n");
1039
 
        return;
1040
 
 
1041
 
    }
1042
 
 
1043
 
    fprintf(output, "%s", shift);
1044
 
    fprintf(output, "%d", i + 1);
1045
 
    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1046
 
}
1047
 
#if defined(LIBXML_XPTR_ENABLED)
1048
 
static void
1049
 
xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1050
 
    int i;
1051
 
    char shift[100];
1052
 
 
1053
 
    for (i = 0;((i < depth) && (i < 25));i++)
1054
 
        shift[2 * i] = shift[2 * i + 1] = ' ';
1055
 
    shift[2 * i] = shift[2 * i + 1] = 0;
1056
 
 
1057
 
    if (cur == NULL) {
1058
 
        fprintf(output, "%s", shift);
1059
 
        fprintf(output, "LocationSet is NULL !\n");
1060
 
        return;
1061
 
 
1062
 
    }
1063
 
 
1064
 
    for (i = 0;i < cur->locNr;i++) {
1065
 
        fprintf(output, "%s", shift);
1066
 
        fprintf(output, "%d : ", i + 1);
1067
 
        xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1068
 
    }
1069
 
}
1070
 
#endif /* LIBXML_XPTR_ENABLED */
1071
 
 
1072
 
/**
1073
 
 * xmlXPathDebugDumpObject:
1074
 
 * @output:  the FILE * to dump the output
1075
 
 * @cur:  the object to inspect
1076
 
 * @depth:  indentation level
1077
 
 *
1078
 
 * Dump the content of the object for debugging purposes
1079
 
 */
1080
 
void
1081
 
xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1082
 
    int i;
1083
 
    char shift[100];
1084
 
 
1085
 
    if (output == NULL) return;
1086
 
 
1087
 
    for (i = 0;((i < depth) && (i < 25));i++)
1088
 
        shift[2 * i] = shift[2 * i + 1] = ' ';
1089
 
    shift[2 * i] = shift[2 * i + 1] = 0;
1090
 
 
1091
 
 
1092
 
    fprintf(output, "%s", shift);
1093
 
 
1094
 
    if (cur == NULL) {
1095
 
        fprintf(output, "Object is empty (NULL)\n");
1096
 
        return;
1097
 
    }
1098
 
    switch(cur->type) {
1099
 
        case XPATH_UNDEFINED:
1100
 
            fprintf(output, "Object is uninitialized\n");
1101
 
            break;
1102
 
        case XPATH_NODESET:
1103
 
            fprintf(output, "Object is a Node Set :\n");
1104
 
            xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1105
 
            break;
1106
 
        case XPATH_XSLT_TREE:
1107
 
            fprintf(output, "Object is an XSLT value tree :\n");
1108
 
            xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1109
 
            break;
1110
 
        case XPATH_BOOLEAN:
1111
 
            fprintf(output, "Object is a Boolean : ");
1112
 
            if (cur->boolval) fprintf(output, "true\n");
1113
 
            else fprintf(output, "false\n");
1114
 
            break;
1115
 
        case XPATH_NUMBER:
1116
 
            switch (xmlXPathIsInf(cur->floatval)) {
1117
 
            case 1:
1118
 
                fprintf(output, "Object is a number : Infinity\n");
1119
 
                break;
1120
 
            case -1:
1121
 
                fprintf(output, "Object is a number : -Infinity\n");
1122
 
                break;
1123
 
            default:
1124
 
                if (xmlXPathIsNaN(cur->floatval)) {
1125
 
                    fprintf(output, "Object is a number : NaN\n");
1126
 
                } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1127
 
                    fprintf(output, "Object is a number : 0\n");
1128
 
                } else {
1129
 
                    fprintf(output, "Object is a number : %0g\n", cur->floatval);
1130
 
                }
1131
 
            }
1132
 
            break;
1133
 
        case XPATH_STRING:
1134
 
            fprintf(output, "Object is a string : ");
1135
 
            xmlDebugDumpString(output, cur->stringval);
1136
 
            fprintf(output, "\n");
1137
 
            break;
1138
 
        case XPATH_POINT:
1139
 
            fprintf(output, "Object is a point : index %d in node", cur->index);
1140
 
            xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1141
 
            fprintf(output, "\n");
1142
 
            break;
1143
 
        case XPATH_RANGE:
1144
 
            if ((cur->user2 == NULL) ||
1145
 
                ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1146
 
                fprintf(output, "Object is a collapsed range :\n");
1147
 
                fprintf(output, "%s", shift);
1148
 
                if (cur->index >= 0)
1149
 
                    fprintf(output, "index %d in ", cur->index);
1150
 
                fprintf(output, "node\n");
1151
 
                xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1152
 
                                      depth + 1);
1153
 
            } else  {
1154
 
                fprintf(output, "Object is a range :\n");
1155
 
                fprintf(output, "%s", shift);
1156
 
                fprintf(output, "From ");
1157
 
                if (cur->index >= 0)
1158
 
                    fprintf(output, "index %d in ", cur->index);
1159
 
                fprintf(output, "node\n");
1160
 
                xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1161
 
                                      depth + 1);
1162
 
                fprintf(output, "%s", shift);
1163
 
                fprintf(output, "To ");
1164
 
                if (cur->index2 >= 0)
1165
 
                    fprintf(output, "index %d in ", cur->index2);
1166
 
                fprintf(output, "node\n");
1167
 
                xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1168
 
                                      depth + 1);
1169
 
                fprintf(output, "\n");
1170
 
            }
1171
 
            break;
1172
 
        case XPATH_LOCATIONSET:
1173
 
#if defined(LIBXML_XPTR_ENABLED)
1174
 
            fprintf(output, "Object is a Location Set:\n");
1175
 
            xmlXPathDebugDumpLocationSet(output,
1176
 
                    (xmlLocationSetPtr) cur->user, depth);
1177
 
#endif
1178
 
            break;
1179
 
        case XPATH_USERS:
1180
 
            fprintf(output, "Object is user defined\n");
1181
 
            break;
1182
 
    }
1183
 
}
1184
 
 
1185
 
static void
1186
 
xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1187
 
                             xmlXPathStepOpPtr op, int depth) {
1188
 
    int i;
1189
 
    char shift[100];
1190
 
 
1191
 
    for (i = 0;((i < depth) && (i < 25));i++)
1192
 
        shift[2 * i] = shift[2 * i + 1] = ' ';
1193
 
    shift[2 * i] = shift[2 * i + 1] = 0;
1194
 
 
1195
 
    fprintf(output, "%s", shift);
1196
 
    if (op == NULL) {
1197
 
        fprintf(output, "Step is NULL\n");
1198
 
        return;
1199
 
    }
1200
 
    switch (op->op) {
1201
 
        case XPATH_OP_END:
1202
 
            fprintf(output, "END"); break;
1203
 
        case XPATH_OP_AND:
1204
 
            fprintf(output, "AND"); break;
1205
 
        case XPATH_OP_OR:
1206
 
            fprintf(output, "OR"); break;
1207
 
        case XPATH_OP_EQUAL:
1208
 
             if (op->value)
1209
 
                 fprintf(output, "EQUAL =");
1210
 
             else
1211
 
                 fprintf(output, "EQUAL !=");
1212
 
             break;
1213
 
        case XPATH_OP_CMP:
1214
 
             if (op->value)
1215
 
                 fprintf(output, "CMP <");
1216
 
             else
1217
 
                 fprintf(output, "CMP >");
1218
 
             if (!op->value2)
1219
 
                 fprintf(output, "=");
1220
 
             break;
1221
 
        case XPATH_OP_PLUS:
1222
 
             if (op->value == 0)
1223
 
                 fprintf(output, "PLUS -");
1224
 
             else if (op->value == 1)
1225
 
                 fprintf(output, "PLUS +");
1226
 
             else if (op->value == 2)
1227
 
                 fprintf(output, "PLUS unary -");
1228
 
             else if (op->value == 3)
1229
 
                 fprintf(output, "PLUS unary - -");
1230
 
             break;
1231
 
        case XPATH_OP_MULT:
1232
 
             if (op->value == 0)
1233
 
                 fprintf(output, "MULT *");
1234
 
             else if (op->value == 1)
1235
 
                 fprintf(output, "MULT div");
1236
 
             else
1237
 
                 fprintf(output, "MULT mod");
1238
 
             break;
1239
 
        case XPATH_OP_UNION:
1240
 
             fprintf(output, "UNION"); break;
1241
 
        case XPATH_OP_ROOT:
1242
 
             fprintf(output, "ROOT"); break;
1243
 
        case XPATH_OP_NODE:
1244
 
             fprintf(output, "NODE"); break;
1245
 
        case XPATH_OP_RESET:
1246
 
             fprintf(output, "RESET"); break;
1247
 
        case XPATH_OP_SORT:
1248
 
             fprintf(output, "SORT"); break;
1249
 
        case XPATH_OP_COLLECT: {
1250
 
            xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1251
 
            xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1252
 
            xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1253
 
            const xmlChar *prefix = op->value4;
1254
 
            const xmlChar *name = op->value5;
1255
 
 
1256
 
            fprintf(output, "COLLECT ");
1257
 
            switch (axis) {
1258
 
                case AXIS_ANCESTOR:
1259
 
                    fprintf(output, " 'ancestors' "); break;
1260
 
                case AXIS_ANCESTOR_OR_SELF:
1261
 
                    fprintf(output, " 'ancestors-or-self' "); break;
1262
 
                case AXIS_ATTRIBUTE:
1263
 
                    fprintf(output, " 'attributes' "); break;
1264
 
                case AXIS_CHILD:
1265
 
                    fprintf(output, " 'child' "); break;
1266
 
                case AXIS_DESCENDANT:
1267
 
                    fprintf(output, " 'descendant' "); break;
1268
 
                case AXIS_DESCENDANT_OR_SELF:
1269
 
                    fprintf(output, " 'descendant-or-self' "); break;
1270
 
                case AXIS_FOLLOWING:
1271
 
                    fprintf(output, " 'following' "); break;
1272
 
                case AXIS_FOLLOWING_SIBLING:
1273
 
                    fprintf(output, " 'following-siblings' "); break;
1274
 
                case AXIS_NAMESPACE:
1275
 
                    fprintf(output, " 'namespace' "); break;
1276
 
                case AXIS_PARENT:
1277
 
                    fprintf(output, " 'parent' "); break;
1278
 
                case AXIS_PRECEDING:
1279
 
                    fprintf(output, " 'preceding' "); break;
1280
 
                case AXIS_PRECEDING_SIBLING:
1281
 
                    fprintf(output, " 'preceding-sibling' "); break;
1282
 
                case AXIS_SELF:
1283
 
                    fprintf(output, " 'self' "); break;
1284
 
            }
1285
 
            switch (test) {
1286
 
                case NODE_TEST_NONE:
1287
 
                    fprintf(output, "'none' "); break;
1288
 
                case NODE_TEST_TYPE:
1289
 
                    fprintf(output, "'type' "); break;
1290
 
                case NODE_TEST_PI:
1291
 
                    fprintf(output, "'PI' "); break;
1292
 
                case NODE_TEST_ALL:
1293
 
                    fprintf(output, "'all' "); break;
1294
 
                case NODE_TEST_NS:
1295
 
                    fprintf(output, "'namespace' "); break;
1296
 
                case NODE_TEST_NAME:
1297
 
                    fprintf(output, "'name' "); break;
1298
 
            }
1299
 
            switch (type) {
1300
 
                case NODE_TYPE_NODE:
1301
 
                    fprintf(output, "'node' "); break;
1302
 
                case NODE_TYPE_COMMENT:
1303
 
                    fprintf(output, "'comment' "); break;
1304
 
                case NODE_TYPE_TEXT:
1305
 
                    fprintf(output, "'text' "); break;
1306
 
                case NODE_TYPE_PI:
1307
 
                    fprintf(output, "'PI' "); break;
1308
 
            }
1309
 
            if (prefix != NULL)
1310
 
                fprintf(output, "%s:", prefix);
1311
 
            if (name != NULL)
1312
 
                fprintf(output, "%s", (const char *) name);
1313
 
            break;
1314
 
 
1315
 
        }
1316
 
        case XPATH_OP_VALUE: {
1317
 
            xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1318
 
 
1319
 
            fprintf(output, "ELEM ");
1320
 
            xmlXPathDebugDumpObject(output, object, 0);
1321
 
            goto finish;
1322
 
        }
1323
 
        case XPATH_OP_VARIABLE: {
1324
 
            const xmlChar *prefix = op->value5;
1325
 
            const xmlChar *name = op->value4;
1326
 
 
1327
 
            if (prefix != NULL)
1328
 
                fprintf(output, "VARIABLE %s:%s", prefix, name);
1329
 
            else
1330
 
                fprintf(output, "VARIABLE %s", name);
1331
 
            break;
1332
 
        }
1333
 
        case XPATH_OP_FUNCTION: {
1334
 
            int nbargs = op->value;
1335
 
            const xmlChar *prefix = op->value5;
1336
 
            const xmlChar *name = op->value4;
1337
 
 
1338
 
            if (prefix != NULL)
1339
 
                fprintf(output, "FUNCTION %s:%s(%d args)",
1340
 
                        prefix, name, nbargs);
1341
 
            else
1342
 
                fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1343
 
            break;
1344
 
        }
1345
 
        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1346
 
        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1347
 
        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1348
 
#ifdef LIBXML_XPTR_ENABLED
1349
 
        case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1350
 
#endif
1351
 
        default:
1352
 
        fprintf(output, "UNKNOWN %d\n", op->op); return;
1353
 
    }
1354
 
    fprintf(output, "\n");
1355
 
finish:
1356
 
    if (op->ch1 >= 0)
1357
 
        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1358
 
    if (op->ch2 >= 0)
1359
 
        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1360
 
}
1361
 
 
1362
 
/**
1363
 
 * xmlXPathDebugDumpCompExpr:
1364
 
 * @output:  the FILE * for the output
1365
 
 * @comp:  the precompiled XPath expression
1366
 
 * @depth:  the indentation level.
1367
 
 *
1368
 
 * Dumps the tree of the compiled XPath expression.
1369
 
 */
1370
 
void
1371
 
xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1372
 
                          int depth) {
1373
 
    int i;
1374
 
    char shift[100];
1375
 
 
1376
 
    if ((output == NULL) || (comp == NULL)) return;
1377
 
 
1378
 
    for (i = 0;((i < depth) && (i < 25));i++)
1379
 
        shift[2 * i] = shift[2 * i + 1] = ' ';
1380
 
    shift[2 * i] = shift[2 * i + 1] = 0;
1381
 
 
1382
 
    fprintf(output, "%s", shift);
1383
 
 
1384
 
    fprintf(output, "Compiled Expression : %d elements\n",
1385
 
            comp->nbStep);
1386
 
    i = comp->last;
1387
 
    xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1388
 
}
1389
 
 
1390
 
#ifdef XP_DEBUG_OBJ_USAGE
1391
 
 
1392
 
/*
1393
 
* XPath object usage related debugging variables.
1394
 
*/
1395
 
static int xmlXPathDebugObjCounterUndefined = 0;
1396
 
static int xmlXPathDebugObjCounterNodeset = 0;
1397
 
static int xmlXPathDebugObjCounterBool = 0;
1398
 
static int xmlXPathDebugObjCounterNumber = 0;
1399
 
static int xmlXPathDebugObjCounterString = 0;
1400
 
static int xmlXPathDebugObjCounterPoint = 0;
1401
 
static int xmlXPathDebugObjCounterRange = 0;
1402
 
static int xmlXPathDebugObjCounterLocset = 0;
1403
 
static int xmlXPathDebugObjCounterUsers = 0;
1404
 
static int xmlXPathDebugObjCounterXSLTTree = 0;
1405
 
static int xmlXPathDebugObjCounterAll = 0;
1406
 
 
1407
 
static int xmlXPathDebugObjTotalUndefined = 0;
1408
 
static int xmlXPathDebugObjTotalNodeset = 0;
1409
 
static int xmlXPathDebugObjTotalBool = 0;
1410
 
static int xmlXPathDebugObjTotalNumber = 0;
1411
 
static int xmlXPathDebugObjTotalString = 0;
1412
 
static int xmlXPathDebugObjTotalPoint = 0;
1413
 
static int xmlXPathDebugObjTotalRange = 0;
1414
 
static int xmlXPathDebugObjTotalLocset = 0;
1415
 
static int xmlXPathDebugObjTotalUsers = 0;
1416
 
static int xmlXPathDebugObjTotalXSLTTree = 0;
1417
 
static int xmlXPathDebugObjTotalAll = 0;
1418
 
 
1419
 
static int xmlXPathDebugObjMaxUndefined = 0;
1420
 
static int xmlXPathDebugObjMaxNodeset = 0;
1421
 
static int xmlXPathDebugObjMaxBool = 0;
1422
 
static int xmlXPathDebugObjMaxNumber = 0;
1423
 
static int xmlXPathDebugObjMaxString = 0;
1424
 
static int xmlXPathDebugObjMaxPoint = 0;
1425
 
static int xmlXPathDebugObjMaxRange = 0;
1426
 
static int xmlXPathDebugObjMaxLocset = 0;
1427
 
static int xmlXPathDebugObjMaxUsers = 0;
1428
 
static int xmlXPathDebugObjMaxXSLTTree = 0;
1429
 
static int xmlXPathDebugObjMaxAll = 0;
1430
 
 
1431
 
/* REVISIT TODO: Make this static when committing */
1432
 
static void
1433
 
xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1434
 
{
1435
 
    if (ctxt != NULL) {
1436
 
        if (ctxt->cache != NULL) {
1437
 
            xmlXPathContextCachePtr cache =
1438
 
                (xmlXPathContextCachePtr) ctxt->cache;
1439
 
 
1440
 
            cache->dbgCachedAll = 0;
1441
 
            cache->dbgCachedNodeset = 0;
1442
 
            cache->dbgCachedString = 0;
1443
 
            cache->dbgCachedBool = 0;
1444
 
            cache->dbgCachedNumber = 0;
1445
 
            cache->dbgCachedPoint = 0;
1446
 
            cache->dbgCachedRange = 0;
1447
 
            cache->dbgCachedLocset = 0;
1448
 
            cache->dbgCachedUsers = 0;
1449
 
            cache->dbgCachedXSLTTree = 0;
1450
 
            cache->dbgCachedUndefined = 0;
1451
 
 
1452
 
            cache->dbgReusedAll = 0;
1453
 
            cache->dbgReusedNodeset = 0;
1454
 
            cache->dbgReusedString = 0;
1455
 
            cache->dbgReusedBool = 0;
1456
 
            cache->dbgReusedNumber = 0;
1457
 
            cache->dbgReusedPoint = 0;
1458
 
            cache->dbgReusedRange = 0;
1459
 
            cache->dbgReusedLocset = 0;
1460
 
            cache->dbgReusedUsers = 0;
1461
 
            cache->dbgReusedXSLTTree = 0;
1462
 
            cache->dbgReusedUndefined = 0;
1463
 
        }
1464
 
    }
1465
 
 
1466
 
    xmlXPathDebugObjCounterUndefined = 0;
1467
 
    xmlXPathDebugObjCounterNodeset = 0;
1468
 
    xmlXPathDebugObjCounterBool = 0;
1469
 
    xmlXPathDebugObjCounterNumber = 0;
1470
 
    xmlXPathDebugObjCounterString = 0;
1471
 
    xmlXPathDebugObjCounterPoint = 0;
1472
 
    xmlXPathDebugObjCounterRange = 0;
1473
 
    xmlXPathDebugObjCounterLocset = 0;
1474
 
    xmlXPathDebugObjCounterUsers = 0;
1475
 
    xmlXPathDebugObjCounterXSLTTree = 0;
1476
 
    xmlXPathDebugObjCounterAll = 0;
1477
 
 
1478
 
    xmlXPathDebugObjTotalUndefined = 0;
1479
 
    xmlXPathDebugObjTotalNodeset = 0;
1480
 
    xmlXPathDebugObjTotalBool = 0;
1481
 
    xmlXPathDebugObjTotalNumber = 0;
1482
 
    xmlXPathDebugObjTotalString = 0;
1483
 
    xmlXPathDebugObjTotalPoint = 0;
1484
 
    xmlXPathDebugObjTotalRange = 0;
1485
 
    xmlXPathDebugObjTotalLocset = 0;
1486
 
    xmlXPathDebugObjTotalUsers = 0;
1487
 
    xmlXPathDebugObjTotalXSLTTree = 0;
1488
 
    xmlXPathDebugObjTotalAll = 0;
1489
 
 
1490
 
    xmlXPathDebugObjMaxUndefined = 0;
1491
 
    xmlXPathDebugObjMaxNodeset = 0;
1492
 
    xmlXPathDebugObjMaxBool = 0;
1493
 
    xmlXPathDebugObjMaxNumber = 0;
1494
 
    xmlXPathDebugObjMaxString = 0;
1495
 
    xmlXPathDebugObjMaxPoint = 0;
1496
 
    xmlXPathDebugObjMaxRange = 0;
1497
 
    xmlXPathDebugObjMaxLocset = 0;
1498
 
    xmlXPathDebugObjMaxUsers = 0;
1499
 
    xmlXPathDebugObjMaxXSLTTree = 0;
1500
 
    xmlXPathDebugObjMaxAll = 0;
1501
 
 
1502
 
}
1503
 
 
1504
 
static void
1505
 
xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1506
 
                              xmlXPathObjectType objType)
1507
 
{
1508
 
    int isCached = 0;
1509
 
 
1510
 
    if (ctxt != NULL) {
1511
 
        if (ctxt->cache != NULL) {
1512
 
            xmlXPathContextCachePtr cache =
1513
 
                (xmlXPathContextCachePtr) ctxt->cache;
1514
 
 
1515
 
            isCached = 1;
1516
 
 
1517
 
            cache->dbgReusedAll++;
1518
 
            switch (objType) {
1519
 
                case XPATH_UNDEFINED:
1520
 
                    cache->dbgReusedUndefined++;
1521
 
                    break;
1522
 
                case XPATH_NODESET:
1523
 
                    cache->dbgReusedNodeset++;
1524
 
                    break;
1525
 
                case XPATH_BOOLEAN:
1526
 
                    cache->dbgReusedBool++;
1527
 
                    break;
1528
 
                case XPATH_NUMBER:
1529
 
                    cache->dbgReusedNumber++;
1530
 
                    break;
1531
 
                case XPATH_STRING:
1532
 
                    cache->dbgReusedString++;
1533
 
                    break;
1534
 
                case XPATH_POINT:
1535
 
                    cache->dbgReusedPoint++;
1536
 
                    break;
1537
 
                case XPATH_RANGE:
1538
 
                    cache->dbgReusedRange++;
1539
 
                    break;
1540
 
                case XPATH_LOCATIONSET:
1541
 
                    cache->dbgReusedLocset++;
1542
 
                    break;
1543
 
                case XPATH_USERS:
1544
 
                    cache->dbgReusedUsers++;
1545
 
                    break;
1546
 
                case XPATH_XSLT_TREE:
1547
 
                    cache->dbgReusedXSLTTree++;
1548
 
                    break;
1549
 
                default:
1550
 
                    break;
1551
 
            }
1552
 
        }
1553
 
    }
1554
 
 
1555
 
    switch (objType) {
1556
 
        case XPATH_UNDEFINED:
1557
 
            if (! isCached)
1558
 
                xmlXPathDebugObjTotalUndefined++;
1559
 
            xmlXPathDebugObjCounterUndefined++;
1560
 
            if (xmlXPathDebugObjCounterUndefined >
1561
 
                xmlXPathDebugObjMaxUndefined)
1562
 
                xmlXPathDebugObjMaxUndefined =
1563
 
                    xmlXPathDebugObjCounterUndefined;
1564
 
            break;
1565
 
        case XPATH_NODESET:
1566
 
            if (! isCached)
1567
 
                xmlXPathDebugObjTotalNodeset++;
1568
 
            xmlXPathDebugObjCounterNodeset++;
1569
 
            if (xmlXPathDebugObjCounterNodeset >
1570
 
                xmlXPathDebugObjMaxNodeset)
1571
 
                xmlXPathDebugObjMaxNodeset =
1572
 
                    xmlXPathDebugObjCounterNodeset;
1573
 
            break;
1574
 
        case XPATH_BOOLEAN:
1575
 
            if (! isCached)
1576
 
                xmlXPathDebugObjTotalBool++;
1577
 
            xmlXPathDebugObjCounterBool++;
1578
 
            if (xmlXPathDebugObjCounterBool >
1579
 
                xmlXPathDebugObjMaxBool)
1580
 
                xmlXPathDebugObjMaxBool =
1581
 
                    xmlXPathDebugObjCounterBool;
1582
 
            break;
1583
 
        case XPATH_NUMBER:
1584
 
            if (! isCached)
1585
 
                xmlXPathDebugObjTotalNumber++;
1586
 
            xmlXPathDebugObjCounterNumber++;
1587
 
            if (xmlXPathDebugObjCounterNumber >
1588
 
                xmlXPathDebugObjMaxNumber)
1589
 
                xmlXPathDebugObjMaxNumber =
1590
 
                    xmlXPathDebugObjCounterNumber;
1591
 
            break;
1592
 
        case XPATH_STRING:
1593
 
            if (! isCached)
1594
 
                xmlXPathDebugObjTotalString++;
1595
 
            xmlXPathDebugObjCounterString++;
1596
 
            if (xmlXPathDebugObjCounterString >
1597
 
                xmlXPathDebugObjMaxString)
1598
 
                xmlXPathDebugObjMaxString =
1599
 
                    xmlXPathDebugObjCounterString;
1600
 
            break;
1601
 
        case XPATH_POINT:
1602
 
            if (! isCached)
1603
 
                xmlXPathDebugObjTotalPoint++;
1604
 
            xmlXPathDebugObjCounterPoint++;
1605
 
            if (xmlXPathDebugObjCounterPoint >
1606
 
                xmlXPathDebugObjMaxPoint)
1607
 
                xmlXPathDebugObjMaxPoint =
1608
 
                    xmlXPathDebugObjCounterPoint;
1609
 
            break;
1610
 
        case XPATH_RANGE:
1611
 
            if (! isCached)
1612
 
                xmlXPathDebugObjTotalRange++;
1613
 
            xmlXPathDebugObjCounterRange++;
1614
 
            if (xmlXPathDebugObjCounterRange >
1615
 
                xmlXPathDebugObjMaxRange)
1616
 
                xmlXPathDebugObjMaxRange =
1617
 
                    xmlXPathDebugObjCounterRange;
1618
 
            break;
1619
 
        case XPATH_LOCATIONSET:
1620
 
            if (! isCached)
1621
 
                xmlXPathDebugObjTotalLocset++;
1622
 
            xmlXPathDebugObjCounterLocset++;
1623
 
            if (xmlXPathDebugObjCounterLocset >
1624
 
                xmlXPathDebugObjMaxLocset)
1625
 
                xmlXPathDebugObjMaxLocset =
1626
 
                    xmlXPathDebugObjCounterLocset;
1627
 
            break;
1628
 
        case XPATH_USERS:
1629
 
            if (! isCached)
1630
 
                xmlXPathDebugObjTotalUsers++;
1631
 
            xmlXPathDebugObjCounterUsers++;
1632
 
            if (xmlXPathDebugObjCounterUsers >
1633
 
                xmlXPathDebugObjMaxUsers)
1634
 
                xmlXPathDebugObjMaxUsers =
1635
 
                    xmlXPathDebugObjCounterUsers;
1636
 
            break;
1637
 
        case XPATH_XSLT_TREE:
1638
 
            if (! isCached)
1639
 
                xmlXPathDebugObjTotalXSLTTree++;
1640
 
            xmlXPathDebugObjCounterXSLTTree++;
1641
 
            if (xmlXPathDebugObjCounterXSLTTree >
1642
 
                xmlXPathDebugObjMaxXSLTTree)
1643
 
                xmlXPathDebugObjMaxXSLTTree =
1644
 
                    xmlXPathDebugObjCounterXSLTTree;
1645
 
            break;
1646
 
        default:
1647
 
            break;
1648
 
    }
1649
 
    if (! isCached)
1650
 
        xmlXPathDebugObjTotalAll++;
1651
 
    xmlXPathDebugObjCounterAll++;
1652
 
    if (xmlXPathDebugObjCounterAll >
1653
 
        xmlXPathDebugObjMaxAll)
1654
 
        xmlXPathDebugObjMaxAll =
1655
 
            xmlXPathDebugObjCounterAll;
1656
 
}
1657
 
 
1658
 
static void
1659
 
xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1660
 
                              xmlXPathObjectType objType)
1661
 
{
1662
 
    int isCached = 0;
1663
 
 
1664
 
    if (ctxt != NULL) {
1665
 
        if (ctxt->cache != NULL) {
1666
 
            xmlXPathContextCachePtr cache =
1667
 
                (xmlXPathContextCachePtr) ctxt->cache;
1668
 
 
1669
 
            isCached = 1;
1670
 
 
1671
 
            cache->dbgCachedAll++;
1672
 
            switch (objType) {
1673
 
                case XPATH_UNDEFINED:
1674
 
                    cache->dbgCachedUndefined++;
1675
 
                    break;
1676
 
                case XPATH_NODESET:
1677
 
                    cache->dbgCachedNodeset++;
1678
 
                    break;
1679
 
                case XPATH_BOOLEAN:
1680
 
                    cache->dbgCachedBool++;
1681
 
                    break;
1682
 
                case XPATH_NUMBER:
1683
 
                    cache->dbgCachedNumber++;
1684
 
                    break;
1685
 
                case XPATH_STRING:
1686
 
                    cache->dbgCachedString++;
1687
 
                    break;
1688
 
                case XPATH_POINT:
1689
 
                    cache->dbgCachedPoint++;
1690
 
                    break;
1691
 
                case XPATH_RANGE:
1692
 
                    cache->dbgCachedRange++;
1693
 
                    break;
1694
 
                case XPATH_LOCATIONSET:
1695
 
                    cache->dbgCachedLocset++;
1696
 
                    break;
1697
 
                case XPATH_USERS:
1698
 
                    cache->dbgCachedUsers++;
1699
 
                    break;
1700
 
                case XPATH_XSLT_TREE:
1701
 
                    cache->dbgCachedXSLTTree++;
1702
 
                    break;
1703
 
                default:
1704
 
                    break;
1705
 
            }
1706
 
 
1707
 
        }
1708
 
    }
1709
 
    switch (objType) {
1710
 
        case XPATH_UNDEFINED:
1711
 
            xmlXPathDebugObjCounterUndefined--;
1712
 
            break;
1713
 
        case XPATH_NODESET:
1714
 
            xmlXPathDebugObjCounterNodeset--;
1715
 
            break;
1716
 
        case XPATH_BOOLEAN:
1717
 
            xmlXPathDebugObjCounterBool--;
1718
 
            break;
1719
 
        case XPATH_NUMBER:
1720
 
            xmlXPathDebugObjCounterNumber--;
1721
 
            break;
1722
 
        case XPATH_STRING:
1723
 
            xmlXPathDebugObjCounterString--;
1724
 
            break;
1725
 
        case XPATH_POINT:
1726
 
            xmlXPathDebugObjCounterPoint--;
1727
 
            break;
1728
 
        case XPATH_RANGE:
1729
 
            xmlXPathDebugObjCounterRange--;
1730
 
            break;
1731
 
        case XPATH_LOCATIONSET:
1732
 
            xmlXPathDebugObjCounterLocset--;
1733
 
            break;
1734
 
        case XPATH_USERS:
1735
 
            xmlXPathDebugObjCounterUsers--;
1736
 
            break;
1737
 
        case XPATH_XSLT_TREE:
1738
 
            xmlXPathDebugObjCounterXSLTTree--;
1739
 
            break;
1740
 
        default:
1741
 
            break;
1742
 
    }
1743
 
    xmlXPathDebugObjCounterAll--;
1744
 
}
1745
 
 
1746
 
/* REVISIT TODO: Make this static when committing */
1747
 
static void
1748
 
xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1749
 
{
1750
 
    int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1751
 
        reqXSLTTree, reqUndefined;
1752
 
    int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1753
 
        caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1754
 
    int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1755
 
        reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1756
 
    int leftObjs = xmlXPathDebugObjCounterAll;
1757
 
 
1758
 
    reqAll = xmlXPathDebugObjTotalAll;
1759
 
    reqNodeset = xmlXPathDebugObjTotalNodeset;
1760
 
    reqString = xmlXPathDebugObjTotalString;
1761
 
    reqBool = xmlXPathDebugObjTotalBool;
1762
 
    reqNumber = xmlXPathDebugObjTotalNumber;
1763
 
    reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1764
 
    reqUndefined = xmlXPathDebugObjTotalUndefined;
1765
 
 
1766
 
    printf("# XPath object usage:\n");
1767
 
 
1768
 
    if (ctxt != NULL) {
1769
 
        if (ctxt->cache != NULL) {
1770
 
            xmlXPathContextCachePtr cache =
1771
 
                (xmlXPathContextCachePtr) ctxt->cache;
1772
 
 
1773
 
            reAll = cache->dbgReusedAll;
1774
 
            reqAll += reAll;
1775
 
            reNodeset = cache->dbgReusedNodeset;
1776
 
            reqNodeset += reNodeset;
1777
 
            reString = cache->dbgReusedString;
1778
 
            reqString += reString;
1779
 
            reBool = cache->dbgReusedBool;
1780
 
            reqBool += reBool;
1781
 
            reNumber = cache->dbgReusedNumber;
1782
 
            reqNumber += reNumber;
1783
 
            reXSLTTree = cache->dbgReusedXSLTTree;
1784
 
            reqXSLTTree += reXSLTTree;
1785
 
            reUndefined = cache->dbgReusedUndefined;
1786
 
            reqUndefined += reUndefined;
1787
 
 
1788
 
            caAll = cache->dbgCachedAll;
1789
 
            caBool = cache->dbgCachedBool;
1790
 
            caNodeset = cache->dbgCachedNodeset;
1791
 
            caString = cache->dbgCachedString;
1792
 
            caNumber = cache->dbgCachedNumber;
1793
 
            caXSLTTree = cache->dbgCachedXSLTTree;
1794
 
            caUndefined = cache->dbgCachedUndefined;
1795
 
 
1796
 
            if (cache->nodesetObjs)
1797
 
                leftObjs -= cache->nodesetObjs->number;
1798
 
            if (cache->stringObjs)
1799
 
                leftObjs -= cache->stringObjs->number;
1800
 
            if (cache->booleanObjs)
1801
 
                leftObjs -= cache->booleanObjs->number;
1802
 
            if (cache->numberObjs)
1803
 
                leftObjs -= cache->numberObjs->number;
1804
 
            if (cache->miscObjs)
1805
 
                leftObjs -= cache->miscObjs->number;
1806
 
        }
1807
 
    }
1808
 
 
1809
 
    printf("# all\n");
1810
 
    printf("#   total  : %d\n", reqAll);
1811
 
    printf("#   left  : %d\n", leftObjs);
1812
 
    printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
1813
 
    printf("#   reused : %d\n", reAll);
1814
 
    printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
1815
 
 
1816
 
    printf("# node-sets\n");
1817
 
    printf("#   total  : %d\n", reqNodeset);
1818
 
    printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
1819
 
    printf("#   reused : %d\n", reNodeset);
1820
 
    printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
1821
 
 
1822
 
    printf("# strings\n");
1823
 
    printf("#   total  : %d\n", reqString);
1824
 
    printf("#   created: %d\n", xmlXPathDebugObjTotalString);
1825
 
    printf("#   reused : %d\n", reString);
1826
 
    printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
1827
 
 
1828
 
    printf("# booleans\n");
1829
 
    printf("#   total  : %d\n", reqBool);
1830
 
    printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
1831
 
    printf("#   reused : %d\n", reBool);
1832
 
    printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
1833
 
 
1834
 
    printf("# numbers\n");
1835
 
    printf("#   total  : %d\n", reqNumber);
1836
 
    printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
1837
 
    printf("#   reused : %d\n", reNumber);
1838
 
    printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
1839
 
 
1840
 
    printf("# XSLT result tree fragments\n");
1841
 
    printf("#   total  : %d\n", reqXSLTTree);
1842
 
    printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1843
 
    printf("#   reused : %d\n", reXSLTTree);
1844
 
    printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
1845
 
 
1846
 
    printf("# undefined\n");
1847
 
    printf("#   total  : %d\n", reqUndefined);
1848
 
    printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
1849
 
    printf("#   reused : %d\n", reUndefined);
1850
 
    printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
1851
 
 
1852
 
}
1853
 
 
1854
 
#endif /* XP_DEBUG_OBJ_USAGE */
1855
 
 
1856
 
#endif /* LIBXML_DEBUG_ENABLED */
1857
 
 
1858
 
/************************************************************************
1859
 
 *                                                                      *
1860
 
 *                      XPath object caching                            *
1861
 
 *                                                                      *
1862
 
 ************************************************************************/
1863
 
 
1864
 
/**
1865
 
 * xmlXPathNewCache:
1866
 
 *
1867
 
 * Create a new object cache
1868
 
 *
1869
 
 * Returns the xmlXPathCache just allocated.
1870
 
 */
1871
 
static xmlXPathContextCachePtr
1872
 
xmlXPathNewCache(void)
1873
 
{
1874
 
    xmlXPathContextCachePtr ret;
1875
 
 
1876
 
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1877
 
    if (ret == NULL) {
1878
 
        xmlXPathErrMemory(NULL, "creating object cache\n");
1879
 
        return(NULL);
1880
 
    }
1881
 
    memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
1882
 
    ret->maxNodeset = 100;
1883
 
    ret->maxString = 100;
1884
 
    ret->maxBoolean = 100;
1885
 
    ret->maxNumber = 100;
1886
 
    ret->maxMisc = 100;
1887
 
    return(ret);
1888
 
}
1889
 
 
1890
 
static void
1891
 
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
1892
 
{
1893
 
    int i;
1894
 
    xmlXPathObjectPtr obj;
1895
 
 
1896
 
    if (list == NULL)
1897
 
        return;
1898
 
 
1899
 
    for (i = 0; i < list->number; i++) {
1900
 
        obj = list->items[i];
1901
 
        /*
1902
 
        * Note that it is already assured that we don't need to
1903
 
        * look out for namespace nodes in the node-set.
1904
 
        */
1905
 
        if (obj->nodesetval != NULL) {
1906
 
            if (obj->nodesetval->nodeTab != NULL)
1907
 
                xmlFree(obj->nodesetval->nodeTab);
1908
 
            xmlFree(obj->nodesetval);
1909
 
        }
1910
 
        xmlFree(obj);
1911
 
#ifdef XP_DEBUG_OBJ_USAGE
1912
 
        xmlXPathDebugObjCounterAll--;
1913
 
#endif
1914
 
    }
1915
 
    xmlPointerListFree(list);
1916
 
}
1917
 
 
1918
 
static void
1919
 
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1920
 
{
1921
 
    if (cache == NULL)
1922
 
        return;
1923
 
    if (cache->nodesetObjs)
1924
 
        xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1925
 
    if (cache->stringObjs)
1926
 
        xmlXPathCacheFreeObjectList(cache->stringObjs);
1927
 
    if (cache->booleanObjs)
1928
 
        xmlXPathCacheFreeObjectList(cache->booleanObjs);
1929
 
    if (cache->numberObjs)
1930
 
        xmlXPathCacheFreeObjectList(cache->numberObjs);
1931
 
    if (cache->miscObjs)
1932
 
        xmlXPathCacheFreeObjectList(cache->miscObjs);
1933
 
    xmlFree(cache);
1934
 
}
1935
 
 
1936
 
/**
1937
 
 * xmlXPathContextSetCache:
1938
 
 *
1939
 
 * @ctxt:  the XPath context
1940
 
 * @active: enables/disables (creates/frees) the cache
1941
 
 * @value: a value with semantics dependant on @options
1942
 
 * @options: options (currently only the value 0 is used)
1943
 
 *
1944
 
 * Creates/frees an object cache on the XPath context.
1945
 
 * If activates XPath objects (xmlXPathObject) will be cached internally
1946
 
 * to be reused.
1947
 
 * @options:
1948
 
 *   0: This will set the XPath object caching:
1949
 
 *      @value:
1950
 
 *        This will set the maximum number of XPath objects
1951
 
 *        to be cached per slot
1952
 
 *        There are 5 slots for: node-set, string, number, boolean, and
1953
 
 *        misc objects. Use <0 for the default number (100).
1954
 
 *   Other values for @options have currently no effect.
1955
 
 *
1956
 
 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1957
 
 */
1958
 
int
1959
 
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1960
 
                        int active,
1961
 
                        int value,
1962
 
                        int options)
1963
 
{
1964
 
    if (ctxt == NULL)
1965
 
        return(-1);
1966
 
    if (active) {
1967
 
        xmlXPathContextCachePtr cache;
1968
 
 
1969
 
        if (ctxt->cache == NULL) {
1970
 
            ctxt->cache = xmlXPathNewCache();
1971
 
            if (ctxt->cache == NULL)
1972
 
                return(-1);
1973
 
        }
1974
 
        cache = (xmlXPathContextCachePtr) ctxt->cache;
1975
 
        if (options == 0) {
1976
 
            if (value < 0)
1977
 
                value = 100;
1978
 
            cache->maxNodeset = value;
1979
 
            cache->maxString = value;
1980
 
            cache->maxNumber = value;
1981
 
            cache->maxBoolean = value;
1982
 
            cache->maxMisc = value;
1983
 
        }
1984
 
    } else if (ctxt->cache != NULL) {
1985
 
        xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1986
 
        ctxt->cache = NULL;
1987
 
    }
1988
 
    return(0);
1989
 
}
1990
 
 
1991
 
/**
1992
 
 * xmlXPathCacheWrapNodeSet:
1993
 
 * @ctxt: the XPath context
1994
 
 * @val:  the NodePtr value
1995
 
 *
1996
 
 * This is the cached version of xmlXPathWrapNodeSet().
1997
 
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1998
 
 *
1999
 
 * Returns the created or reused object.
2000
 
 */
2001
 
static xmlXPathObjectPtr
2002
 
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2003
 
{
2004
 
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2005
 
        xmlXPathContextCachePtr cache =
2006
 
            (xmlXPathContextCachePtr) ctxt->cache;
2007
 
 
2008
 
        if ((cache->miscObjs != NULL) &&
2009
 
            (cache->miscObjs->number != 0))
2010
 
        {
2011
 
            xmlXPathObjectPtr ret;
2012
 
 
2013
 
            ret = (xmlXPathObjectPtr)
2014
 
                cache->miscObjs->items[--cache->miscObjs->number];
2015
 
            ret->type = XPATH_NODESET;
2016
 
            ret->nodesetval = val;
2017
 
#ifdef XP_DEBUG_OBJ_USAGE
2018
 
            xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2019
 
#endif
2020
 
            return(ret);
2021
 
        }
2022
 
    }
2023
 
 
2024
 
    return(xmlXPathWrapNodeSet(val));
2025
 
 
2026
 
}
2027
 
 
2028
 
/**
2029
 
 * xmlXPathCacheWrapString:
2030
 
 * @ctxt: the XPath context
2031
 
 * @val:  the xmlChar * value
2032
 
 *
2033
 
 * This is the cached version of xmlXPathWrapString().
2034
 
 * Wraps the @val string into an XPath object.
2035
 
 *
2036
 
 * Returns the created or reused object.
2037
 
 */
2038
 
static xmlXPathObjectPtr
2039
 
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2040
 
{
2041
 
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2042
 
        xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2043
 
 
2044
 
        if ((cache->stringObjs != NULL) &&
2045
 
            (cache->stringObjs->number != 0))
2046
 
        {
2047
 
 
2048
 
            xmlXPathObjectPtr ret;
2049
 
 
2050
 
            ret = (xmlXPathObjectPtr)
2051
 
                cache->stringObjs->items[--cache->stringObjs->number];
2052
 
            ret->type = XPATH_STRING;
2053
 
            ret->stringval = val;
2054
 
#ifdef XP_DEBUG_OBJ_USAGE
2055
 
            xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2056
 
#endif
2057
 
            return(ret);
2058
 
        } else if ((cache->miscObjs != NULL) &&
2059
 
            (cache->miscObjs->number != 0))
2060
 
        {
2061
 
            xmlXPathObjectPtr ret;
2062
 
            /*
2063
 
            * Fallback to misc-cache.
2064
 
            */
2065
 
            ret = (xmlXPathObjectPtr)
2066
 
                cache->miscObjs->items[--cache->miscObjs->number];
2067
 
 
2068
 
            ret->type = XPATH_STRING;
2069
 
            ret->stringval = val;
2070
 
#ifdef XP_DEBUG_OBJ_USAGE
2071
 
            xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2072
 
#endif
2073
 
            return(ret);
2074
 
        }
2075
 
    }
2076
 
    return(xmlXPathWrapString(val));
2077
 
}
2078
 
 
2079
 
/**
2080
 
 * xmlXPathCacheNewNodeSet:
2081
 
 * @ctxt: the XPath context
2082
 
 * @val:  the NodePtr value
2083
 
 *
2084
 
 * This is the cached version of xmlXPathNewNodeSet().
2085
 
 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2086
 
 * it with the single Node @val
2087
 
 *
2088
 
 * Returns the created or reused object.
2089
 
 */
2090
 
static xmlXPathObjectPtr
2091
 
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2092
 
{
2093
 
    if ((ctxt != NULL) && (ctxt->cache)) {
2094
 
        xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2095
 
 
2096
 
        if ((cache->nodesetObjs != NULL) &&
2097
 
            (cache->nodesetObjs->number != 0))
2098
 
        {
2099
 
            xmlXPathObjectPtr ret;
2100
 
            /*
2101
 
            * Use the nodset-cache.
2102
 
            */
2103
 
            ret = (xmlXPathObjectPtr)
2104
 
                cache->nodesetObjs->items[--cache->nodesetObjs->number];
2105
 
            ret->type = XPATH_NODESET;
2106
 
            ret->boolval = 0;
2107
 
            if (val) {
2108
 
                if ((ret->nodesetval->nodeMax == 0) ||
2109
 
                    (val->type == XML_NAMESPACE_DECL))
2110
 
                {
2111
 
                    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2112
 
                } else {
2113
 
                    ret->nodesetval->nodeTab[0] = val;
2114
 
                    ret->nodesetval->nodeNr = 1;
2115
 
                }
2116
 
            }
2117
 
#ifdef XP_DEBUG_OBJ_USAGE
2118
 
            xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2119
 
#endif
2120
 
            return(ret);
2121
 
        } else if ((cache->miscObjs != NULL) &&
2122
 
            (cache->miscObjs->number != 0))
2123
 
        {
2124
 
            xmlXPathObjectPtr ret;
2125
 
            /*
2126
 
            * Fallback to misc-cache.
2127
 
            */
2128
 
 
2129
 
            ret = (xmlXPathObjectPtr)
2130
 
                cache->miscObjs->items[--cache->miscObjs->number];
2131
 
 
2132
 
            ret->type = XPATH_NODESET;
2133
 
            ret->boolval = 0;
2134
 
            ret->nodesetval = xmlXPathNodeSetCreate(val);
2135
 
            if (ret->nodesetval == NULL) {
2136
 
                ctxt->lastError.domain = XML_FROM_XPATH;
2137
 
                ctxt->lastError.code = XML_ERR_NO_MEMORY;
2138
 
                return(NULL);
2139
 
            }
2140
 
#ifdef XP_DEBUG_OBJ_USAGE
2141
 
            xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2142
 
#endif
2143
 
            return(ret);
2144
 
        }
2145
 
    }
2146
 
    return(xmlXPathNewNodeSet(val));
2147
 
}
2148
 
 
2149
 
/**
2150
 
 * xmlXPathCacheNewCString:
2151
 
 * @ctxt: the XPath context
2152
 
 * @val:  the char * value
2153
 
 *
2154
 
 * This is the cached version of xmlXPathNewCString().
2155
 
 * Acquire an xmlXPathObjectPtr of type string and of value @val
2156
 
 *
2157
 
 * Returns the created or reused object.
2158
 
 */
2159
 
static xmlXPathObjectPtr
2160
 
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2161
 
{
2162
 
    if ((ctxt != NULL) && (ctxt->cache)) {
2163
 
        xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2164
 
 
2165
 
        if ((cache->stringObjs != NULL) &&
2166
 
            (cache->stringObjs->number != 0))
2167
 
        {
2168
 
            xmlXPathObjectPtr ret;
2169
 
 
2170
 
            ret = (xmlXPathObjectPtr)
2171
 
                cache->stringObjs->items[--cache->stringObjs->number];
2172
 
 
2173
 
            ret->type = XPATH_STRING;
2174
 
            ret->stringval = xmlStrdup(BAD_CAST val);
2175
 
#ifdef XP_DEBUG_OBJ_USAGE
2176
 
            xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2177
 
#endif
2178
 
            return(ret);
2179
 
        } else if ((cache->miscObjs != NULL) &&
2180
 
            (cache->miscObjs->number != 0))
2181
 
        {
2182
 
            xmlXPathObjectPtr ret;
2183
 
 
2184
 
            ret = (xmlXPathObjectPtr)
2185
 
                cache->miscObjs->items[--cache->miscObjs->number];
2186
 
 
2187
 
            ret->type = XPATH_STRING;
2188
 
            ret->stringval = xmlStrdup(BAD_CAST val);
2189
 
#ifdef XP_DEBUG_OBJ_USAGE
2190
 
            xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2191
 
#endif
2192
 
            return(ret);
2193
 
        }
2194
 
    }
2195
 
    return(xmlXPathNewCString(val));
2196
 
}
2197
 
 
2198
 
/**
2199
 
 * xmlXPathCacheNewString:
2200
 
 * @ctxt: the XPath context
2201
 
 * @val:  the xmlChar * value
2202
 
 *
2203
 
 * This is the cached version of xmlXPathNewString().
2204
 
 * Acquire an xmlXPathObjectPtr of type string and of value @val
2205
 
 *
2206
 
 * Returns the created or reused object.
2207
 
 */
2208
 
static xmlXPathObjectPtr
2209
 
xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2210
 
{
2211
 
    if ((ctxt != NULL) && (ctxt->cache)) {
2212
 
        xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2213
 
 
2214
 
        if ((cache->stringObjs != NULL) &&
2215
 
            (cache->stringObjs->number != 0))
2216
 
        {
2217
 
            xmlXPathObjectPtr ret;
2218
 
 
2219
 
            ret = (xmlXPathObjectPtr)
2220
 
                cache->stringObjs->items[--cache->stringObjs->number];
2221
 
            ret->type = XPATH_STRING;
2222
 
            if (val != NULL)
2223
 
                ret->stringval = xmlStrdup(val);
2224
 
            else
2225
 
                ret->stringval = xmlStrdup((const xmlChar *)"");
2226
 
#ifdef XP_DEBUG_OBJ_USAGE
2227
 
            xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2228
 
#endif
2229
 
            return(ret);
2230
 
        } else if ((cache->miscObjs != NULL) &&
2231
 
            (cache->miscObjs->number != 0))
2232
 
        {
2233
 
            xmlXPathObjectPtr ret;
2234
 
 
2235
 
            ret = (xmlXPathObjectPtr)
2236
 
                cache->miscObjs->items[--cache->miscObjs->number];
2237
 
 
2238
 
            ret->type = XPATH_STRING;
2239
 
            if (val != NULL)
2240
 
                ret->stringval = xmlStrdup(val);
2241
 
            else
2242
 
                ret->stringval = xmlStrdup((const xmlChar *)"");
2243
 
#ifdef XP_DEBUG_OBJ_USAGE
2244
 
            xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2245
 
#endif
2246
 
            return(ret);
2247
 
        }
2248
 
    }
2249
 
    return(xmlXPathNewString(val));
2250
 
}
2251
 
 
2252
 
/**
2253
 
 * xmlXPathCacheNewBoolean:
2254
 
 * @ctxt: the XPath context
2255
 
 * @val:  the boolean value
2256
 
 *
2257
 
 * This is the cached version of xmlXPathNewBoolean().
2258
 
 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2259
 
 *
2260
 
 * Returns the created or reused object.
2261
 
 */
2262
 
static xmlXPathObjectPtr
2263
 
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2264
 
{
2265
 
    if ((ctxt != NULL) && (ctxt->cache)) {
2266
 
        xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2267
 
 
2268
 
        if ((cache->booleanObjs != NULL) &&
2269
 
            (cache->booleanObjs->number != 0))
2270
 
        {
2271
 
            xmlXPathObjectPtr ret;
2272
 
 
2273
 
            ret = (xmlXPathObjectPtr)
2274
 
                cache->booleanObjs->items[--cache->booleanObjs->number];
2275
 
            ret->type = XPATH_BOOLEAN;
2276
 
            ret->boolval = (val != 0);
2277
 
#ifdef XP_DEBUG_OBJ_USAGE
2278
 
            xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2279
 
#endif
2280
 
            return(ret);
2281
 
        } else if ((cache->miscObjs != NULL) &&
2282
 
            (cache->miscObjs->number != 0))
2283
 
        {
2284
 
            xmlXPathObjectPtr ret;
2285
 
 
2286
 
            ret = (xmlXPathObjectPtr)
2287
 
                cache->miscObjs->items[--cache->miscObjs->number];
2288
 
 
2289
 
            ret->type = XPATH_BOOLEAN;
2290
 
            ret->boolval = (val != 0);
2291
 
#ifdef XP_DEBUG_OBJ_USAGE
2292
 
            xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2293
 
#endif
2294
 
            return(ret);
2295
 
        }
2296
 
    }
2297
 
    return(xmlXPathNewBoolean(val));
2298
 
}
2299
 
 
2300
 
/**
2301
 
 * xmlXPathCacheNewFloat:
2302
 
 * @ctxt: the XPath context
2303
 
 * @val:  the double value
2304
 
 *
2305
 
 * This is the cached version of xmlXPathNewFloat().
2306
 
 * Acquires an xmlXPathObjectPtr of type double and of value @val
2307
 
 *
2308
 
 * Returns the created or reused object.
2309
 
 */
2310
 
static xmlXPathObjectPtr
2311
 
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2312
 
{
2313
 
     if ((ctxt != NULL) && (ctxt->cache)) {
2314
 
        xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2315
 
 
2316
 
        if ((cache->numberObjs != NULL) &&
2317
 
            (cache->numberObjs->number != 0))
2318
 
        {
2319
 
            xmlXPathObjectPtr ret;
2320
 
 
2321
 
            ret = (xmlXPathObjectPtr)
2322
 
                cache->numberObjs->items[--cache->numberObjs->number];
2323
 
            ret->type = XPATH_NUMBER;
2324
 
            ret->floatval = val;
2325
 
#ifdef XP_DEBUG_OBJ_USAGE
2326
 
            xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2327
 
#endif
2328
 
            return(ret);
2329
 
        } else if ((cache->miscObjs != NULL) &&
2330
 
            (cache->miscObjs->number != 0))
2331
 
        {
2332
 
            xmlXPathObjectPtr ret;
2333
 
 
2334
 
            ret = (xmlXPathObjectPtr)
2335
 
                cache->miscObjs->items[--cache->miscObjs->number];
2336
 
 
2337
 
            ret->type = XPATH_NUMBER;
2338
 
            ret->floatval = val;
2339
 
#ifdef XP_DEBUG_OBJ_USAGE
2340
 
            xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2341
 
#endif
2342
 
            return(ret);
2343
 
        }
2344
 
    }
2345
 
    return(xmlXPathNewFloat(val));
2346
 
}
2347
 
 
2348
 
/**
2349
 
 * xmlXPathCacheConvertString:
2350
 
 * @ctxt: the XPath context
2351
 
 * @val:  an XPath object
2352
 
 *
2353
 
 * This is the cached version of xmlXPathConvertString().
2354
 
 * Converts an existing object to its string() equivalent
2355
 
 *
2356
 
 * Returns a created or reused object, the old one is freed (cached)
2357
 
 *         (or the operation is done directly on @val)
2358
 
 */
2359
 
 
2360
 
static xmlXPathObjectPtr
2361
 
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2362
 
    xmlChar *res = NULL;
2363
 
 
2364
 
    if (val == NULL)
2365
 
        return(xmlXPathCacheNewCString(ctxt, ""));
2366
 
 
2367
 
    switch (val->type) {
2368
 
    case XPATH_UNDEFINED:
2369
 
#ifdef DEBUG_EXPR
2370
 
        xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2371
 
#endif
2372
 
        break;
2373
 
    case XPATH_NODESET:
2374
 
    case XPATH_XSLT_TREE:
2375
 
        res = xmlXPathCastNodeSetToString(val->nodesetval);
2376
 
        break;
2377
 
    case XPATH_STRING:
2378
 
        return(val);
2379
 
    case XPATH_BOOLEAN:
2380
 
        res = xmlXPathCastBooleanToString(val->boolval);
2381
 
        break;
2382
 
    case XPATH_NUMBER:
2383
 
        res = xmlXPathCastNumberToString(val->floatval);
2384
 
        break;
2385
 
    case XPATH_USERS:
2386
 
    case XPATH_POINT:
2387
 
    case XPATH_RANGE:
2388
 
    case XPATH_LOCATIONSET:
2389
 
        TODO;
2390
 
        break;
2391
 
    }
2392
 
    xmlXPathReleaseObject(ctxt, val);
2393
 
    if (res == NULL)
2394
 
        return(xmlXPathCacheNewCString(ctxt, ""));
2395
 
    return(xmlXPathCacheWrapString(ctxt, res));
2396
 
}
2397
 
 
2398
 
/**
2399
 
 * xmlXPathCacheObjectCopy:
2400
 
 * @ctxt: the XPath context
2401
 
 * @val:  the original object
2402
 
 *
2403
 
 * This is the cached version of xmlXPathObjectCopy().
2404
 
 * Acquire a copy of a given object
2405
 
 *
2406
 
 * Returns a created or reused created object.
2407
 
 */
2408
 
static xmlXPathObjectPtr
2409
 
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2410
 
{
2411
 
    if (val == NULL)
2412
 
        return(NULL);
2413
 
 
2414
 
    if (XP_HAS_CACHE(ctxt)) {
2415
 
        switch (val->type) {
2416
 
            case XPATH_NODESET:
2417
 
                return(xmlXPathCacheWrapNodeSet(ctxt,
2418
 
                    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2419
 
            case XPATH_STRING:
2420
 
                return(xmlXPathCacheNewString(ctxt, val->stringval));
2421
 
            case XPATH_BOOLEAN:
2422
 
                return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2423
 
            case XPATH_NUMBER:
2424
 
                return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2425
 
            default:
2426
 
                break;
2427
 
        }
2428
 
    }
2429
 
    return(xmlXPathObjectCopy(val));
2430
 
}
2431
 
 
2432
 
/**
2433
 
 * xmlXPathCacheConvertBoolean:
2434
 
 * @ctxt: the XPath context
2435
 
 * @val:  an XPath object
2436
 
 *
2437
 
 * This is the cached version of xmlXPathConvertBoolean().
2438
 
 * Converts an existing object to its boolean() equivalent
2439
 
 *
2440
 
 * Returns a created or reused object, the old one is freed (or the operation
2441
 
 *         is done directly on @val)
2442
 
 */
2443
 
static xmlXPathObjectPtr
2444
 
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2445
 
    xmlXPathObjectPtr ret;
2446
 
 
2447
 
    if (val == NULL)
2448
 
        return(xmlXPathCacheNewBoolean(ctxt, 0));
2449
 
    if (val->type == XPATH_BOOLEAN)
2450
 
        return(val);
2451
 
    ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2452
 
    xmlXPathReleaseObject(ctxt, val);
2453
 
    return(ret);
2454
 
}
2455
 
 
2456
 
/**
2457
 
 * xmlXPathCacheConvertNumber:
2458
 
 * @ctxt: the XPath context
2459
 
 * @val:  an XPath object
2460
 
 *
2461
 
 * This is the cached version of xmlXPathConvertNumber().
2462
 
 * Converts an existing object to its number() equivalent
2463
 
 *
2464
 
 * Returns a created or reused object, the old one is freed (or the operation
2465
 
 *         is done directly on @val)
2466
 
 */
2467
 
static xmlXPathObjectPtr
2468
 
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2469
 
    xmlXPathObjectPtr ret;
2470
 
 
2471
 
    if (val == NULL)
2472
 
        return(xmlXPathCacheNewFloat(ctxt, 0.0));
2473
 
    if (val->type == XPATH_NUMBER)
2474
 
        return(val);
2475
 
    ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2476
 
    xmlXPathReleaseObject(ctxt, val);
2477
 
    return(ret);
2478
 
}
2479
 
 
2480
 
/************************************************************************
2481
 
 *                                                                      *
2482
 
 *              Parser stacks related functions and macros              *
2483
 
 *                                                                      *
2484
 
 ************************************************************************/
2485
 
 
2486
 
/**
2487
 
 * xmlXPathSetFrame:
2488
 
 * @ctxt: an XPath parser context
2489
 
 *
2490
 
 * Set the callee evaluation frame
2491
 
 *
2492
 
 * Returns the previous frame value to be restored once done
2493
 
 */
2494
 
static int
2495
 
xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2496
 
    int ret;
2497
 
 
2498
 
    if (ctxt == NULL)
2499
 
        return(0);
2500
 
    ret = ctxt->valueFrame;
2501
 
    ctxt->valueFrame = ctxt->valueNr;
2502
 
    return(ret);
2503
 
}
2504
 
 
2505
 
/**
2506
 
 * xmlXPathPopFrame:
2507
 
 * @ctxt: an XPath parser context
2508
 
 * @frame: the previous frame value
2509
 
 *
2510
 
 * Remove the callee evaluation frame
2511
 
 */
2512
 
static void
2513
 
xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2514
 
    if (ctxt == NULL)
2515
 
        return;
2516
 
    if (ctxt->valueNr < ctxt->valueFrame) {
2517
 
        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2518
 
    }
2519
 
    ctxt->valueFrame = frame;
2520
 
}
2521
 
 
2522
 
/**
2523
 
 * valuePop:
2524
 
 * @ctxt: an XPath evaluation context
2525
 
 *
2526
 
 * Pops the top XPath object from the value stack
2527
 
 *
2528
 
 * Returns the XPath object just removed
2529
 
 */
2530
 
xmlXPathObjectPtr
2531
 
valuePop(xmlXPathParserContextPtr ctxt)
2532
 
{
2533
 
    xmlXPathObjectPtr ret;
2534
 
 
2535
 
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2536
 
        return (NULL);
2537
 
 
2538
 
    if (ctxt->valueNr <= ctxt->valueFrame) {
2539
 
        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2540
 
        return (NULL);
2541
 
    }
2542
 
 
2543
 
    ctxt->valueNr--;
2544
 
    if (ctxt->valueNr > 0)
2545
 
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2546
 
    else
2547
 
        ctxt->value = NULL;
2548
 
    ret = ctxt->valueTab[ctxt->valueNr];
2549
 
    ctxt->valueTab[ctxt->valueNr] = NULL;
2550
 
    return (ret);
2551
 
}
2552
 
/**
2553
 
 * valuePush:
2554
 
 * @ctxt:  an XPath evaluation context
2555
 
 * @value:  the XPath object
2556
 
 *
2557
 
 * Pushes a new XPath object on top of the value stack
2558
 
 *
2559
 
 * returns the number of items on the value stack
2560
 
 */
2561
 
int
2562
 
valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2563
 
{
2564
 
    if ((ctxt == NULL) || (value == NULL)) return(-1);
2565
 
    if (ctxt->valueNr >= ctxt->valueMax) {
2566
 
        xmlXPathObjectPtr *tmp;
2567
 
 
2568
 
        if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2569
 
            xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2570
 
            ctxt->error = XPATH_MEMORY_ERROR;
2571
 
            return (0);
2572
 
        }
2573
 
        tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2574
 
                                             2 * ctxt->valueMax *
2575
 
                                             sizeof(ctxt->valueTab[0]));
2576
 
        if (tmp == NULL) {
2577
 
            xmlXPathErrMemory(NULL, "pushing value\n");
2578
 
            ctxt->error = XPATH_MEMORY_ERROR;
2579
 
            return (0);
2580
 
        }
2581
 
        ctxt->valueMax *= 2;
2582
 
        ctxt->valueTab = tmp;
2583
 
    }
2584
 
    ctxt->valueTab[ctxt->valueNr] = value;
2585
 
    ctxt->value = value;
2586
 
    return (ctxt->valueNr++);
2587
 
}
2588
 
 
2589
 
/**
2590
 
 * xmlXPathPopBoolean:
2591
 
 * @ctxt:  an XPath parser context
2592
 
 *
2593
 
 * Pops a boolean from the stack, handling conversion if needed.
2594
 
 * Check error with #xmlXPathCheckError.
2595
 
 *
2596
 
 * Returns the boolean
2597
 
 */
2598
 
int
2599
 
xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2600
 
    xmlXPathObjectPtr obj;
2601
 
    int ret;
2602
 
 
2603
 
    obj = valuePop(ctxt);
2604
 
    if (obj == NULL) {
2605
 
        xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2606
 
        return(0);
2607
 
    }
2608
 
    if (obj->type != XPATH_BOOLEAN)
2609
 
        ret = xmlXPathCastToBoolean(obj);
2610
 
    else
2611
 
        ret = obj->boolval;
2612
 
    xmlXPathReleaseObject(ctxt->context, obj);
2613
 
    return(ret);
2614
 
}
2615
 
 
2616
 
/**
2617
 
 * xmlXPathPopNumber:
2618
 
 * @ctxt:  an XPath parser context
2619
 
 *
2620
 
 * Pops a number from the stack, handling conversion if needed.
2621
 
 * Check error with #xmlXPathCheckError.
2622
 
 *
2623
 
 * Returns the number
2624
 
 */
2625
 
double
2626
 
xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2627
 
    xmlXPathObjectPtr obj;
2628
 
    double ret;
2629
 
 
2630
 
    obj = valuePop(ctxt);
2631
 
    if (obj == NULL) {
2632
 
        xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2633
 
        return(0);
2634
 
    }
2635
 
    if (obj->type != XPATH_NUMBER)
2636
 
        ret = xmlXPathCastToNumber(obj);
2637
 
    else
2638
 
        ret = obj->floatval;
2639
 
    xmlXPathReleaseObject(ctxt->context, obj);
2640
 
    return(ret);
2641
 
}
2642
 
 
2643
 
/**
2644
 
 * xmlXPathPopString:
2645
 
 * @ctxt:  an XPath parser context
2646
 
 *
2647
 
 * Pops a string from the stack, handling conversion if needed.
2648
 
 * Check error with #xmlXPathCheckError.
2649
 
 *
2650
 
 * Returns the string
2651
 
 */
2652
 
xmlChar *
2653
 
xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2654
 
    xmlXPathObjectPtr obj;
2655
 
    xmlChar * ret;
2656
 
 
2657
 
    obj = valuePop(ctxt);
2658
 
    if (obj == NULL) {
2659
 
        xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2660
 
        return(NULL);
2661
 
    }
2662
 
    ret = xmlXPathCastToString(obj);    /* this does required strdup */
2663
 
    /* TODO: needs refactoring somewhere else */
2664
 
    if (obj->stringval == ret)
2665
 
        obj->stringval = NULL;
2666
 
    xmlXPathReleaseObject(ctxt->context, obj);
2667
 
    return(ret);
2668
 
}
2669
 
 
2670
 
/**
2671
 
 * xmlXPathPopNodeSet:
2672
 
 * @ctxt:  an XPath parser context
2673
 
 *
2674
 
 * Pops a node-set from the stack, handling conversion if needed.
2675
 
 * Check error with #xmlXPathCheckError.
2676
 
 *
2677
 
 * Returns the node-set
2678
 
 */
2679
 
xmlNodeSetPtr
2680
 
xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2681
 
    xmlXPathObjectPtr obj;
2682
 
    xmlNodeSetPtr ret;
2683
 
 
2684
 
    if (ctxt == NULL) return(NULL);
2685
 
    if (ctxt->value == NULL) {
2686
 
        xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2687
 
        return(NULL);
2688
 
    }
2689
 
    if (!xmlXPathStackIsNodeSet(ctxt)) {
2690
 
        xmlXPathSetTypeError(ctxt);
2691
 
        return(NULL);
2692
 
    }
2693
 
    obj = valuePop(ctxt);
2694
 
    ret = obj->nodesetval;
2695
 
#if 0
2696
 
    /* to fix memory leak of not clearing obj->user */
2697
 
    if (obj->boolval && obj->user != NULL)
2698
 
        xmlFreeNodeList((xmlNodePtr) obj->user);
2699
 
#endif
2700
 
    obj->nodesetval = NULL;
2701
 
    xmlXPathReleaseObject(ctxt->context, obj);
2702
 
    return(ret);
2703
 
}
2704
 
 
2705
 
/**
2706
 
 * xmlXPathPopExternal:
2707
 
 * @ctxt:  an XPath parser context
2708
 
 *
2709
 
 * Pops an external object from the stack, handling conversion if needed.
2710
 
 * Check error with #xmlXPathCheckError.
2711
 
 *
2712
 
 * Returns the object
2713
 
 */
2714
 
void *
2715
 
xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2716
 
    xmlXPathObjectPtr obj;
2717
 
    void * ret;
2718
 
 
2719
 
    if ((ctxt == NULL) || (ctxt->value == NULL)) {
2720
 
        xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2721
 
        return(NULL);
2722
 
    }
2723
 
    if (ctxt->value->type != XPATH_USERS) {
2724
 
        xmlXPathSetTypeError(ctxt);
2725
 
        return(NULL);
2726
 
    }
2727
 
    obj = valuePop(ctxt);
2728
 
    ret = obj->user;
2729
 
    obj->user = NULL;
2730
 
    xmlXPathReleaseObject(ctxt->context, obj);
2731
 
    return(ret);
2732
 
}
2733
 
 
2734
 
/*
2735
 
 * Macros for accessing the content. Those should be used only by the parser,
2736
 
 * and not exported.
2737
 
 *
2738
 
 * Dirty macros, i.e. one need to make assumption on the context to use them
2739
 
 *
2740
 
 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
2741
 
 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
2742
 
 *           in ISO-Latin or UTF-8.
2743
 
 *           This should be used internally by the parser
2744
 
 *           only to compare to ASCII values otherwise it would break when
2745
 
 *           running with UTF-8 encoding.
2746
 
 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
2747
 
 *           to compare on ASCII based substring.
2748
 
 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2749
 
 *           strings within the parser.
2750
 
 *   CURRENT Returns the current char value, with the full decoding of
2751
 
 *           UTF-8 if we are using this mode. It returns an int.
2752
 
 *   NEXT    Skip to the next character, this does the proper decoding
2753
 
 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
2754
 
 *           It returns the pointer to the current xmlChar.
2755
 
 */
2756
 
 
2757
 
#define CUR (*ctxt->cur)
2758
 
#define SKIP(val) ctxt->cur += (val)
2759
 
#define NXT(val) ctxt->cur[(val)]
2760
 
#define CUR_PTR ctxt->cur
2761
 
#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2762
 
 
2763
 
#define COPY_BUF(l,b,i,v)                                              \
2764
 
    if (l == 1) b[i++] = (xmlChar) v;                                  \
2765
 
    else i += xmlCopyChar(l,&b[i],v)
2766
 
 
2767
 
#define NEXTL(l)  ctxt->cur += l
2768
 
 
2769
 
#define SKIP_BLANKS                                                     \
2770
 
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2771
 
 
2772
 
#define CURRENT (*ctxt->cur)
2773
 
#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
2774
 
 
2775
 
 
2776
 
#ifndef DBL_DIG
2777
 
#define DBL_DIG 16
2778
 
#endif
2779
 
#ifndef DBL_EPSILON
2780
 
#define DBL_EPSILON 1E-9
2781
 
#endif
2782
 
 
2783
 
#define UPPER_DOUBLE 1E9
2784
 
#define LOWER_DOUBLE 1E-5
2785
 
#define LOWER_DOUBLE_EXP 5
2786
 
 
2787
 
#define INTEGER_DIGITS DBL_DIG
2788
 
#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2789
 
#define EXPONENT_DIGITS (3 + 2)
2790
 
 
2791
 
/**
2792
 
 * xmlXPathFormatNumber:
2793
 
 * @number:     number to format
2794
 
 * @buffer:     output buffer
2795
 
 * @buffersize: size of output buffer
2796
 
 *
2797
 
 * Convert the number into a string representation.
2798
 
 */
2799
 
static void
2800
 
xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2801
 
{
2802
 
    switch (xmlXPathIsInf(number)) {
2803
 
    case 1:
2804
 
        if (buffersize > (int)sizeof("Infinity"))
2805
 
            snprintf(buffer, buffersize, "Infinity");
2806
 
        break;
2807
 
    case -1:
2808
 
        if (buffersize > (int)sizeof("-Infinity"))
2809
 
            snprintf(buffer, buffersize, "-Infinity");
2810
 
        break;
2811
 
    default:
2812
 
        if (xmlXPathIsNaN(number)) {
2813
 
            if (buffersize > (int)sizeof("NaN"))
2814
 
                snprintf(buffer, buffersize, "NaN");
2815
 
        } else if (number == 0 && xmlXPathGetSign(number) != 0) {
2816
 
            snprintf(buffer, buffersize, "0");
2817
 
        } else if (number == ((int) number)) {
2818
 
            char work[30];
2819
 
            char *ptr, *cur;
2820
 
            int value = (int) number;
2821
 
 
2822
 
            ptr = &buffer[0];
2823
 
            if (value == 0) {
2824
 
                *ptr++ = '0';
2825
 
            } else {
2826
 
                snprintf(work, 29, "%d", value);
2827
 
                cur = &work[0];
2828
 
                while ((*cur) && (ptr - buffer < buffersize)) {
2829
 
                    *ptr++ = *cur++;
2830
 
                }
2831
 
            }
2832
 
            if (ptr - buffer < buffersize) {
2833
 
                *ptr = 0;
2834
 
            } else if (buffersize > 0) {
2835
 
                ptr--;
2836
 
                *ptr = 0;
2837
 
            }
2838
 
        } else {
2839
 
            /*
2840
 
              For the dimension of work,
2841
 
                  DBL_DIG is number of significant digits
2842
 
                  EXPONENT is only needed for "scientific notation"
2843
 
                  3 is sign, decimal point, and terminating zero
2844
 
                  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2845
 
              Note that this dimension is slightly (a few characters)
2846
 
              larger than actually necessary.
2847
 
            */
2848
 
            char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2849
 
            int integer_place, fraction_place;
2850
 
            char *ptr;
2851
 
            char *after_fraction;
2852
 
            double absolute_value;
2853
 
            int size;
2854
 
 
2855
 
            absolute_value = fabs(number);
2856
 
 
2857
 
            /*
2858
 
             * First choose format - scientific or regular floating point.
2859
 
             * In either case, result is in work, and after_fraction points
2860
 
             * just past the fractional part.
2861
 
            */
2862
 
            if ( ((absolute_value > UPPER_DOUBLE) ||
2863
 
                  (absolute_value < LOWER_DOUBLE)) &&
2864
 
                 (absolute_value != 0.0) ) {
2865
 
                /* Use scientific notation */
2866
 
                integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2867
 
                fraction_place = DBL_DIG - 1;
2868
 
                size = snprintf(work, sizeof(work),"%*.*e",
2869
 
                         integer_place, fraction_place, number);
2870
 
                while ((size > 0) && (work[size] != 'e')) size--;
2871
 
 
2872
 
            }
2873
 
            else {
2874
 
                /* Use regular notation */
2875
 
                if (absolute_value > 0.0) {
2876
 
                    integer_place = (int)log10(absolute_value);
2877
 
                    if (integer_place > 0)
2878
 
                        fraction_place = DBL_DIG - integer_place - 1;
2879
 
                    else
2880
 
                        fraction_place = DBL_DIG - integer_place;
2881
 
                } else {
2882
 
                    fraction_place = 1;
2883
 
                }
2884
 
                size = snprintf(work, sizeof(work), "%0.*f",
2885
 
                                fraction_place, number);
2886
 
            }
2887
 
 
2888
 
            /* Remove fractional trailing zeroes */
2889
 
            after_fraction = work + size;
2890
 
            ptr = after_fraction;
2891
 
            while (*(--ptr) == '0')
2892
 
                ;
2893
 
            if (*ptr != '.')
2894
 
                ptr++;
2895
 
            while ((*ptr++ = *after_fraction++) != 0);
2896
 
 
2897
 
            /* Finally copy result back to caller */
2898
 
            size = strlen(work) + 1;
2899
 
            if (size > buffersize) {
2900
 
                work[buffersize - 1] = 0;
2901
 
                size = buffersize;
2902
 
            }
2903
 
            memmove(buffer, work, size);
2904
 
        }
2905
 
        break;
2906
 
    }
2907
 
}
2908
 
 
2909
 
 
2910
 
/************************************************************************
2911
 
 *                                                                      *
2912
 
 *                      Routines to handle NodeSets                     *
2913
 
 *                                                                      *
2914
 
 ************************************************************************/
2915
 
 
2916
 
/**
2917
 
 * xmlXPathOrderDocElems:
2918
 
 * @doc:  an input document
2919
 
 *
2920
 
 * Call this routine to speed up XPath computation on static documents.
2921
 
 * This stamps all the element nodes with the document order
2922
 
 * Like for line information, the order is kept in the element->content
2923
 
 * field, the value stored is actually - the node number (starting at -1)
2924
 
 * to be able to differentiate from line numbers.
2925
 
 *
2926
 
 * Returns the number of elements found in the document or -1 in case
2927
 
 *    of error.
2928
 
 */
2929
 
long
2930
 
xmlXPathOrderDocElems(xmlDocPtr doc) {
2931
 
    long count = 0;
2932
 
    xmlNodePtr cur;
2933
 
 
2934
 
    if (doc == NULL)
2935
 
        return(-1);
2936
 
    cur = doc->children;
2937
 
    while (cur != NULL) {
2938
 
        if (cur->type == XML_ELEMENT_NODE) {
2939
 
            cur->content = (void *) (-(++count));
2940
 
            if (cur->children != NULL) {
2941
 
                cur = cur->children;
2942
 
                continue;
2943
 
            }
2944
 
        }
2945
 
        if (cur->next != NULL) {
2946
 
            cur = cur->next;
2947
 
            continue;
2948
 
        }
2949
 
        do {
2950
 
            cur = cur->parent;
2951
 
            if (cur == NULL)
2952
 
                break;
2953
 
            if (cur == (xmlNodePtr) doc) {
2954
 
                cur = NULL;
2955
 
                break;
2956
 
            }
2957
 
            if (cur->next != NULL) {
2958
 
                cur = cur->next;
2959
 
                break;
2960
 
            }
2961
 
        } while (cur != NULL);
2962
 
    }
2963
 
    return(count);
2964
 
}
2965
 
 
2966
 
/**
2967
 
 * xmlXPathCmpNodes:
2968
 
 * @node1:  the first node
2969
 
 * @node2:  the second node
2970
 
 *
2971
 
 * Compare two nodes w.r.t document order
2972
 
 *
2973
 
 * Returns -2 in case of error 1 if first point < second point, 0 if
2974
 
 *         it's the same node, -1 otherwise
2975
 
 */
2976
 
int
2977
 
xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2978
 
    int depth1, depth2;
2979
 
    int attr1 = 0, attr2 = 0;
2980
 
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2981
 
    xmlNodePtr cur, root;
2982
 
 
2983
 
    if ((node1 == NULL) || (node2 == NULL))
2984
 
        return(-2);
2985
 
    /*
2986
 
     * a couple of optimizations which will avoid computations in most cases
2987
 
     */
2988
 
    if (node1 == node2)         /* trivial case */
2989
 
        return(0);
2990
 
    if (node1->type == XML_ATTRIBUTE_NODE) {
2991
 
        attr1 = 1;
2992
 
        attrNode1 = node1;
2993
 
        node1 = node1->parent;
2994
 
    }
2995
 
    if (node2->type == XML_ATTRIBUTE_NODE) {
2996
 
        attr2 = 1;
2997
 
        attrNode2 = node2;
2998
 
        node2 = node2->parent;
2999
 
    }
3000
 
    if (node1 == node2) {
3001
 
        if (attr1 == attr2) {
3002
 
            /* not required, but we keep attributes in order */
3003
 
            if (attr1 != 0) {
3004
 
                cur = attrNode2->prev;
3005
 
                while (cur != NULL) {
3006
 
                    if (cur == attrNode1)
3007
 
                        return (1);
3008
 
                    cur = cur->prev;
3009
 
                }
3010
 
                return (-1);
3011
 
            }
3012
 
            return(0);
3013
 
        }
3014
 
        if (attr2 == 1)
3015
 
            return(1);
3016
 
        return(-1);
3017
 
    }
3018
 
    if ((node1->type == XML_NAMESPACE_DECL) ||
3019
 
        (node2->type == XML_NAMESPACE_DECL))
3020
 
        return(1);
3021
 
    if (node1 == node2->prev)
3022
 
        return(1);
3023
 
    if (node1 == node2->next)
3024
 
        return(-1);
3025
 
 
3026
 
    /*
3027
 
     * Speedup using document order if availble.
3028
 
     */
3029
 
    if ((node1->type == XML_ELEMENT_NODE) &&
3030
 
        (node2->type == XML_ELEMENT_NODE) &&
3031
 
        (0 > (long) node1->content) &&
3032
 
        (0 > (long) node2->content) &&
3033
 
        (node1->doc == node2->doc)) {
3034
 
        long l1, l2;
3035
 
 
3036
 
        l1 = -((long) node1->content);
3037
 
        l2 = -((long) node2->content);
3038
 
        if (l1 < l2)
3039
 
            return(1);
3040
 
        if (l1 > l2)
3041
 
            return(-1);
3042
 
    }
3043
 
 
3044
 
    /*
3045
 
     * compute depth to root
3046
 
     */
3047
 
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3048
 
        if (cur == node1)
3049
 
            return(1);
3050
 
        depth2++;
3051
 
    }
3052
 
    root = cur;
3053
 
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3054
 
        if (cur == node2)
3055
 
            return(-1);
3056
 
        depth1++;
3057
 
    }
3058
 
    /*
3059
 
     * Distinct document (or distinct entities :-( ) case.
3060
 
     */
3061
 
    if (root != cur) {
3062
 
        return(-2);
3063
 
    }
3064
 
    /*
3065
 
     * get the nearest common ancestor.
3066
 
     */
3067
 
    while (depth1 > depth2) {
3068
 
        depth1--;
3069
 
        node1 = node1->parent;
3070
 
    }
3071
 
    while (depth2 > depth1) {
3072
 
        depth2--;
3073
 
        node2 = node2->parent;
3074
 
    }
3075
 
    while (node1->parent != node2->parent) {
3076
 
        node1 = node1->parent;
3077
 
        node2 = node2->parent;
3078
 
        /* should not happen but just in case ... */
3079
 
        if ((node1 == NULL) || (node2 == NULL))
3080
 
            return(-2);
3081
 
    }
3082
 
    /*
3083
 
     * Find who's first.
3084
 
     */
3085
 
    if (node1 == node2->prev)
3086
 
        return(1);
3087
 
    if (node1 == node2->next)
3088
 
        return(-1);
3089
 
    /*
3090
 
     * Speedup using document order if availble.
3091
 
     */
3092
 
    if ((node1->type == XML_ELEMENT_NODE) &&
3093
 
        (node2->type == XML_ELEMENT_NODE) &&
3094
 
        (0 > (long) node1->content) &&
3095
 
        (0 > (long) node2->content) &&
3096
 
        (node1->doc == node2->doc)) {
3097
 
        long l1, l2;
3098
 
 
3099
 
        l1 = -((long) node1->content);
3100
 
        l2 = -((long) node2->content);
3101
 
        if (l1 < l2)
3102
 
            return(1);
3103
 
        if (l1 > l2)
3104
 
            return(-1);
3105
 
    }
3106
 
 
3107
 
    for (cur = node1->next;cur != NULL;cur = cur->next)
3108
 
        if (cur == node2)
3109
 
            return(1);
3110
 
    return(-1); /* assume there is no sibling list corruption */
3111
 
}
3112
 
 
3113
 
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3114
 
/**
3115
 
 * xmlXPathCmpNodesExt:
3116
 
 * @node1:  the first node
3117
 
 * @node2:  the second node
3118
 
 *
3119
 
 * Compare two nodes w.r.t document order.
3120
 
 * This one is optimized for handling of non-element nodes.
3121
 
 *
3122
 
 * Returns -2 in case of error 1 if first point < second point, 0 if
3123
 
 *         it's the same node, -1 otherwise
3124
 
 */
3125
 
static int
3126
 
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
3127
 
    int depth1, depth2;
3128
 
    int misc = 0, precedence1 = 0, precedence2 = 0;
3129
 
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
3130
 
    xmlNodePtr cur, root;
3131
 
    long l1, l2;
3132
 
 
3133
 
    if ((node1 == NULL) || (node2 == NULL))
3134
 
        return(-2);
3135
 
 
3136
 
    if (node1 == node2)
3137
 
        return(0);
3138
 
 
3139
 
    /*
3140
 
     * a couple of optimizations which will avoid computations in most cases
3141
 
     */
3142
 
    switch (node1->type) {
3143
 
        case XML_ELEMENT_NODE:
3144
 
            if (node2->type == XML_ELEMENT_NODE) {
3145
 
                if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3146
 
                    (0 > (long) node2->content) &&
3147
 
                    (node1->doc == node2->doc))
3148
 
                {
3149
 
                    l1 = -((long) node1->content);
3150
 
                    l2 = -((long) node2->content);
3151
 
                    if (l1 < l2)
3152
 
                        return(1);
3153
 
                    if (l1 > l2)
3154
 
                        return(-1);
3155
 
                } else
3156
 
                    goto turtle_comparison;
3157
 
            }
3158
 
            break;
3159
 
        case XML_ATTRIBUTE_NODE:
3160
 
            precedence1 = 1; /* element is owner */
3161
 
            miscNode1 = node1;
3162
 
            node1 = node1->parent;
3163
 
            misc = 1;
3164
 
            break;
3165
 
        case XML_TEXT_NODE:
3166
 
        case XML_CDATA_SECTION_NODE:
3167
 
        case XML_COMMENT_NODE:
3168
 
        case XML_PI_NODE: {
3169
 
            miscNode1 = node1;
3170
 
            /*
3171
 
            * Find nearest element node.
3172
 
            */
3173
 
            if (node1->prev != NULL) {
3174
 
                do {
3175
 
                    node1 = node1->prev;
3176
 
                    if (node1->type == XML_ELEMENT_NODE) {
3177
 
                        precedence1 = 3; /* element in prev-sibl axis */
3178
 
                        break;
3179
 
                    }
3180
 
                    if (node1->prev == NULL) {
3181
 
                        precedence1 = 2; /* element is parent */
3182
 
                        /*
3183
 
                        * URGENT TODO: Are there any cases, where the
3184
 
                        * parent of such a node is not an element node?
3185
 
                        */
3186
 
                        node1 = node1->parent;
3187
 
                        break;
3188
 
                    }
3189
 
                } while (1);
3190
 
            } else {
3191
 
                precedence1 = 2; /* element is parent */
3192
 
                node1 = node1->parent;
3193
 
            }
3194
 
            if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
3195
 
                (0 <= (long) node1->content)) {
3196
 
                /*
3197
 
                * Fallback for whatever case.
3198
 
                */
3199
 
                node1 = miscNode1;
3200
 
                precedence1 = 0;
3201
 
            } else
3202
 
                misc = 1;
3203
 
        }
3204
 
            break;
3205
 
        case XML_NAMESPACE_DECL:
3206
 
            /*
3207
 
            * TODO: why do we return 1 for namespace nodes?
3208
 
            */
3209
 
            return(1);
3210
 
        default:
3211
 
            break;
3212
 
    }
3213
 
    switch (node2->type) {
3214
 
        case XML_ELEMENT_NODE:
3215
 
            break;
3216
 
        case XML_ATTRIBUTE_NODE:
3217
 
            precedence2 = 1; /* element is owner */
3218
 
            miscNode2 = node2;
3219
 
            node2 = node2->parent;
3220
 
            misc = 1;
3221
 
            break;
3222
 
        case XML_TEXT_NODE:
3223
 
        case XML_CDATA_SECTION_NODE:
3224
 
        case XML_COMMENT_NODE:
3225
 
        case XML_PI_NODE: {
3226
 
            miscNode2 = node2;
3227
 
            if (node2->prev != NULL) {
3228
 
                do {
3229
 
                    node2 = node2->prev;
3230
 
                    if (node2->type == XML_ELEMENT_NODE) {
3231
 
                        precedence2 = 3; /* element in prev-sibl axis */
3232
 
                        break;
3233
 
                    }
3234
 
                    if (node2->prev == NULL) {
3235
 
                        precedence2 = 2; /* element is parent */
3236
 
                        node2 = node2->parent;
3237
 
                        break;
3238
 
                    }
3239
 
                } while (1);
3240
 
            } else {
3241
 
                precedence2 = 2; /* element is parent */
3242
 
                node2 = node2->parent;
3243
 
            }
3244
 
            if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3245
 
                (0 <= (long) node1->content))
3246
 
            {
3247
 
                node2 = miscNode2;
3248
 
                precedence2 = 0;
3249
 
            } else
3250
 
                misc = 1;
3251
 
        }
3252
 
            break;
3253
 
        case XML_NAMESPACE_DECL:
3254
 
            return(1);
3255
 
        default:
3256
 
            break;
3257
 
    }
3258
 
    if (misc) {
3259
 
        if (node1 == node2) {
3260
 
            if (precedence1 == precedence2) {
3261
 
                /*
3262
 
                * The ugly case; but normally there aren't many
3263
 
                * adjacent non-element nodes around.
3264
 
                */
3265
 
                cur = miscNode2->prev;
3266
 
                while (cur != NULL) {
3267
 
                    if (cur == miscNode1)
3268
 
                        return(1);
3269
 
                    if (cur->type == XML_ELEMENT_NODE)
3270
 
                        return(-1);
3271
 
                    cur = cur->prev;
3272
 
                }
3273
 
                return (-1);
3274
 
            } else {
3275
 
                /*
3276
 
                * Evaluate based on higher precedence wrt to the element.
3277
 
                * TODO: This assumes attributes are sorted before content.
3278
 
                *   Is this 100% correct?
3279
 
                */
3280
 
                if (precedence1 < precedence2)
3281
 
                    return(1);
3282
 
                else
3283
 
                    return(-1);
3284
 
            }
3285
 
        }
3286
 
        /*
3287
 
        * Special case: One of the helper-elements is contained by the other.
3288
 
        * <foo>
3289
 
        *   <node2>
3290
 
        *     <node1>Text-1(precedence1 == 2)</node1>
3291
 
        *   </node2>
3292
 
        *   Text-6(precedence2 == 3)
3293
 
        * </foo>
3294
 
        */
3295
 
        if ((precedence2 == 3) && (precedence1 > 1)) {
3296
 
            cur = node1->parent;
3297
 
            while (cur) {
3298
 
                if (cur == node2)
3299
 
                    return(1);
3300
 
                cur = cur->parent;
3301
 
            }
3302
 
        }
3303
 
        if ((precedence1 == 3) && (precedence2 > 1)) {
3304
 
            cur = node2->parent;
3305
 
            while (cur) {
3306
 
                if (cur == node1)
3307
 
                    return(-1);
3308
 
                cur = cur->parent;
3309
 
            }
3310
 
        }
3311
 
    }
3312
 
 
3313
 
    /*
3314
 
     * Speedup using document order if availble.
3315
 
     */
3316
 
    if ((node1->type == XML_ELEMENT_NODE) &&
3317
 
        (node2->type == XML_ELEMENT_NODE) &&
3318
 
        (0 > (long) node1->content) &&
3319
 
        (0 > (long) node2->content) &&
3320
 
        (node1->doc == node2->doc)) {
3321
 
 
3322
 
        l1 = -((long) node1->content);
3323
 
        l2 = -((long) node2->content);
3324
 
        if (l1 < l2)
3325
 
            return(1);
3326
 
        if (l1 > l2)
3327
 
            return(-1);
3328
 
    }
3329
 
 
3330
 
turtle_comparison:
3331
 
 
3332
 
    if (node1 == node2->prev)
3333
 
        return(1);
3334
 
    if (node1 == node2->next)
3335
 
        return(-1);
3336
 
    /*
3337
 
     * compute depth to root
3338
 
     */
3339
 
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3340
 
        if (cur == node1)
3341
 
            return(1);
3342
 
        depth2++;
3343
 
    }
3344
 
    root = cur;
3345
 
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3346
 
        if (cur == node2)
3347
 
            return(-1);
3348
 
        depth1++;
3349
 
    }
3350
 
    /*
3351
 
     * Distinct document (or distinct entities :-( ) case.
3352
 
     */
3353
 
    if (root != cur) {
3354
 
        return(-2);
3355
 
    }
3356
 
    /*
3357
 
     * get the nearest common ancestor.
3358
 
     */
3359
 
    while (depth1 > depth2) {
3360
 
        depth1--;
3361
 
        node1 = node1->parent;
3362
 
    }
3363
 
    while (depth2 > depth1) {
3364
 
        depth2--;
3365
 
        node2 = node2->parent;
3366
 
    }
3367
 
    while (node1->parent != node2->parent) {
3368
 
        node1 = node1->parent;
3369
 
        node2 = node2->parent;
3370
 
        /* should not happen but just in case ... */
3371
 
        if ((node1 == NULL) || (node2 == NULL))
3372
 
            return(-2);
3373
 
    }
3374
 
    /*
3375
 
     * Find who's first.
3376
 
     */
3377
 
    if (node1 == node2->prev)
3378
 
        return(1);
3379
 
    if (node1 == node2->next)
3380
 
        return(-1);
3381
 
    /*
3382
 
     * Speedup using document order if availble.
3383
 
     */
3384
 
    if ((node1->type == XML_ELEMENT_NODE) &&
3385
 
        (node2->type == XML_ELEMENT_NODE) &&
3386
 
        (0 > (long) node1->content) &&
3387
 
        (0 > (long) node2->content) &&
3388
 
        (node1->doc == node2->doc)) {
3389
 
 
3390
 
        l1 = -((long) node1->content);
3391
 
        l2 = -((long) node2->content);
3392
 
        if (l1 < l2)
3393
 
            return(1);
3394
 
        if (l1 > l2)
3395
 
            return(-1);
3396
 
    }
3397
 
 
3398
 
    for (cur = node1->next;cur != NULL;cur = cur->next)
3399
 
        if (cur == node2)
3400
 
            return(1);
3401
 
    return(-1); /* assume there is no sibling list corruption */
3402
 
}
3403
 
#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
3404
 
 
3405
 
/**
3406
 
 * xmlXPathNodeSetSort:
3407
 
 * @set:  the node set
3408
 
 *
3409
 
 * Sort the node set in document order
3410
 
 */
3411
 
void
3412
 
xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3413
 
#ifndef WITH_TIM_SORT
3414
 
    int i, j, incr, len;
3415
 
    xmlNodePtr tmp;
3416
 
#endif
3417
 
 
3418
 
    if (set == NULL)
3419
 
        return;
3420
 
 
3421
 
#ifndef WITH_TIM_SORT
3422
 
    /*
3423
 
     * Use the old Shell's sort implementation to sort the node-set
3424
 
     * Timsort ought to be quite faster
3425
 
     */
3426
 
    len = set->nodeNr;
3427
 
    for (incr = len / 2; incr > 0; incr /= 2) {
3428
 
        for (i = incr; i < len; i++) {
3429
 
            j = i - incr;
3430
 
            while (j >= 0) {
3431
 
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3432
 
                if (xmlXPathCmpNodesExt(set->nodeTab[j],
3433
 
                        set->nodeTab[j + incr]) == -1)
3434
 
#else
3435
 
                if (xmlXPathCmpNodes(set->nodeTab[j],
3436
 
                        set->nodeTab[j + incr]) == -1)
3437
 
#endif
3438
 
                {
3439
 
                    tmp = set->nodeTab[j];
3440
 
                    set->nodeTab[j] = set->nodeTab[j + incr];
3441
 
                    set->nodeTab[j + incr] = tmp;
3442
 
                    j -= incr;
3443
 
                } else
3444
 
                    break;
3445
 
            }
3446
 
        }
3447
 
    }
3448
 
#else /* WITH_TIM_SORT */
3449
 
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3450
 
#endif /* WITH_TIM_SORT */
3451
 
}
3452
 
 
3453
 
#define XML_NODESET_DEFAULT     10
3454
 
/**
3455
 
 * xmlXPathNodeSetDupNs:
3456
 
 * @node:  the parent node of the namespace XPath node
3457
 
 * @ns:  the libxml namespace declaration node.
3458
 
 *
3459
 
 * Namespace node in libxml don't match the XPath semantic. In a node set
3460
 
 * the namespace nodes are duplicated and the next pointer is set to the
3461
 
 * parent node in the XPath semantic.
3462
 
 *
3463
 
 * Returns the newly created object.
3464
 
 */
3465
 
static xmlNodePtr
3466
 
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3467
 
    xmlNsPtr cur;
3468
 
 
3469
 
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3470
 
        return(NULL);
3471
 
    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3472
 
        return((xmlNodePtr) ns);
3473
 
 
3474
 
    /*
3475
 
     * Allocate a new Namespace and fill the fields.
3476
 
     */
3477
 
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3478
 
    if (cur == NULL) {
3479
 
        xmlXPathErrMemory(NULL, "duplicating namespace\n");
3480
 
        return(NULL);
3481
 
    }
3482
 
    memset(cur, 0, sizeof(xmlNs));
3483
 
    cur->type = XML_NAMESPACE_DECL;
3484
 
    if (ns->href != NULL)
3485
 
        cur->href = xmlStrdup(ns->href);
3486
 
    if (ns->prefix != NULL)
3487
 
        cur->prefix = xmlStrdup(ns->prefix);
3488
 
    cur->next = (xmlNsPtr) node;
3489
 
    return((xmlNodePtr) cur);
3490
 
}
3491
 
 
3492
 
/**
3493
 
 * xmlXPathNodeSetFreeNs:
3494
 
 * @ns:  the XPath namespace node found in a nodeset.
3495
 
 *
3496
 
 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3497
 
 * the namespace nodes are duplicated and the next pointer is set to the
3498
 
 * parent node in the XPath semantic. Check if such a node needs to be freed
3499
 
 */
3500
 
void
3501
 
xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3502
 
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3503
 
        return;
3504
 
 
3505
 
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3506
 
        if (ns->href != NULL)
3507
 
            xmlFree((xmlChar *)ns->href);
3508
 
        if (ns->prefix != NULL)
3509
 
            xmlFree((xmlChar *)ns->prefix);
3510
 
        xmlFree(ns);
3511
 
    }
3512
 
}
3513
 
 
3514
 
/**
3515
 
 * xmlXPathNodeSetCreate:
3516
 
 * @val:  an initial xmlNodePtr, or NULL
3517
 
 *
3518
 
 * Create a new xmlNodeSetPtr of type double and of value @val
3519
 
 *
3520
 
 * Returns the newly created object.
3521
 
 */
3522
 
xmlNodeSetPtr
3523
 
xmlXPathNodeSetCreate(xmlNodePtr val) {
3524
 
    xmlNodeSetPtr ret;
3525
 
 
3526
 
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3527
 
    if (ret == NULL) {
3528
 
        xmlXPathErrMemory(NULL, "creating nodeset\n");
3529
 
        return(NULL);
3530
 
    }
3531
 
    memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3532
 
    if (val != NULL) {
3533
 
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3534
 
                                             sizeof(xmlNodePtr));
3535
 
        if (ret->nodeTab == NULL) {
3536
 
            xmlXPathErrMemory(NULL, "creating nodeset\n");
3537
 
            xmlFree(ret);
3538
 
            return(NULL);
3539
 
        }
3540
 
        memset(ret->nodeTab, 0 ,
3541
 
               XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3542
 
        ret->nodeMax = XML_NODESET_DEFAULT;
3543
 
        if (val->type == XML_NAMESPACE_DECL) {
3544
 
            xmlNsPtr ns = (xmlNsPtr) val;
3545
 
 
3546
 
            ret->nodeTab[ret->nodeNr++] =
3547
 
                xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3548
 
        } else
3549
 
            ret->nodeTab[ret->nodeNr++] = val;
3550
 
    }
3551
 
    return(ret);
3552
 
}
3553
 
 
3554
 
/**
3555
 
 * xmlXPathNodeSetCreateSize:
3556
 
 * @size:  the initial size of the set
3557
 
 *
3558
 
 * Create a new xmlNodeSetPtr of type double and of value @val
3559
 
 *
3560
 
 * Returns the newly created object.
3561
 
 */
3562
 
static xmlNodeSetPtr
3563
 
xmlXPathNodeSetCreateSize(int size) {
3564
 
    xmlNodeSetPtr ret;
3565
 
 
3566
 
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3567
 
    if (ret == NULL) {
3568
 
        xmlXPathErrMemory(NULL, "creating nodeset\n");
3569
 
        return(NULL);
3570
 
    }
3571
 
    memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3572
 
    if (size < XML_NODESET_DEFAULT)
3573
 
        size = XML_NODESET_DEFAULT;
3574
 
    ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3575
 
    if (ret->nodeTab == NULL) {
3576
 
        xmlXPathErrMemory(NULL, "creating nodeset\n");
3577
 
        xmlFree(ret);
3578
 
        return(NULL);
3579
 
    }
3580
 
    memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3581
 
    ret->nodeMax = size;
3582
 
    return(ret);
3583
 
}
3584
 
 
3585
 
/**
3586
 
 * xmlXPathNodeSetContains:
3587
 
 * @cur:  the node-set
3588
 
 * @val:  the node
3589
 
 *
3590
 
 * checks whether @cur contains @val
3591
 
 *
3592
 
 * Returns true (1) if @cur contains @val, false (0) otherwise
3593
 
 */
3594
 
int
3595
 
xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3596
 
    int i;
3597
 
 
3598
 
    if ((cur == NULL) || (val == NULL)) return(0);
3599
 
    if (val->type == XML_NAMESPACE_DECL) {
3600
 
        for (i = 0; i < cur->nodeNr; i++) {
3601
 
            if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3602
 
                xmlNsPtr ns1, ns2;
3603
 
 
3604
 
                ns1 = (xmlNsPtr) val;
3605
 
                ns2 = (xmlNsPtr) cur->nodeTab[i];
3606
 
                if (ns1 == ns2)
3607
 
                    return(1);
3608
 
                if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3609
 
                    (xmlStrEqual(ns1->prefix, ns2->prefix)))
3610
 
                    return(1);
3611
 
            }
3612
 
        }
3613
 
    } else {
3614
 
        for (i = 0; i < cur->nodeNr; i++) {
3615
 
            if (cur->nodeTab[i] == val)
3616
 
                return(1);
3617
 
        }
3618
 
    }
3619
 
    return(0);
3620
 
}
3621
 
 
3622
 
/**
3623
 
 * xmlXPathNodeSetAddNs:
3624
 
 * @cur:  the initial node set
3625
 
 * @node:  the hosting node
3626
 
 * @ns:  a the namespace node
3627
 
 *
3628
 
 * add a new namespace node to an existing NodeSet
3629
 
 *
3630
 
 * Returns 0 in case of success and -1 in case of error
3631
 
 */
3632
 
int
3633
 
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3634
 
    int i;
3635
 
 
3636
 
 
3637
 
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3638
 
        (ns->type != XML_NAMESPACE_DECL) ||
3639
 
        (node->type != XML_ELEMENT_NODE))
3640
 
        return(-1);
3641
 
 
3642
 
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3643
 
    /*
3644
 
     * prevent duplicates
3645
 
     */
3646
 
    for (i = 0;i < cur->nodeNr;i++) {
3647
 
        if ((cur->nodeTab[i] != NULL) &&
3648
 
            (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3649
 
            (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3650
 
            (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3651
 
            return(0);
3652
 
    }
3653
 
 
3654
 
    /*
3655
 
     * grow the nodeTab if needed
3656
 
     */
3657
 
    if (cur->nodeMax == 0) {
3658
 
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3659
 
                                             sizeof(xmlNodePtr));
3660
 
        if (cur->nodeTab == NULL) {
3661
 
            xmlXPathErrMemory(NULL, "growing nodeset\n");
3662
 
            return(-1);
3663
 
        }
3664
 
        memset(cur->nodeTab, 0 ,
3665
 
               XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3666
 
        cur->nodeMax = XML_NODESET_DEFAULT;
3667
 
    } else if (cur->nodeNr == cur->nodeMax) {
3668
 
        xmlNodePtr *temp;
3669
 
 
3670
 
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3671
 
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3672
 
            return(-1);
3673
 
        }
3674
 
        temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3675
 
                                      sizeof(xmlNodePtr));
3676
 
        if (temp == NULL) {
3677
 
            xmlXPathErrMemory(NULL, "growing nodeset\n");
3678
 
            return(-1);
3679
 
        }
3680
 
        cur->nodeMax *= 2;
3681
 
        cur->nodeTab = temp;
3682
 
    }
3683
 
    cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3684
 
    return(0);
3685
 
}
3686
 
 
3687
 
/**
3688
 
 * xmlXPathNodeSetAdd:
3689
 
 * @cur:  the initial node set
3690
 
 * @val:  a new xmlNodePtr
3691
 
 *
3692
 
 * add a new xmlNodePtr to an existing NodeSet
3693
 
 *
3694
 
 * Returns 0 in case of success, and -1 in case of error
3695
 
 */
3696
 
int
3697
 
xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3698
 
    int i;
3699
 
 
3700
 
    if ((cur == NULL) || (val == NULL)) return(-1);
3701
 
 
3702
 
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3703
 
    /*
3704
 
     * prevent duplcates
3705
 
     */
3706
 
    for (i = 0;i < cur->nodeNr;i++)
3707
 
        if (cur->nodeTab[i] == val) return(0);
3708
 
 
3709
 
    /*
3710
 
     * grow the nodeTab if needed
3711
 
     */
3712
 
    if (cur->nodeMax == 0) {
3713
 
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3714
 
                                             sizeof(xmlNodePtr));
3715
 
        if (cur->nodeTab == NULL) {
3716
 
            xmlXPathErrMemory(NULL, "growing nodeset\n");
3717
 
            return(-1);
3718
 
        }
3719
 
        memset(cur->nodeTab, 0 ,
3720
 
               XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3721
 
        cur->nodeMax = XML_NODESET_DEFAULT;
3722
 
    } else if (cur->nodeNr == cur->nodeMax) {
3723
 
        xmlNodePtr *temp;
3724
 
 
3725
 
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3726
 
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3727
 
            return(-1);
3728
 
        }
3729
 
        temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3730
 
                                      sizeof(xmlNodePtr));
3731
 
        if (temp == NULL) {
3732
 
            xmlXPathErrMemory(NULL, "growing nodeset\n");
3733
 
            return(-1);
3734
 
        }
3735
 
        cur->nodeMax *= 2;
3736
 
        cur->nodeTab = temp;
3737
 
    }
3738
 
    if (val->type == XML_NAMESPACE_DECL) {
3739
 
        xmlNsPtr ns = (xmlNsPtr) val;
3740
 
 
3741
 
        cur->nodeTab[cur->nodeNr++] =
3742
 
            xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3743
 
    } else
3744
 
        cur->nodeTab[cur->nodeNr++] = val;
3745
 
    return(0);
3746
 
}
3747
 
 
3748
 
/**
3749
 
 * xmlXPathNodeSetAddUnique:
3750
 
 * @cur:  the initial node set
3751
 
 * @val:  a new xmlNodePtr
3752
 
 *
3753
 
 * add a new xmlNodePtr to an existing NodeSet, optimized version
3754
 
 * when we are sure the node is not already in the set.
3755
 
 *
3756
 
 * Returns 0 in case of success and -1 in case of failure
3757
 
 */
3758
 
int
3759
 
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3760
 
    if ((cur == NULL) || (val == NULL)) return(-1);
3761
 
 
3762
 
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3763
 
    /*
3764
 
     * grow the nodeTab if needed
3765
 
     */
3766
 
    if (cur->nodeMax == 0) {
3767
 
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3768
 
                                             sizeof(xmlNodePtr));
3769
 
        if (cur->nodeTab == NULL) {
3770
 
            xmlXPathErrMemory(NULL, "growing nodeset\n");
3771
 
            return(-1);
3772
 
        }
3773
 
        memset(cur->nodeTab, 0 ,
3774
 
               XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3775
 
        cur->nodeMax = XML_NODESET_DEFAULT;
3776
 
    } else if (cur->nodeNr == cur->nodeMax) {
3777
 
        xmlNodePtr *temp;
3778
 
 
3779
 
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3780
 
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3781
 
            return(-1);
3782
 
        }
3783
 
        temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3784
 
                                      sizeof(xmlNodePtr));
3785
 
        if (temp == NULL) {
3786
 
            xmlXPathErrMemory(NULL, "growing nodeset\n");
3787
 
            return(-1);
3788
 
        }
3789
 
        cur->nodeTab = temp;
3790
 
        cur->nodeMax *= 2;
3791
 
    }
3792
 
    if (val->type == XML_NAMESPACE_DECL) {
3793
 
        xmlNsPtr ns = (xmlNsPtr) val;
3794
 
 
3795
 
        cur->nodeTab[cur->nodeNr++] =
3796
 
            xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3797
 
    } else
3798
 
        cur->nodeTab[cur->nodeNr++] = val;
3799
 
    return(0);
3800
 
}
3801
 
 
3802
 
/**
3803
 
 * xmlXPathNodeSetMerge:
3804
 
 * @val1:  the first NodeSet or NULL
3805
 
 * @val2:  the second NodeSet
3806
 
 *
3807
 
 * Merges two nodesets, all nodes from @val2 are added to @val1
3808
 
 * if @val1 is NULL, a new set is created and copied from @val2
3809
 
 *
3810
 
 * Returns @val1 once extended or NULL in case of error.
3811
 
 */
3812
 
xmlNodeSetPtr
3813
 
xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3814
 
    int i, j, initNr, skip;
3815
 
    xmlNodePtr n1, n2;
3816
 
 
3817
 
    if (val2 == NULL) return(val1);
3818
 
    if (val1 == NULL) {
3819
 
        val1 = xmlXPathNodeSetCreate(NULL);
3820
 
    if (val1 == NULL)
3821
 
        return (NULL);
3822
 
#if 0
3823
 
        /*
3824
 
        * TODO: The optimization won't work in every case, since
3825
 
        *  those nasty namespace nodes need to be added with
3826
 
        *  xmlXPathNodeSetDupNs() to the set; thus a pure
3827
 
        *  memcpy is not possible.
3828
 
        *  If there was a flag on the nodesetval, indicating that
3829
 
        *  some temporary nodes are in, that would be helpfull.
3830
 
        */
3831
 
        /*
3832
 
        * Optimization: Create an equally sized node-set
3833
 
        * and memcpy the content.
3834
 
        */
3835
 
        val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3836
 
        if (val1 == NULL)
3837
 
            return(NULL);
3838
 
        if (val2->nodeNr != 0) {
3839
 
            if (val2->nodeNr == 1)
3840
 
                *(val1->nodeTab) = *(val2->nodeTab);
3841
 
            else {
3842
 
                memcpy(val1->nodeTab, val2->nodeTab,
3843
 
                    val2->nodeNr * sizeof(xmlNodePtr));
3844
 
            }
3845
 
            val1->nodeNr = val2->nodeNr;
3846
 
        }
3847
 
        return(val1);
3848
 
#endif
3849
 
    }
3850
 
 
3851
 
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3852
 
    initNr = val1->nodeNr;
3853
 
 
3854
 
    for (i = 0;i < val2->nodeNr;i++) {
3855
 
        n2 = val2->nodeTab[i];
3856
 
        /*
3857
 
         * check against duplicates
3858
 
         */
3859
 
        skip = 0;
3860
 
        for (j = 0; j < initNr; j++) {
3861
 
            n1 = val1->nodeTab[j];
3862
 
            if (n1 == n2) {
3863
 
                skip = 1;
3864
 
                break;
3865
 
            } else if ((n1->type == XML_NAMESPACE_DECL) &&
3866
 
                       (n2->type == XML_NAMESPACE_DECL)) {
3867
 
                if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3868
 
                    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3869
 
                        ((xmlNsPtr) n2)->prefix)))
3870
 
                {
3871
 
                    skip = 1;
3872
 
                    break;
3873
 
                }
3874
 
            }
3875
 
        }
3876
 
        if (skip)
3877
 
            continue;
3878
 
 
3879
 
        /*
3880
 
         * grow the nodeTab if needed
3881
 
         */
3882
 
        if (val1->nodeMax == 0) {
3883
 
            val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3884
 
                                                    sizeof(xmlNodePtr));
3885
 
            if (val1->nodeTab == NULL) {
3886
 
                xmlXPathErrMemory(NULL, "merging nodeset\n");
3887
 
                return(NULL);
3888
 
            }
3889
 
            memset(val1->nodeTab, 0 ,
3890
 
                   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3891
 
            val1->nodeMax = XML_NODESET_DEFAULT;
3892
 
        } else if (val1->nodeNr == val1->nodeMax) {
3893
 
            xmlNodePtr *temp;
3894
 
 
3895
 
            if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3896
 
                xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3897
 
                return(NULL);
3898
 
            }
3899
 
            temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3900
 
                                             sizeof(xmlNodePtr));
3901
 
            if (temp == NULL) {
3902
 
                xmlXPathErrMemory(NULL, "merging nodeset\n");
3903
 
                return(NULL);
3904
 
            }
3905
 
            val1->nodeTab = temp;
3906
 
            val1->nodeMax *= 2;
3907
 
        }
3908
 
        if (n2->type == XML_NAMESPACE_DECL) {
3909
 
            xmlNsPtr ns = (xmlNsPtr) n2;
3910
 
 
3911
 
            val1->nodeTab[val1->nodeNr++] =
3912
 
                xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3913
 
        } else
3914
 
            val1->nodeTab[val1->nodeNr++] = n2;
3915
 
    }
3916
 
 
3917
 
    return(val1);
3918
 
}
3919
 
 
3920
 
 
3921
 
/**
3922
 
 * xmlXPathNodeSetMergeAndClear:
3923
 
 * @set1:  the first NodeSet or NULL
3924
 
 * @set2:  the second NodeSet
3925
 
 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3926
 
 *
3927
 
 * Merges two nodesets, all nodes from @set2 are added to @set1
3928
 
 * if @set1 is NULL, a new set is created and copied from @set2.
3929
 
 * Checks for duplicate nodes. Clears set2.
3930
 
 *
3931
 
 * Returns @set1 once extended or NULL in case of error.
3932
 
 */
3933
 
static xmlNodeSetPtr
3934
 
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3935
 
                             int hasNullEntries)
3936
 
{
3937
 
    if ((set1 == NULL) && (hasNullEntries == 0)) {
3938
 
        /*
3939
 
        * Note that doing a memcpy of the list, namespace nodes are
3940
 
        * just assigned to set1, since set2 is cleared anyway.
3941
 
        */
3942
 
        set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3943
 
        if (set1 == NULL)
3944
 
            return(NULL);
3945
 
        if (set2->nodeNr != 0) {
3946
 
            memcpy(set1->nodeTab, set2->nodeTab,
3947
 
                set2->nodeNr * sizeof(xmlNodePtr));
3948
 
            set1->nodeNr = set2->nodeNr;
3949
 
        }
3950
 
    } else {
3951
 
        int i, j, initNbSet1;
3952
 
        xmlNodePtr n1, n2;
3953
 
 
3954
 
        if (set1 == NULL)
3955
 
            set1 = xmlXPathNodeSetCreate(NULL);
3956
 
        if (set1 == NULL)
3957
 
            return (NULL);
3958
 
 
3959
 
        initNbSet1 = set1->nodeNr;
3960
 
        for (i = 0;i < set2->nodeNr;i++) {
3961
 
            n2 = set2->nodeTab[i];
3962
 
            /*
3963
 
            * Skip NULLed entries.
3964
 
            */
3965
 
            if (n2 == NULL)
3966
 
                continue;
3967
 
            /*
3968
 
            * Skip duplicates.
3969
 
            */
3970
 
            for (j = 0; j < initNbSet1; j++) {
3971
 
                n1 = set1->nodeTab[j];
3972
 
                if (n1 == n2) {
3973
 
                    goto skip_node;
3974
 
                } else if ((n1->type == XML_NAMESPACE_DECL) &&
3975
 
                    (n2->type == XML_NAMESPACE_DECL))
3976
 
                {
3977
 
                    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3978
 
                        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3979
 
                        ((xmlNsPtr) n2)->prefix)))
3980
 
                    {
3981
 
                        /*
3982
 
                        * Free the namespace node.
3983
 
                        */
3984
 
                        set2->nodeTab[i] = NULL;
3985
 
                        xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3986
 
                        goto skip_node;
3987
 
                    }
3988
 
                }
3989
 
            }
3990
 
            /*
3991
 
            * grow the nodeTab if needed
3992
 
            */
3993
 
            if (set1->nodeMax == 0) {
3994
 
                set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3995
 
                    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3996
 
                if (set1->nodeTab == NULL) {
3997
 
                    xmlXPathErrMemory(NULL, "merging nodeset\n");
3998
 
                    return(NULL);
3999
 
                }
4000
 
                memset(set1->nodeTab, 0,
4001
 
                    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4002
 
                set1->nodeMax = XML_NODESET_DEFAULT;
4003
 
            } else if (set1->nodeNr >= set1->nodeMax) {
4004
 
                xmlNodePtr *temp;
4005
 
 
4006
 
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4007
 
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4008
 
                    return(NULL);
4009
 
                }
4010
 
                temp = (xmlNodePtr *) xmlRealloc(
4011
 
                    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4012
 
                if (temp == NULL) {
4013
 
                    xmlXPathErrMemory(NULL, "merging nodeset\n");
4014
 
                    return(NULL);
4015
 
                }
4016
 
                set1->nodeTab = temp;
4017
 
                set1->nodeMax *= 2;
4018
 
            }
4019
 
            if (n2->type == XML_NAMESPACE_DECL) {
4020
 
                xmlNsPtr ns = (xmlNsPtr) n2;
4021
 
 
4022
 
                set1->nodeTab[set1->nodeNr++] =
4023
 
                    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
4024
 
            } else
4025
 
                set1->nodeTab[set1->nodeNr++] = n2;
4026
 
skip_node:
4027
 
            {}
4028
 
        }
4029
 
    }
4030
 
    set2->nodeNr = 0;
4031
 
    return(set1);
4032
 
}
4033
 
 
4034
 
/**
4035
 
 * xmlXPathNodeSetMergeAndClearNoDupls:
4036
 
 * @set1:  the first NodeSet or NULL
4037
 
 * @set2:  the second NodeSet
4038
 
 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4039
 
 *
4040
 
 * Merges two nodesets, all nodes from @set2 are added to @set1
4041
 
 * if @set1 is NULL, a new set is created and copied from @set2.
4042
 
 * Doesn't chack for duplicate nodes. Clears set2.
4043
 
 *
4044
 
 * Returns @set1 once extended or NULL in case of error.
4045
 
 */
4046
 
static xmlNodeSetPtr
4047
 
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4048
 
                                    int hasNullEntries)
4049
 
{
4050
 
    if (set2 == NULL)
4051
 
        return(set1);
4052
 
    if ((set1 == NULL) && (hasNullEntries == 0)) {
4053
 
        /*
4054
 
        * Note that doing a memcpy of the list, namespace nodes are
4055
 
        * just assigned to set1, since set2 is cleared anyway.
4056
 
        */
4057
 
        set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4058
 
        if (set1 == NULL)
4059
 
            return(NULL);
4060
 
        if (set2->nodeNr != 0) {
4061
 
            memcpy(set1->nodeTab, set2->nodeTab,
4062
 
                set2->nodeNr * sizeof(xmlNodePtr));
4063
 
            set1->nodeNr = set2->nodeNr;
4064
 
        }
4065
 
    } else {
4066
 
        int i;
4067
 
        xmlNodePtr n2;
4068
 
 
4069
 
        if (set1 == NULL)
4070
 
            set1 = xmlXPathNodeSetCreate(NULL);
4071
 
        if (set1 == NULL)
4072
 
            return (NULL);
4073
 
 
4074
 
        for (i = 0;i < set2->nodeNr;i++) {
4075
 
            n2 = set2->nodeTab[i];
4076
 
            /*
4077
 
            * Skip NULLed entries.
4078
 
            */
4079
 
            if (n2 == NULL)
4080
 
                continue;
4081
 
            if (set1->nodeMax == 0) {
4082
 
                set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4083
 
                    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4084
 
                if (set1->nodeTab == NULL) {
4085
 
                    xmlXPathErrMemory(NULL, "merging nodeset\n");
4086
 
                    return(NULL);
4087
 
                }
4088
 
                memset(set1->nodeTab, 0,
4089
 
                    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4090
 
                set1->nodeMax = XML_NODESET_DEFAULT;
4091
 
            } else if (set1->nodeNr >= set1->nodeMax) {
4092
 
                xmlNodePtr *temp;
4093
 
 
4094
 
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4095
 
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4096
 
                    return(NULL);
4097
 
                }
4098
 
                temp = (xmlNodePtr *) xmlRealloc(
4099
 
                    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4100
 
                if (temp == NULL) {
4101
 
                    xmlXPathErrMemory(NULL, "merging nodeset\n");
4102
 
                    return(NULL);
4103
 
                }
4104
 
                set1->nodeTab = temp;
4105
 
                set1->nodeMax *= 2;
4106
 
            }
4107
 
            set1->nodeTab[set1->nodeNr++] = n2;
4108
 
        }
4109
 
    }
4110
 
    set2->nodeNr = 0;
4111
 
    return(set1);
4112
 
}
4113
 
 
4114
 
/**
4115
 
 * xmlXPathNodeSetDel:
4116
 
 * @cur:  the initial node set
4117
 
 * @val:  an xmlNodePtr
4118
 
 *
4119
 
 * Removes an xmlNodePtr from an existing NodeSet
4120
 
 */
4121
 
void
4122
 
xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4123
 
    int i;
4124
 
 
4125
 
    if (cur == NULL) return;
4126
 
    if (val == NULL) return;
4127
 
 
4128
 
    /*
4129
 
     * find node in nodeTab
4130
 
     */
4131
 
    for (i = 0;i < cur->nodeNr;i++)
4132
 
        if (cur->nodeTab[i] == val) break;
4133
 
 
4134
 
    if (i >= cur->nodeNr) {     /* not found */
4135
 
#ifdef DEBUG
4136
 
        xmlGenericError(xmlGenericErrorContext,
4137
 
                "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4138
 
                val->name);
4139
 
#endif
4140
 
        return;
4141
 
    }
4142
 
    if ((cur->nodeTab[i] != NULL) &&
4143
 
        (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4144
 
        xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4145
 
    cur->nodeNr--;
4146
 
    for (;i < cur->nodeNr;i++)
4147
 
        cur->nodeTab[i] = cur->nodeTab[i + 1];
4148
 
    cur->nodeTab[cur->nodeNr] = NULL;
4149
 
}
4150
 
 
4151
 
/**
4152
 
 * xmlXPathNodeSetRemove:
4153
 
 * @cur:  the initial node set
4154
 
 * @val:  the index to remove
4155
 
 *
4156
 
 * Removes an entry from an existing NodeSet list.
4157
 
 */
4158
 
void
4159
 
xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4160
 
    if (cur == NULL) return;
4161
 
    if (val >= cur->nodeNr) return;
4162
 
    if ((cur->nodeTab[val] != NULL) &&
4163
 
        (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4164
 
        xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4165
 
    cur->nodeNr--;
4166
 
    for (;val < cur->nodeNr;val++)
4167
 
        cur->nodeTab[val] = cur->nodeTab[val + 1];
4168
 
    cur->nodeTab[cur->nodeNr] = NULL;
4169
 
}
4170
 
 
4171
 
/**
4172
 
 * xmlXPathFreeNodeSet:
4173
 
 * @obj:  the xmlNodeSetPtr to free
4174
 
 *
4175
 
 * Free the NodeSet compound (not the actual nodes !).
4176
 
 */
4177
 
void
4178
 
xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4179
 
    if (obj == NULL) return;
4180
 
    if (obj->nodeTab != NULL) {
4181
 
        int i;
4182
 
 
4183
 
        /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4184
 
        for (i = 0;i < obj->nodeNr;i++)
4185
 
            if ((obj->nodeTab[i] != NULL) &&
4186
 
                (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4187
 
                xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4188
 
        xmlFree(obj->nodeTab);
4189
 
    }
4190
 
    xmlFree(obj);
4191
 
}
4192
 
 
4193
 
/**
4194
 
 * xmlXPathNodeSetClear:
4195
 
 * @set:  the node set to clear
4196
 
 *
4197
 
 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4198
 
 * are feed), but does *not* free the list itself. Sets the length of the
4199
 
 * list to 0.
4200
 
 */
4201
 
static void
4202
 
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4203
 
{
4204
 
    if ((set == NULL) || (set->nodeNr <= 0))
4205
 
        return;
4206
 
    else if (hasNsNodes) {
4207
 
        int i;
4208
 
        xmlNodePtr node;
4209
 
 
4210
 
        for (i = 0; i < set->nodeNr; i++) {
4211
 
            node = set->nodeTab[i];
4212
 
            if ((node != NULL) &&
4213
 
                (node->type == XML_NAMESPACE_DECL))
4214
 
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4215
 
        }
4216
 
    }
4217
 
    set->nodeNr = 0;
4218
 
}
4219
 
 
4220
 
/**
4221
 
 * xmlXPathNodeSetClearFromPos:
4222
 
 * @set: the node set to be cleared
4223
 
 * @pos: the start position to clear from
4224
 
 *
4225
 
 * Clears the list from temporary XPath objects (e.g. namespace nodes
4226
 
 * are feed) starting with the entry at @pos, but does *not* free the list
4227
 
 * itself. Sets the length of the list to @pos.
4228
 
 */
4229
 
static void
4230
 
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4231
 
{
4232
 
    if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4233
 
        return;
4234
 
    else if ((hasNsNodes)) {
4235
 
        int i;
4236
 
        xmlNodePtr node;
4237
 
 
4238
 
        for (i = pos; i < set->nodeNr; i++) {
4239
 
            node = set->nodeTab[i];
4240
 
            if ((node != NULL) &&
4241
 
                (node->type == XML_NAMESPACE_DECL))
4242
 
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4243
 
        }
4244
 
    }
4245
 
    set->nodeNr = pos;
4246
 
}
4247
 
 
4248
 
/**
4249
 
 * xmlXPathFreeValueTree:
4250
 
 * @obj:  the xmlNodeSetPtr to free
4251
 
 *
4252
 
 * Free the NodeSet compound and the actual tree, this is different
4253
 
 * from xmlXPathFreeNodeSet()
4254
 
 */
4255
 
static void
4256
 
xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4257
 
    int i;
4258
 
 
4259
 
    if (obj == NULL) return;
4260
 
 
4261
 
    if (obj->nodeTab != NULL) {
4262
 
        for (i = 0;i < obj->nodeNr;i++) {
4263
 
            if (obj->nodeTab[i] != NULL) {
4264
 
                if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4265
 
                    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4266
 
                } else {
4267
 
                    xmlFreeNodeList(obj->nodeTab[i]);
4268
 
                }
4269
 
            }
4270
 
        }
4271
 
        xmlFree(obj->nodeTab);
4272
 
    }
4273
 
    xmlFree(obj);
4274
 
}
4275
 
 
4276
 
#if defined(DEBUG) || defined(DEBUG_STEP)
4277
 
/**
4278
 
 * xmlGenericErrorContextNodeSet:
4279
 
 * @output:  a FILE * for the output
4280
 
 * @obj:  the xmlNodeSetPtr to display
4281
 
 *
4282
 
 * Quick display of a NodeSet
4283
 
 */
4284
 
void
4285
 
xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4286
 
    int i;
4287
 
 
4288
 
    if (output == NULL) output = xmlGenericErrorContext;
4289
 
    if (obj == NULL)  {
4290
 
        fprintf(output, "NodeSet == NULL !\n");
4291
 
        return;
4292
 
    }
4293
 
    if (obj->nodeNr == 0) {
4294
 
        fprintf(output, "NodeSet is empty\n");
4295
 
        return;
4296
 
    }
4297
 
    if (obj->nodeTab == NULL) {
4298
 
        fprintf(output, " nodeTab == NULL !\n");
4299
 
        return;
4300
 
    }
4301
 
    for (i = 0; i < obj->nodeNr; i++) {
4302
 
        if (obj->nodeTab[i] == NULL) {
4303
 
            fprintf(output, " NULL !\n");
4304
 
            return;
4305
 
        }
4306
 
        if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4307
 
            (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4308
 
            fprintf(output, " /");
4309
 
        else if (obj->nodeTab[i]->name == NULL)
4310
 
            fprintf(output, " noname!");
4311
 
        else fprintf(output, " %s", obj->nodeTab[i]->name);
4312
 
    }
4313
 
    fprintf(output, "\n");
4314
 
}
4315
 
#endif
4316
 
 
4317
 
/**
4318
 
 * xmlXPathNewNodeSet:
4319
 
 * @val:  the NodePtr value
4320
 
 *
4321
 
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4322
 
 * it with the single Node @val
4323
 
 *
4324
 
 * Returns the newly created object.
4325
 
 */
4326
 
xmlXPathObjectPtr
4327
 
xmlXPathNewNodeSet(xmlNodePtr val) {
4328
 
    xmlXPathObjectPtr ret;
4329
 
 
4330
 
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4331
 
    if (ret == NULL) {
4332
 
        xmlXPathErrMemory(NULL, "creating nodeset\n");
4333
 
        return(NULL);
4334
 
    }
4335
 
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4336
 
    ret->type = XPATH_NODESET;
4337
 
    ret->boolval = 0;
4338
 
    ret->nodesetval = xmlXPathNodeSetCreate(val);
4339
 
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4340
 
#ifdef XP_DEBUG_OBJ_USAGE
4341
 
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4342
 
#endif
4343
 
    return(ret);
4344
 
}
4345
 
 
4346
 
/**
4347
 
 * xmlXPathNewValueTree:
4348
 
 * @val:  the NodePtr value
4349
 
 *
4350
 
 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4351
 
 * it with the tree root @val
4352
 
 *
4353
 
 * Returns the newly created object.
4354
 
 */
4355
 
xmlXPathObjectPtr
4356
 
xmlXPathNewValueTree(xmlNodePtr val) {
4357
 
    xmlXPathObjectPtr ret;
4358
 
 
4359
 
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4360
 
    if (ret == NULL) {
4361
 
        xmlXPathErrMemory(NULL, "creating result value tree\n");
4362
 
        return(NULL);
4363
 
    }
4364
 
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4365
 
    ret->type = XPATH_XSLT_TREE;
4366
 
    ret->boolval = 1;
4367
 
    ret->user = (void *) val;
4368
 
    ret->nodesetval = xmlXPathNodeSetCreate(val);
4369
 
#ifdef XP_DEBUG_OBJ_USAGE
4370
 
    xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4371
 
#endif
4372
 
    return(ret);
4373
 
}
4374
 
 
4375
 
/**
4376
 
 * xmlXPathNewNodeSetList:
4377
 
 * @val:  an existing NodeSet
4378
 
 *
4379
 
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4380
 
 * it with the Nodeset @val
4381
 
 *
4382
 
 * Returns the newly created object.
4383
 
 */
4384
 
xmlXPathObjectPtr
4385
 
xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4386
 
{
4387
 
    xmlXPathObjectPtr ret;
4388
 
    int i;
4389
 
 
4390
 
    if (val == NULL)
4391
 
        ret = NULL;
4392
 
    else if (val->nodeTab == NULL)
4393
 
        ret = xmlXPathNewNodeSet(NULL);
4394
 
    else {
4395
 
        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4396
 
        if (ret) {
4397
 
            for (i = 1; i < val->nodeNr; ++i) {
4398
 
                if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4399
 
                    < 0) break;
4400
 
            }
4401
 
        }
4402
 
    }
4403
 
 
4404
 
    return (ret);
4405
 
}
4406
 
 
4407
 
/**
4408
 
 * xmlXPathWrapNodeSet:
4409
 
 * @val:  the NodePtr value
4410
 
 *
4411
 
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4412
 
 *
4413
 
 * Returns the newly created object.
4414
 
 */
4415
 
xmlXPathObjectPtr
4416
 
xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4417
 
    xmlXPathObjectPtr ret;
4418
 
 
4419
 
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4420
 
    if (ret == NULL) {
4421
 
        xmlXPathErrMemory(NULL, "creating node set object\n");
4422
 
        return(NULL);
4423
 
    }
4424
 
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4425
 
    ret->type = XPATH_NODESET;
4426
 
    ret->nodesetval = val;
4427
 
#ifdef XP_DEBUG_OBJ_USAGE
4428
 
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4429
 
#endif
4430
 
    return(ret);
4431
 
}
4432
 
 
4433
 
/**
4434
 
 * xmlXPathFreeNodeSetList:
4435
 
 * @obj:  an existing NodeSetList object
4436
 
 *
4437
 
 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4438
 
 * the list contrary to xmlXPathFreeObject().
4439
 
 */
4440
 
void
4441
 
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4442
 
    if (obj == NULL) return;
4443
 
#ifdef XP_DEBUG_OBJ_USAGE
4444
 
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
4445
 
#endif
4446
 
    xmlFree(obj);
4447
 
}
4448
 
 
4449
 
/**
4450
 
 * xmlXPathDifference:
4451
 
 * @nodes1:  a node-set
4452
 
 * @nodes2:  a node-set
4453
 
 *
4454
 
 * Implements the EXSLT - Sets difference() function:
4455
 
 *    node-set set:difference (node-set, node-set)
4456
 
 *
4457
 
 * Returns the difference between the two node sets, or nodes1 if
4458
 
 *         nodes2 is empty
4459
 
 */
4460
 
xmlNodeSetPtr
4461
 
xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4462
 
    xmlNodeSetPtr ret;
4463
 
    int i, l1;
4464
 
    xmlNodePtr cur;
4465
 
 
4466
 
    if (xmlXPathNodeSetIsEmpty(nodes2))
4467
 
        return(nodes1);
4468
 
 
4469
 
    ret = xmlXPathNodeSetCreate(NULL);
4470
 
    if (xmlXPathNodeSetIsEmpty(nodes1))
4471
 
        return(ret);
4472
 
 
4473
 
    l1 = xmlXPathNodeSetGetLength(nodes1);
4474
 
 
4475
 
    for (i = 0; i < l1; i++) {
4476
 
        cur = xmlXPathNodeSetItem(nodes1, i);
4477
 
        if (!xmlXPathNodeSetContains(nodes2, cur)) {
4478
 
            if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4479
 
                break;
4480
 
        }
4481
 
    }
4482
 
    return(ret);
4483
 
}
4484
 
 
4485
 
/**
4486
 
 * xmlXPathIntersection:
4487
 
 * @nodes1:  a node-set
4488
 
 * @nodes2:  a node-set
4489
 
 *
4490
 
 * Implements the EXSLT - Sets intersection() function:
4491
 
 *    node-set set:intersection (node-set, node-set)
4492
 
 *
4493
 
 * Returns a node set comprising the nodes that are within both the
4494
 
 *         node sets passed as arguments
4495
 
 */
4496
 
xmlNodeSetPtr
4497
 
xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4498
 
    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4499
 
    int i, l1;
4500
 
    xmlNodePtr cur;
4501
 
 
4502
 
    if (ret == NULL)
4503
 
        return(ret);
4504
 
    if (xmlXPathNodeSetIsEmpty(nodes1))
4505
 
        return(ret);
4506
 
    if (xmlXPathNodeSetIsEmpty(nodes2))
4507
 
        return(ret);
4508
 
 
4509
 
    l1 = xmlXPathNodeSetGetLength(nodes1);
4510
 
 
4511
 
    for (i = 0; i < l1; i++) {
4512
 
        cur = xmlXPathNodeSetItem(nodes1, i);
4513
 
        if (xmlXPathNodeSetContains(nodes2, cur)) {
4514
 
            if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4515
 
                break;
4516
 
        }
4517
 
    }
4518
 
    return(ret);
4519
 
}
4520
 
 
4521
 
/**
4522
 
 * xmlXPathDistinctSorted:
4523
 
 * @nodes:  a node-set, sorted by document order
4524
 
 *
4525
 
 * Implements the EXSLT - Sets distinct() function:
4526
 
 *    node-set set:distinct (node-set)
4527
 
 *
4528
 
 * Returns a subset of the nodes contained in @nodes, or @nodes if
4529
 
 *         it is empty
4530
 
 */
4531
 
xmlNodeSetPtr
4532
 
xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4533
 
    xmlNodeSetPtr ret;
4534
 
    xmlHashTablePtr hash;
4535
 
    int i, l;
4536
 
    xmlChar * strval;
4537
 
    xmlNodePtr cur;
4538
 
 
4539
 
    if (xmlXPathNodeSetIsEmpty(nodes))
4540
 
        return(nodes);
4541
 
 
4542
 
    ret = xmlXPathNodeSetCreate(NULL);
4543
 
    if (ret == NULL)
4544
 
        return(ret);
4545
 
    l = xmlXPathNodeSetGetLength(nodes);
4546
 
    hash = xmlHashCreate (l);
4547
 
    for (i = 0; i < l; i++) {
4548
 
        cur = xmlXPathNodeSetItem(nodes, i);
4549
 
        strval = xmlXPathCastNodeToString(cur);
4550
 
        if (xmlHashLookup(hash, strval) == NULL) {
4551
 
            xmlHashAddEntry(hash, strval, strval);
4552
 
            if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4553
 
                break;
4554
 
        } else {
4555
 
            xmlFree(strval);
4556
 
        }
4557
 
    }
4558
 
    xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4559
 
    return(ret);
4560
 
}
4561
 
 
4562
 
/**
4563
 
 * xmlXPathDistinct:
4564
 
 * @nodes:  a node-set
4565
 
 *
4566
 
 * Implements the EXSLT - Sets distinct() function:
4567
 
 *    node-set set:distinct (node-set)
4568
 
 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4569
 
 * is called with the sorted node-set
4570
 
 *
4571
 
 * Returns a subset of the nodes contained in @nodes, or @nodes if
4572
 
 *         it is empty
4573
 
 */
4574
 
xmlNodeSetPtr
4575
 
xmlXPathDistinct (xmlNodeSetPtr nodes) {
4576
 
    if (xmlXPathNodeSetIsEmpty(nodes))
4577
 
        return(nodes);
4578
 
 
4579
 
    xmlXPathNodeSetSort(nodes);
4580
 
    return(xmlXPathDistinctSorted(nodes));
4581
 
}
4582
 
 
4583
 
/**
4584
 
 * xmlXPathHasSameNodes:
4585
 
 * @nodes1:  a node-set
4586
 
 * @nodes2:  a node-set
4587
 
 *
4588
 
 * Implements the EXSLT - Sets has-same-nodes function:
4589
 
 *    boolean set:has-same-node(node-set, node-set)
4590
 
 *
4591
 
 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4592
 
 *         otherwise
4593
 
 */
4594
 
int
4595
 
xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4596
 
    int i, l;
4597
 
    xmlNodePtr cur;
4598
 
 
4599
 
    if (xmlXPathNodeSetIsEmpty(nodes1) ||
4600
 
        xmlXPathNodeSetIsEmpty(nodes2))
4601
 
        return(0);
4602
 
 
4603
 
    l = xmlXPathNodeSetGetLength(nodes1);
4604
 
    for (i = 0; i < l; i++) {
4605
 
        cur = xmlXPathNodeSetItem(nodes1, i);
4606
 
        if (xmlXPathNodeSetContains(nodes2, cur))
4607
 
            return(1);
4608
 
    }
4609
 
    return(0);
4610
 
}
4611
 
 
4612
 
/**
4613
 
 * xmlXPathNodeLeadingSorted:
4614
 
 * @nodes: a node-set, sorted by document order
4615
 
 * @node: a node
4616
 
 *
4617
 
 * Implements the EXSLT - Sets leading() function:
4618
 
 *    node-set set:leading (node-set, node-set)
4619
 
 *
4620
 
 * Returns the nodes in @nodes that precede @node in document order,
4621
 
 *         @nodes if @node is NULL or an empty node-set if @nodes
4622
 
 *         doesn't contain @node
4623
 
 */
4624
 
xmlNodeSetPtr
4625
 
xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4626
 
    int i, l;
4627
 
    xmlNodePtr cur;
4628
 
    xmlNodeSetPtr ret;
4629
 
 
4630
 
    if (node == NULL)
4631
 
        return(nodes);
4632
 
 
4633
 
    ret = xmlXPathNodeSetCreate(NULL);
4634
 
    if (ret == NULL)
4635
 
        return(ret);
4636
 
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4637
 
        (!xmlXPathNodeSetContains(nodes, node)))
4638
 
        return(ret);
4639
 
 
4640
 
    l = xmlXPathNodeSetGetLength(nodes);
4641
 
    for (i = 0; i < l; i++) {
4642
 
        cur = xmlXPathNodeSetItem(nodes, i);
4643
 
        if (cur == node)
4644
 
            break;
4645
 
        if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4646
 
            break;
4647
 
    }
4648
 
    return(ret);
4649
 
}
4650
 
 
4651
 
/**
4652
 
 * xmlXPathNodeLeading:
4653
 
 * @nodes:  a node-set
4654
 
 * @node:  a node
4655
 
 *
4656
 
 * Implements the EXSLT - Sets leading() function:
4657
 
 *    node-set set:leading (node-set, node-set)
4658
 
 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4659
 
 * is called.
4660
 
 *
4661
 
 * Returns the nodes in @nodes that precede @node in document order,
4662
 
 *         @nodes if @node is NULL or an empty node-set if @nodes
4663
 
 *         doesn't contain @node
4664
 
 */
4665
 
xmlNodeSetPtr
4666
 
xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4667
 
    xmlXPathNodeSetSort(nodes);
4668
 
    return(xmlXPathNodeLeadingSorted(nodes, node));
4669
 
}
4670
 
 
4671
 
/**
4672
 
 * xmlXPathLeadingSorted:
4673
 
 * @nodes1:  a node-set, sorted by document order
4674
 
 * @nodes2:  a node-set, sorted by document order
4675
 
 *
4676
 
 * Implements the EXSLT - Sets leading() function:
4677
 
 *    node-set set:leading (node-set, node-set)
4678
 
 *
4679
 
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4680
 
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4681
 
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4682
 
 */
4683
 
xmlNodeSetPtr
4684
 
xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4685
 
    if (xmlXPathNodeSetIsEmpty(nodes2))
4686
 
        return(nodes1);
4687
 
    return(xmlXPathNodeLeadingSorted(nodes1,
4688
 
                                     xmlXPathNodeSetItem(nodes2, 1)));
4689
 
}
4690
 
 
4691
 
/**
4692
 
 * xmlXPathLeading:
4693
 
 * @nodes1:  a node-set
4694
 
 * @nodes2:  a node-set
4695
 
 *
4696
 
 * Implements the EXSLT - Sets leading() function:
4697
 
 *    node-set set:leading (node-set, node-set)
4698
 
 * @nodes1 and @nodes2 are sorted by document order, then
4699
 
 * #exslSetsLeadingSorted is called.
4700
 
 *
4701
 
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4702
 
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4703
 
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4704
 
 */
4705
 
xmlNodeSetPtr
4706
 
xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4707
 
    if (xmlXPathNodeSetIsEmpty(nodes2))
4708
 
        return(nodes1);
4709
 
    if (xmlXPathNodeSetIsEmpty(nodes1))
4710
 
        return(xmlXPathNodeSetCreate(NULL));
4711
 
    xmlXPathNodeSetSort(nodes1);
4712
 
    xmlXPathNodeSetSort(nodes2);
4713
 
    return(xmlXPathNodeLeadingSorted(nodes1,
4714
 
                                     xmlXPathNodeSetItem(nodes2, 1)));
4715
 
}
4716
 
 
4717
 
/**
4718
 
 * xmlXPathNodeTrailingSorted:
4719
 
 * @nodes: a node-set, sorted by document order
4720
 
 * @node: a node
4721
 
 *
4722
 
 * Implements the EXSLT - Sets trailing() function:
4723
 
 *    node-set set:trailing (node-set, node-set)
4724
 
 *
4725
 
 * Returns the nodes in @nodes that follow @node in document order,
4726
 
 *         @nodes if @node is NULL or an empty node-set if @nodes
4727
 
 *         doesn't contain @node
4728
 
 */
4729
 
xmlNodeSetPtr
4730
 
xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4731
 
    int i, l;
4732
 
    xmlNodePtr cur;
4733
 
    xmlNodeSetPtr ret;
4734
 
 
4735
 
    if (node == NULL)
4736
 
        return(nodes);
4737
 
 
4738
 
    ret = xmlXPathNodeSetCreate(NULL);
4739
 
    if (ret == NULL)
4740
 
        return(ret);
4741
 
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4742
 
        (!xmlXPathNodeSetContains(nodes, node)))
4743
 
        return(ret);
4744
 
 
4745
 
    l = xmlXPathNodeSetGetLength(nodes);
4746
 
    for (i = l - 1; i >= 0; i--) {
4747
 
        cur = xmlXPathNodeSetItem(nodes, i);
4748
 
        if (cur == node)
4749
 
            break;
4750
 
        if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4751
 
            break;
4752
 
    }
4753
 
    xmlXPathNodeSetSort(ret);   /* bug 413451 */
4754
 
    return(ret);
4755
 
}
4756
 
 
4757
 
/**
4758
 
 * xmlXPathNodeTrailing:
4759
 
 * @nodes:  a node-set
4760
 
 * @node:  a node
4761
 
 *
4762
 
 * Implements the EXSLT - Sets trailing() function:
4763
 
 *    node-set set:trailing (node-set, node-set)
4764
 
 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4765
 
 * is called.
4766
 
 *
4767
 
 * Returns the nodes in @nodes that follow @node in document order,
4768
 
 *         @nodes if @node is NULL or an empty node-set if @nodes
4769
 
 *         doesn't contain @node
4770
 
 */
4771
 
xmlNodeSetPtr
4772
 
xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4773
 
    xmlXPathNodeSetSort(nodes);
4774
 
    return(xmlXPathNodeTrailingSorted(nodes, node));
4775
 
}
4776
 
 
4777
 
/**
4778
 
 * xmlXPathTrailingSorted:
4779
 
 * @nodes1:  a node-set, sorted by document order
4780
 
 * @nodes2:  a node-set, sorted by document order
4781
 
 *
4782
 
 * Implements the EXSLT - Sets trailing() function:
4783
 
 *    node-set set:trailing (node-set, node-set)
4784
 
 *
4785
 
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4786
 
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4787
 
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4788
 
 */
4789
 
xmlNodeSetPtr
4790
 
xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4791
 
    if (xmlXPathNodeSetIsEmpty(nodes2))
4792
 
        return(nodes1);
4793
 
    return(xmlXPathNodeTrailingSorted(nodes1,
4794
 
                                      xmlXPathNodeSetItem(nodes2, 0)));
4795
 
}
4796
 
 
4797
 
/**
4798
 
 * xmlXPathTrailing:
4799
 
 * @nodes1:  a node-set
4800
 
 * @nodes2:  a node-set
4801
 
 *
4802
 
 * Implements the EXSLT - Sets trailing() function:
4803
 
 *    node-set set:trailing (node-set, node-set)
4804
 
 * @nodes1 and @nodes2 are sorted by document order, then
4805
 
 * #xmlXPathTrailingSorted is called.
4806
 
 *
4807
 
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4808
 
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4809
 
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4810
 
 */
4811
 
xmlNodeSetPtr
4812
 
xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4813
 
    if (xmlXPathNodeSetIsEmpty(nodes2))
4814
 
        return(nodes1);
4815
 
    if (xmlXPathNodeSetIsEmpty(nodes1))
4816
 
        return(xmlXPathNodeSetCreate(NULL));
4817
 
    xmlXPathNodeSetSort(nodes1);
4818
 
    xmlXPathNodeSetSort(nodes2);
4819
 
    return(xmlXPathNodeTrailingSorted(nodes1,
4820
 
                                      xmlXPathNodeSetItem(nodes2, 0)));
4821
 
}
4822
 
 
4823
 
/************************************************************************
4824
 
 *                                                                      *
4825
 
 *              Routines to handle extra functions                      *
4826
 
 *                                                                      *
4827
 
 ************************************************************************/
4828
 
 
4829
 
/**
4830
 
 * xmlXPathRegisterFunc:
4831
 
 * @ctxt:  the XPath context
4832
 
 * @name:  the function name
4833
 
 * @f:  the function implementation or NULL
4834
 
 *
4835
 
 * Register a new function. If @f is NULL it unregisters the function
4836
 
 *
4837
 
 * Returns 0 in case of success, -1 in case of error
4838
 
 */
4839
 
int
4840
 
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4841
 
                     xmlXPathFunction f) {
4842
 
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4843
 
}
4844
 
 
4845
 
/**
4846
 
 * xmlXPathRegisterFuncNS:
4847
 
 * @ctxt:  the XPath context
4848
 
 * @name:  the function name
4849
 
 * @ns_uri:  the function namespace URI
4850
 
 * @f:  the function implementation or NULL
4851
 
 *
4852
 
 * Register a new function. If @f is NULL it unregisters the function
4853
 
 *
4854
 
 * Returns 0 in case of success, -1 in case of error
4855
 
 */
4856
 
int
4857
 
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4858
 
                       const xmlChar *ns_uri, xmlXPathFunction f) {
4859
 
    if (ctxt == NULL)
4860
 
        return(-1);
4861
 
    if (name == NULL)
4862
 
        return(-1);
4863
 
 
4864
 
    if (ctxt->funcHash == NULL)
4865
 
        ctxt->funcHash = xmlHashCreate(0);
4866
 
    if (ctxt->funcHash == NULL)
4867
 
        return(-1);
4868
 
    if (f == NULL)
4869
 
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4870
 
    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4871
 
}
4872
 
 
4873
 
/**
4874
 
 * xmlXPathRegisterFuncLookup:
4875
 
 * @ctxt:  the XPath context
4876
 
 * @f:  the lookup function
4877
 
 * @funcCtxt:  the lookup data
4878
 
 *
4879
 
 * Registers an external mechanism to do function lookup.
4880
 
 */
4881
 
void
4882
 
xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4883
 
                            xmlXPathFuncLookupFunc f,
4884
 
                            void *funcCtxt) {
4885
 
    if (ctxt == NULL)
4886
 
        return;
4887
 
    ctxt->funcLookupFunc = f;
4888
 
    ctxt->funcLookupData = funcCtxt;
4889
 
}
4890
 
 
4891
 
/**
4892
 
 * xmlXPathFunctionLookup:
4893
 
 * @ctxt:  the XPath context
4894
 
 * @name:  the function name
4895
 
 *
4896
 
 * Search in the Function array of the context for the given
4897
 
 * function.
4898
 
 *
4899
 
 * Returns the xmlXPathFunction or NULL if not found
4900
 
 */
4901
 
xmlXPathFunction
4902
 
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4903
 
    if (ctxt == NULL)
4904
 
        return (NULL);
4905
 
 
4906
 
    if (ctxt->funcLookupFunc != NULL) {
4907
 
        xmlXPathFunction ret;
4908
 
        xmlXPathFuncLookupFunc f;
4909
 
 
4910
 
        f = ctxt->funcLookupFunc;
4911
 
        ret = f(ctxt->funcLookupData, name, NULL);
4912
 
        if (ret != NULL)
4913
 
            return(ret);
4914
 
    }
4915
 
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4916
 
}
4917
 
 
4918
 
/**
4919
 
 * xmlXPathFunctionLookupNS:
4920
 
 * @ctxt:  the XPath context
4921
 
 * @name:  the function name
4922
 
 * @ns_uri:  the function namespace URI
4923
 
 *
4924
 
 * Search in the Function array of the context for the given
4925
 
 * function.
4926
 
 *
4927
 
 * Returns the xmlXPathFunction or NULL if not found
4928
 
 */
4929
 
xmlXPathFunction
4930
 
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4931
 
                         const xmlChar *ns_uri) {
4932
 
    xmlXPathFunction ret;
4933
 
 
4934
 
    if (ctxt == NULL)
4935
 
        return(NULL);
4936
 
    if (name == NULL)
4937
 
        return(NULL);
4938
 
 
4939
 
    if (ctxt->funcLookupFunc != NULL) {
4940
 
        xmlXPathFuncLookupFunc f;
4941
 
 
4942
 
        f = ctxt->funcLookupFunc;
4943
 
        ret = f(ctxt->funcLookupData, name, ns_uri);
4944
 
        if (ret != NULL)
4945
 
            return(ret);
4946
 
    }
4947
 
 
4948
 
    if (ctxt->funcHash == NULL)
4949
 
        return(NULL);
4950
 
 
4951
 
    XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4952
 
    return(ret);
4953
 
}
4954
 
 
4955
 
/**
4956
 
 * xmlXPathRegisteredFuncsCleanup:
4957
 
 * @ctxt:  the XPath context
4958
 
 *
4959
 
 * Cleanup the XPath context data associated to registered functions
4960
 
 */
4961
 
void
4962
 
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4963
 
    if (ctxt == NULL)
4964
 
        return;
4965
 
 
4966
 
    xmlHashFree(ctxt->funcHash, NULL);
4967
 
    ctxt->funcHash = NULL;
4968
 
}
4969
 
 
4970
 
/************************************************************************
4971
 
 *                                                                      *
4972
 
 *                      Routines to handle Variables                    *
4973
 
 *                                                                      *
4974
 
 ************************************************************************/
4975
 
 
4976
 
/**
4977
 
 * xmlXPathRegisterVariable:
4978
 
 * @ctxt:  the XPath context
4979
 
 * @name:  the variable name
4980
 
 * @value:  the variable value or NULL
4981
 
 *
4982
 
 * Register a new variable value. If @value is NULL it unregisters
4983
 
 * the variable
4984
 
 *
4985
 
 * Returns 0 in case of success, -1 in case of error
4986
 
 */
4987
 
int
4988
 
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4989
 
                         xmlXPathObjectPtr value) {
4990
 
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4991
 
}
4992
 
 
4993
 
/**
4994
 
 * xmlXPathRegisterVariableNS:
4995
 
 * @ctxt:  the XPath context
4996
 
 * @name:  the variable name
4997
 
 * @ns_uri:  the variable namespace URI
4998
 
 * @value:  the variable value or NULL
4999
 
 *
5000
 
 * Register a new variable value. If @value is NULL it unregisters
5001
 
 * the variable
5002
 
 *
5003
 
 * Returns 0 in case of success, -1 in case of error
5004
 
 */
5005
 
int
5006
 
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5007
 
                           const xmlChar *ns_uri,
5008
 
                           xmlXPathObjectPtr value) {
5009
 
    if (ctxt == NULL)
5010
 
        return(-1);
5011
 
    if (name == NULL)
5012
 
        return(-1);
5013
 
 
5014
 
    if (ctxt->varHash == NULL)
5015
 
        ctxt->varHash = xmlHashCreate(0);
5016
 
    if (ctxt->varHash == NULL)
5017
 
        return(-1);
5018
 
    if (value == NULL)
5019
 
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5020
 
                                   (xmlHashDeallocator)xmlXPathFreeObject));
5021
 
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5022
 
                               (void *) value,
5023
 
                               (xmlHashDeallocator)xmlXPathFreeObject));
5024
 
}
5025
 
 
5026
 
/**
5027
 
 * xmlXPathRegisterVariableLookup:
5028
 
 * @ctxt:  the XPath context
5029
 
 * @f:  the lookup function
5030
 
 * @data:  the lookup data
5031
 
 *
5032
 
 * register an external mechanism to do variable lookup
5033
 
 */
5034
 
void
5035
 
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5036
 
         xmlXPathVariableLookupFunc f, void *data) {
5037
 
    if (ctxt == NULL)
5038
 
        return;
5039
 
    ctxt->varLookupFunc = f;
5040
 
    ctxt->varLookupData = data;
5041
 
}
5042
 
 
5043
 
/**
5044
 
 * xmlXPathVariableLookup:
5045
 
 * @ctxt:  the XPath context
5046
 
 * @name:  the variable name
5047
 
 *
5048
 
 * Search in the Variable array of the context for the given
5049
 
 * variable value.
5050
 
 *
5051
 
 * Returns a copy of the value or NULL if not found
5052
 
 */
5053
 
xmlXPathObjectPtr
5054
 
xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5055
 
    if (ctxt == NULL)
5056
 
        return(NULL);
5057
 
 
5058
 
    if (ctxt->varLookupFunc != NULL) {
5059
 
        xmlXPathObjectPtr ret;
5060
 
 
5061
 
        ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5062
 
                (ctxt->varLookupData, name, NULL);
5063
 
        return(ret);
5064
 
    }
5065
 
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5066
 
}
5067
 
 
5068
 
/**
5069
 
 * xmlXPathVariableLookupNS:
5070
 
 * @ctxt:  the XPath context
5071
 
 * @name:  the variable name
5072
 
 * @ns_uri:  the variable namespace URI
5073
 
 *
5074
 
 * Search in the Variable array of the context for the given
5075
 
 * variable value.
5076
 
 *
5077
 
 * Returns the a copy of the value or NULL if not found
5078
 
 */
5079
 
xmlXPathObjectPtr
5080
 
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5081
 
                         const xmlChar *ns_uri) {
5082
 
    if (ctxt == NULL)
5083
 
        return(NULL);
5084
 
 
5085
 
    if (ctxt->varLookupFunc != NULL) {
5086
 
        xmlXPathObjectPtr ret;
5087
 
 
5088
 
        ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5089
 
                (ctxt->varLookupData, name, ns_uri);
5090
 
        if (ret != NULL) return(ret);
5091
 
    }
5092
 
 
5093
 
    if (ctxt->varHash == NULL)
5094
 
        return(NULL);
5095
 
    if (name == NULL)
5096
 
        return(NULL);
5097
 
 
5098
 
    return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5099
 
                xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5100
 
}
5101
 
 
5102
 
/**
5103
 
 * xmlXPathRegisteredVariablesCleanup:
5104
 
 * @ctxt:  the XPath context
5105
 
 *
5106
 
 * Cleanup the XPath context data associated to registered variables
5107
 
 */
5108
 
void
5109
 
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5110
 
    if (ctxt == NULL)
5111
 
        return;
5112
 
 
5113
 
    xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
5114
 
    ctxt->varHash = NULL;
5115
 
}
5116
 
 
5117
 
/**
5118
 
 * xmlXPathRegisterNs:
5119
 
 * @ctxt:  the XPath context
5120
 
 * @prefix:  the namespace prefix cannot be NULL or empty string
5121
 
 * @ns_uri:  the namespace name
5122
 
 *
5123
 
 * Register a new namespace. If @ns_uri is NULL it unregisters
5124
 
 * the namespace
5125
 
 *
5126
 
 * Returns 0 in case of success, -1 in case of error
5127
 
 */
5128
 
int
5129
 
xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5130
 
                           const xmlChar *ns_uri) {
5131
 
    if (ctxt == NULL)
5132
 
        return(-1);
5133
 
    if (prefix == NULL)
5134
 
        return(-1);
5135
 
    if (prefix[0] == 0)
5136
 
        return(-1);
5137
 
 
5138
 
    if (ctxt->nsHash == NULL)
5139
 
        ctxt->nsHash = xmlHashCreate(10);
5140
 
    if (ctxt->nsHash == NULL)
5141
 
        return(-1);
5142
 
    if (ns_uri == NULL)
5143
 
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5144
 
                                  (xmlHashDeallocator)xmlFree));
5145
 
    return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5146
 
                              (xmlHashDeallocator)xmlFree));
5147
 
}
5148
 
 
5149
 
/**
5150
 
 * xmlXPathNsLookup:
5151
 
 * @ctxt:  the XPath context
5152
 
 * @prefix:  the namespace prefix value
5153
 
 *
5154
 
 * Search in the namespace declaration array of the context for the given
5155
 
 * namespace name associated to the given prefix
5156
 
 *
5157
 
 * Returns the value or NULL if not found
5158
 
 */
5159
 
const xmlChar *
5160
 
xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5161
 
    if (ctxt == NULL)
5162
 
        return(NULL);
5163
 
    if (prefix == NULL)
5164
 
        return(NULL);
5165
 
 
5166
 
#ifdef XML_XML_NAMESPACE
5167
 
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5168
 
        return(XML_XML_NAMESPACE);
5169
 
#endif
5170
 
 
5171
 
    if (ctxt->namespaces != NULL) {
5172
 
        int i;
5173
 
 
5174
 
        for (i = 0;i < ctxt->nsNr;i++) {
5175
 
            if ((ctxt->namespaces[i] != NULL) &&
5176
 
                (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5177
 
                return(ctxt->namespaces[i]->href);
5178
 
        }
5179
 
    }
5180
 
 
5181
 
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5182
 
}
5183
 
 
5184
 
/**
5185
 
 * xmlXPathRegisteredNsCleanup:
5186
 
 * @ctxt:  the XPath context
5187
 
 *
5188
 
 * Cleanup the XPath context data associated to registered variables
5189
 
 */
5190
 
void
5191
 
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5192
 
    if (ctxt == NULL)
5193
 
        return;
5194
 
 
5195
 
    xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5196
 
    ctxt->nsHash = NULL;
5197
 
}
5198
 
 
5199
 
/************************************************************************
5200
 
 *                                                                      *
5201
 
 *                      Routines to handle Values                       *
5202
 
 *                                                                      *
5203
 
 ************************************************************************/
5204
 
 
5205
 
/* Allocations are terrible, one needs to optimize all this !!! */
5206
 
 
5207
 
/**
5208
 
 * xmlXPathNewFloat:
5209
 
 * @val:  the double value
5210
 
 *
5211
 
 * Create a new xmlXPathObjectPtr of type double and of value @val
5212
 
 *
5213
 
 * Returns the newly created object.
5214
 
 */
5215
 
xmlXPathObjectPtr
5216
 
xmlXPathNewFloat(double val) {
5217
 
    xmlXPathObjectPtr ret;
5218
 
 
5219
 
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5220
 
    if (ret == NULL) {
5221
 
        xmlXPathErrMemory(NULL, "creating float object\n");
5222
 
        return(NULL);
5223
 
    }
5224
 
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5225
 
    ret->type = XPATH_NUMBER;
5226
 
    ret->floatval = val;
5227
 
#ifdef XP_DEBUG_OBJ_USAGE
5228
 
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5229
 
#endif
5230
 
    return(ret);
5231
 
}
5232
 
 
5233
 
/**
5234
 
 * xmlXPathNewBoolean:
5235
 
 * @val:  the boolean value
5236
 
 *
5237
 
 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5238
 
 *
5239
 
 * Returns the newly created object.
5240
 
 */
5241
 
xmlXPathObjectPtr
5242
 
xmlXPathNewBoolean(int val) {
5243
 
    xmlXPathObjectPtr ret;
5244
 
 
5245
 
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5246
 
    if (ret == NULL) {
5247
 
        xmlXPathErrMemory(NULL, "creating boolean object\n");
5248
 
        return(NULL);
5249
 
    }
5250
 
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5251
 
    ret->type = XPATH_BOOLEAN;
5252
 
    ret->boolval = (val != 0);
5253
 
#ifdef XP_DEBUG_OBJ_USAGE
5254
 
    xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5255
 
#endif
5256
 
    return(ret);
5257
 
}
5258
 
 
5259
 
/**
5260
 
 * xmlXPathNewString:
5261
 
 * @val:  the xmlChar * value
5262
 
 *
5263
 
 * Create a new xmlXPathObjectPtr of type string and of value @val
5264
 
 *
5265
 
 * Returns the newly created object.
5266
 
 */
5267
 
xmlXPathObjectPtr
5268
 
xmlXPathNewString(const xmlChar *val) {
5269
 
    xmlXPathObjectPtr ret;
5270
 
 
5271
 
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5272
 
    if (ret == NULL) {
5273
 
        xmlXPathErrMemory(NULL, "creating string object\n");
5274
 
        return(NULL);
5275
 
    }
5276
 
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5277
 
    ret->type = XPATH_STRING;
5278
 
    if (val != NULL)
5279
 
        ret->stringval = xmlStrdup(val);
5280
 
    else
5281
 
        ret->stringval = xmlStrdup((const xmlChar *)"");
5282
 
#ifdef XP_DEBUG_OBJ_USAGE
5283
 
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5284
 
#endif
5285
 
    return(ret);
5286
 
}
5287
 
 
5288
 
/**
5289
 
 * xmlXPathWrapString:
5290
 
 * @val:  the xmlChar * value
5291
 
 *
5292
 
 * Wraps the @val string into an XPath object.
5293
 
 *
5294
 
 * Returns the newly created object.
5295
 
 */
5296
 
xmlXPathObjectPtr
5297
 
xmlXPathWrapString (xmlChar *val) {
5298
 
    xmlXPathObjectPtr ret;
5299
 
 
5300
 
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5301
 
    if (ret == NULL) {
5302
 
        xmlXPathErrMemory(NULL, "creating string object\n");
5303
 
        return(NULL);
5304
 
    }
5305
 
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5306
 
    ret->type = XPATH_STRING;
5307
 
    ret->stringval = val;
5308
 
#ifdef XP_DEBUG_OBJ_USAGE
5309
 
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5310
 
#endif
5311
 
    return(ret);
5312
 
}
5313
 
 
5314
 
/**
5315
 
 * xmlXPathNewCString:
5316
 
 * @val:  the char * value
5317
 
 *
5318
 
 * Create a new xmlXPathObjectPtr of type string and of value @val
5319
 
 *
5320
 
 * Returns the newly created object.
5321
 
 */
5322
 
xmlXPathObjectPtr
5323
 
xmlXPathNewCString(const char *val) {
5324
 
    xmlXPathObjectPtr ret;
5325
 
 
5326
 
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5327
 
    if (ret == NULL) {
5328
 
        xmlXPathErrMemory(NULL, "creating string object\n");
5329
 
        return(NULL);
5330
 
    }
5331
 
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5332
 
    ret->type = XPATH_STRING;
5333
 
    ret->stringval = xmlStrdup(BAD_CAST val);
5334
 
#ifdef XP_DEBUG_OBJ_USAGE
5335
 
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5336
 
#endif
5337
 
    return(ret);
5338
 
}
5339
 
 
5340
 
/**
5341
 
 * xmlXPathWrapCString:
5342
 
 * @val:  the char * value
5343
 
 *
5344
 
 * Wraps a string into an XPath object.
5345
 
 *
5346
 
 * Returns the newly created object.
5347
 
 */
5348
 
xmlXPathObjectPtr
5349
 
xmlXPathWrapCString (char * val) {
5350
 
    return(xmlXPathWrapString((xmlChar *)(val)));
5351
 
}
5352
 
 
5353
 
/**
5354
 
 * xmlXPathWrapExternal:
5355
 
 * @val:  the user data
5356
 
 *
5357
 
 * Wraps the @val data into an XPath object.
5358
 
 *
5359
 
 * Returns the newly created object.
5360
 
 */
5361
 
xmlXPathObjectPtr
5362
 
xmlXPathWrapExternal (void *val) {
5363
 
    xmlXPathObjectPtr ret;
5364
 
 
5365
 
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5366
 
    if (ret == NULL) {
5367
 
        xmlXPathErrMemory(NULL, "creating user object\n");
5368
 
        return(NULL);
5369
 
    }
5370
 
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5371
 
    ret->type = XPATH_USERS;
5372
 
    ret->user = val;
5373
 
#ifdef XP_DEBUG_OBJ_USAGE
5374
 
    xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5375
 
#endif
5376
 
    return(ret);
5377
 
}
5378
 
 
5379
 
/**
5380
 
 * xmlXPathObjectCopy:
5381
 
 * @val:  the original object
5382
 
 *
5383
 
 * allocate a new copy of a given object
5384
 
 *
5385
 
 * Returns the newly created object.
5386
 
 */
5387
 
xmlXPathObjectPtr
5388
 
xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5389
 
    xmlXPathObjectPtr ret;
5390
 
 
5391
 
    if (val == NULL)
5392
 
        return(NULL);
5393
 
 
5394
 
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5395
 
    if (ret == NULL) {
5396
 
        xmlXPathErrMemory(NULL, "copying object\n");
5397
 
        return(NULL);
5398
 
    }
5399
 
    memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5400
 
#ifdef XP_DEBUG_OBJ_USAGE
5401
 
    xmlXPathDebugObjUsageRequested(NULL, val->type);
5402
 
#endif
5403
 
    switch (val->type) {
5404
 
        case XPATH_BOOLEAN:
5405
 
        case XPATH_NUMBER:
5406
 
        case XPATH_POINT:
5407
 
        case XPATH_RANGE:
5408
 
            break;
5409
 
        case XPATH_STRING:
5410
 
            ret->stringval = xmlStrdup(val->stringval);
5411
 
            break;
5412
 
        case XPATH_XSLT_TREE:
5413
 
#if 0
5414
 
/*
5415
 
  Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5416
 
  this previous handling is no longer correct, and can cause some serious
5417
 
  problems (ref. bug 145547)
5418
 
*/
5419
 
            if ((val->nodesetval != NULL) &&
5420
 
                (val->nodesetval->nodeTab != NULL)) {
5421
 
                xmlNodePtr cur, tmp;
5422
 
                xmlDocPtr top;
5423
 
 
5424
 
                ret->boolval = 1;
5425
 
                top =  xmlNewDoc(NULL);
5426
 
                top->name = (char *)
5427
 
                    xmlStrdup(val->nodesetval->nodeTab[0]->name);
5428
 
                ret->user = top;
5429
 
                if (top != NULL) {
5430
 
                    top->doc = top;
5431
 
                    cur = val->nodesetval->nodeTab[0]->children;
5432
 
                    while (cur != NULL) {
5433
 
                        tmp = xmlDocCopyNode(cur, top, 1);
5434
 
                        xmlAddChild((xmlNodePtr) top, tmp);
5435
 
                        cur = cur->next;
5436
 
                    }
5437
 
                }
5438
 
 
5439
 
                ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5440
 
            } else
5441
 
                ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5442
 
            /* Deallocate the copied tree value */
5443
 
            break;
5444
 
#endif
5445
 
        case XPATH_NODESET:
5446
 
            ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5447
 
            /* Do not deallocate the copied tree value */
5448
 
            ret->boolval = 0;
5449
 
            break;
5450
 
        case XPATH_LOCATIONSET:
5451
 
#ifdef LIBXML_XPTR_ENABLED
5452
 
        {
5453
 
            xmlLocationSetPtr loc = val->user;
5454
 
            ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5455
 
            break;
5456
 
        }
5457
 
#endif
5458
 
        case XPATH_USERS:
5459
 
            ret->user = val->user;
5460
 
            break;
5461
 
        case XPATH_UNDEFINED:
5462
 
            xmlGenericError(xmlGenericErrorContext,
5463
 
                    "xmlXPathObjectCopy: unsupported type %d\n",
5464
 
                    val->type);
5465
 
            break;
5466
 
    }
5467
 
    return(ret);
5468
 
}
5469
 
 
5470
 
/**
5471
 
 * xmlXPathFreeObject:
5472
 
 * @obj:  the object to free
5473
 
 *
5474
 
 * Free up an xmlXPathObjectPtr object.
5475
 
 */
5476
 
void
5477
 
xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5478
 
    if (obj == NULL) return;
5479
 
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5480
 
        if (obj->boolval) {
5481
 
#if 0
5482
 
            if (obj->user != NULL) {
5483
 
                xmlXPathFreeNodeSet(obj->nodesetval);
5484
 
                xmlFreeNodeList((xmlNodePtr) obj->user);
5485
 
            } else
5486
 
#endif
5487
 
            obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5488
 
            if (obj->nodesetval != NULL)
5489
 
                xmlXPathFreeValueTree(obj->nodesetval);
5490
 
        } else {
5491
 
            if (obj->nodesetval != NULL)
5492
 
                xmlXPathFreeNodeSet(obj->nodesetval);
5493
 
        }
5494
 
#ifdef LIBXML_XPTR_ENABLED
5495
 
    } else if (obj->type == XPATH_LOCATIONSET) {
5496
 
        if (obj->user != NULL)
5497
 
            xmlXPtrFreeLocationSet(obj->user);
5498
 
#endif
5499
 
    } else if (obj->type == XPATH_STRING) {
5500
 
        if (obj->stringval != NULL)
5501
 
            xmlFree(obj->stringval);
5502
 
    }
5503
 
#ifdef XP_DEBUG_OBJ_USAGE
5504
 
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
5505
 
#endif
5506
 
    xmlFree(obj);
5507
 
}
5508
 
 
5509
 
/**
5510
 
 * xmlXPathReleaseObject:
5511
 
 * @obj:  the xmlXPathObjectPtr to free or to cache
5512
 
 *
5513
 
 * Depending on the state of the cache this frees the given
5514
 
 * XPath object or stores it in the cache.
5515
 
 */
5516
 
static void
5517
 
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5518
 
{
5519
 
#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5520
 
        sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5521
 
    if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5522
 
 
5523
 
#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5524
 
 
5525
 
    if (obj == NULL)
5526
 
        return;
5527
 
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5528
 
         xmlXPathFreeObject(obj);
5529
 
    } else {
5530
 
        xmlXPathContextCachePtr cache =
5531
 
            (xmlXPathContextCachePtr) ctxt->cache;
5532
 
 
5533
 
        switch (obj->type) {
5534
 
            case XPATH_NODESET:
5535
 
            case XPATH_XSLT_TREE:
5536
 
                if (obj->nodesetval != NULL) {
5537
 
                    if (obj->boolval) {
5538
 
                        /*
5539
 
                        * It looks like the @boolval is used for
5540
 
                        * evaluation if this an XSLT Result Tree Fragment.
5541
 
                        * TODO: Check if this assumption is correct.
5542
 
                        */
5543
 
                        obj->type = XPATH_XSLT_TREE; /* just for debugging */
5544
 
                        xmlXPathFreeValueTree(obj->nodesetval);
5545
 
                        obj->nodesetval = NULL;
5546
 
                    } else if ((obj->nodesetval->nodeMax <= 40) &&
5547
 
                        (XP_CACHE_WANTS(cache->nodesetObjs,
5548
 
                                        cache->maxNodeset)))
5549
 
                    {
5550
 
                        XP_CACHE_ADD(cache->nodesetObjs, obj);
5551
 
                        goto obj_cached;
5552
 
                    } else {
5553
 
                        xmlXPathFreeNodeSet(obj->nodesetval);
5554
 
                        obj->nodesetval = NULL;
5555
 
                    }
5556
 
                }
5557
 
                break;
5558
 
            case XPATH_STRING:
5559
 
                if (obj->stringval != NULL)
5560
 
                    xmlFree(obj->stringval);
5561
 
 
5562
 
                if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5563
 
                    XP_CACHE_ADD(cache->stringObjs, obj);
5564
 
                    goto obj_cached;
5565
 
                }
5566
 
                break;
5567
 
            case XPATH_BOOLEAN:
5568
 
                if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5569
 
                    XP_CACHE_ADD(cache->booleanObjs, obj);
5570
 
                    goto obj_cached;
5571
 
                }
5572
 
                break;
5573
 
            case XPATH_NUMBER:
5574
 
                if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5575
 
                    XP_CACHE_ADD(cache->numberObjs, obj);
5576
 
                    goto obj_cached;
5577
 
                }
5578
 
                break;
5579
 
#ifdef LIBXML_XPTR_ENABLED
5580
 
            case XPATH_LOCATIONSET:
5581
 
                if (obj->user != NULL) {
5582
 
                    xmlXPtrFreeLocationSet(obj->user);
5583
 
                }
5584
 
                goto free_obj;
5585
 
#endif
5586
 
            default:
5587
 
                goto free_obj;
5588
 
        }
5589
 
 
5590
 
        /*
5591
 
        * Fallback to adding to the misc-objects slot.
5592
 
        */
5593
 
        if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5594
 
            XP_CACHE_ADD(cache->miscObjs, obj);
5595
 
        } else
5596
 
            goto free_obj;
5597
 
 
5598
 
obj_cached:
5599
 
 
5600
 
#ifdef XP_DEBUG_OBJ_USAGE
5601
 
        xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5602
 
#endif
5603
 
 
5604
 
        if (obj->nodesetval != NULL) {
5605
 
            xmlNodeSetPtr tmpset = obj->nodesetval;
5606
 
 
5607
 
            /*
5608
 
            * TODO: Due to those nasty ns-nodes, we need to traverse
5609
 
            *  the list and free the ns-nodes.
5610
 
            * URGENT TODO: Check if it's actually slowing things down.
5611
 
            *  Maybe we shouldn't try to preserve the list.
5612
 
            */
5613
 
            if (tmpset->nodeNr > 1) {
5614
 
                int i;
5615
 
                xmlNodePtr node;
5616
 
 
5617
 
                for (i = 0; i < tmpset->nodeNr; i++) {
5618
 
                    node = tmpset->nodeTab[i];
5619
 
                    if ((node != NULL) &&
5620
 
                        (node->type == XML_NAMESPACE_DECL))
5621
 
                    {
5622
 
                        xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5623
 
                    }
5624
 
                }
5625
 
            } else if (tmpset->nodeNr == 1) {
5626
 
                if ((tmpset->nodeTab[0] != NULL) &&
5627
 
                    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5628
 
                    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5629
 
            }
5630
 
            tmpset->nodeNr = 0;
5631
 
            memset(obj, 0, sizeof(xmlXPathObject));
5632
 
            obj->nodesetval = tmpset;
5633
 
        } else
5634
 
            memset(obj, 0, sizeof(xmlXPathObject));
5635
 
 
5636
 
        return;
5637
 
 
5638
 
free_obj:
5639
 
        /*
5640
 
        * Cache is full; free the object.
5641
 
        */
5642
 
        if (obj->nodesetval != NULL)
5643
 
            xmlXPathFreeNodeSet(obj->nodesetval);
5644
 
#ifdef XP_DEBUG_OBJ_USAGE
5645
 
        xmlXPathDebugObjUsageReleased(NULL, obj->type);
5646
 
#endif
5647
 
        xmlFree(obj);
5648
 
    }
5649
 
    return;
5650
 
}
5651
 
 
5652
 
 
5653
 
/************************************************************************
5654
 
 *                                                                      *
5655
 
 *                      Type Casting Routines                           *
5656
 
 *                                                                      *
5657
 
 ************************************************************************/
5658
 
 
5659
 
/**
5660
 
 * xmlXPathCastBooleanToString:
5661
 
 * @val:  a boolean
5662
 
 *
5663
 
 * Converts a boolean to its string value.
5664
 
 *
5665
 
 * Returns a newly allocated string.
5666
 
 */
5667
 
xmlChar *
5668
 
xmlXPathCastBooleanToString (int val) {
5669
 
    xmlChar *ret;
5670
 
    if (val)
5671
 
        ret = xmlStrdup((const xmlChar *) "true");
5672
 
    else
5673
 
        ret = xmlStrdup((const xmlChar *) "false");
5674
 
    return(ret);
5675
 
}
5676
 
 
5677
 
/**
5678
 
 * xmlXPathCastNumberToString:
5679
 
 * @val:  a number
5680
 
 *
5681
 
 * Converts a number to its string value.
5682
 
 *
5683
 
 * Returns a newly allocated string.
5684
 
 */
5685
 
xmlChar *
5686
 
xmlXPathCastNumberToString (double val) {
5687
 
    xmlChar *ret;
5688
 
    switch (xmlXPathIsInf(val)) {
5689
 
    case 1:
5690
 
        ret = xmlStrdup((const xmlChar *) "Infinity");
5691
 
        break;
5692
 
    case -1:
5693
 
        ret = xmlStrdup((const xmlChar *) "-Infinity");
5694
 
        break;
5695
 
    default:
5696
 
        if (xmlXPathIsNaN(val)) {
5697
 
            ret = xmlStrdup((const xmlChar *) "NaN");
5698
 
        } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5699
 
            ret = xmlStrdup((const xmlChar *) "0");
5700
 
        } else {
5701
 
            /* could be improved */
5702
 
            char buf[100];
5703
 
            xmlXPathFormatNumber(val, buf, 99);
5704
 
            buf[99] = 0;
5705
 
            ret = xmlStrdup((const xmlChar *) buf);
5706
 
        }
5707
 
    }
5708
 
    return(ret);
5709
 
}
5710
 
 
5711
 
/**
5712
 
 * xmlXPathCastNodeToString:
5713
 
 * @node:  a node
5714
 
 *
5715
 
 * Converts a node to its string value.
5716
 
 *
5717
 
 * Returns a newly allocated string.
5718
 
 */
5719
 
xmlChar *
5720
 
xmlXPathCastNodeToString (xmlNodePtr node) {
5721
 
xmlChar *ret;
5722
 
    if ((ret = xmlNodeGetContent(node)) == NULL)
5723
 
        ret = xmlStrdup((const xmlChar *) "");
5724
 
    return(ret);
5725
 
}
5726
 
 
5727
 
/**
5728
 
 * xmlXPathCastNodeSetToString:
5729
 
 * @ns:  a node-set
5730
 
 *
5731
 
 * Converts a node-set to its string value.
5732
 
 *
5733
 
 * Returns a newly allocated string.
5734
 
 */
5735
 
xmlChar *
5736
 
xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5737
 
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5738
 
        return(xmlStrdup((const xmlChar *) ""));
5739
 
 
5740
 
    if (ns->nodeNr > 1)
5741
 
        xmlXPathNodeSetSort(ns);
5742
 
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5743
 
}
5744
 
 
5745
 
/**
5746
 
 * xmlXPathCastToString:
5747
 
 * @val:  an XPath object
5748
 
 *
5749
 
 * Converts an existing object to its string() equivalent
5750
 
 *
5751
 
 * Returns the allocated string value of the object, NULL in case of error.
5752
 
 *         It's up to the caller to free the string memory with xmlFree().
5753
 
 */
5754
 
xmlChar *
5755
 
xmlXPathCastToString(xmlXPathObjectPtr val) {
5756
 
    xmlChar *ret = NULL;
5757
 
 
5758
 
    if (val == NULL)
5759
 
        return(xmlStrdup((const xmlChar *) ""));
5760
 
    switch (val->type) {
5761
 
        case XPATH_UNDEFINED:
5762
 
#ifdef DEBUG_EXPR
5763
 
            xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5764
 
#endif
5765
 
            ret = xmlStrdup((const xmlChar *) "");
5766
 
            break;
5767
 
        case XPATH_NODESET:
5768
 
        case XPATH_XSLT_TREE:
5769
 
            ret = xmlXPathCastNodeSetToString(val->nodesetval);
5770
 
            break;
5771
 
        case XPATH_STRING:
5772
 
            return(xmlStrdup(val->stringval));
5773
 
        case XPATH_BOOLEAN:
5774
 
            ret = xmlXPathCastBooleanToString(val->boolval);
5775
 
            break;
5776
 
        case XPATH_NUMBER: {
5777
 
            ret = xmlXPathCastNumberToString(val->floatval);
5778
 
            break;
5779
 
        }
5780
 
        case XPATH_USERS:
5781
 
        case XPATH_POINT:
5782
 
        case XPATH_RANGE:
5783
 
        case XPATH_LOCATIONSET:
5784
 
            TODO
5785
 
            ret = xmlStrdup((const xmlChar *) "");
5786
 
            break;
5787
 
    }
5788
 
    return(ret);
5789
 
}
5790
 
 
5791
 
/**
5792
 
 * xmlXPathConvertString:
5793
 
 * @val:  an XPath object
5794
 
 *
5795
 
 * Converts an existing object to its string() equivalent
5796
 
 *
5797
 
 * Returns the new object, the old one is freed (or the operation
5798
 
 *         is done directly on @val)
5799
 
 */
5800
 
xmlXPathObjectPtr
5801
 
xmlXPathConvertString(xmlXPathObjectPtr val) {
5802
 
    xmlChar *res = NULL;
5803
 
 
5804
 
    if (val == NULL)
5805
 
        return(xmlXPathNewCString(""));
5806
 
 
5807
 
    switch (val->type) {
5808
 
    case XPATH_UNDEFINED:
5809
 
#ifdef DEBUG_EXPR
5810
 
        xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5811
 
#endif
5812
 
        break;
5813
 
    case XPATH_NODESET:
5814
 
    case XPATH_XSLT_TREE:
5815
 
        res = xmlXPathCastNodeSetToString(val->nodesetval);
5816
 
        break;
5817
 
    case XPATH_STRING:
5818
 
        return(val);
5819
 
    case XPATH_BOOLEAN:
5820
 
        res = xmlXPathCastBooleanToString(val->boolval);
5821
 
        break;
5822
 
    case XPATH_NUMBER:
5823
 
        res = xmlXPathCastNumberToString(val->floatval);
5824
 
        break;
5825
 
    case XPATH_USERS:
5826
 
    case XPATH_POINT:
5827
 
    case XPATH_RANGE:
5828
 
    case XPATH_LOCATIONSET:
5829
 
        TODO;
5830
 
        break;
5831
 
    }
5832
 
    xmlXPathFreeObject(val);
5833
 
    if (res == NULL)
5834
 
        return(xmlXPathNewCString(""));
5835
 
    return(xmlXPathWrapString(res));
5836
 
}
5837
 
 
5838
 
/**
5839
 
 * xmlXPathCastBooleanToNumber:
5840
 
 * @val:  a boolean
5841
 
 *
5842
 
 * Converts a boolean to its number value
5843
 
 *
5844
 
 * Returns the number value
5845
 
 */
5846
 
double
5847
 
xmlXPathCastBooleanToNumber(int val) {
5848
 
    if (val)
5849
 
        return(1.0);
5850
 
    return(0.0);
5851
 
}
5852
 
 
5853
 
/**
5854
 
 * xmlXPathCastStringToNumber:
5855
 
 * @val:  a string
5856
 
 *
5857
 
 * Converts a string to its number value
5858
 
 *
5859
 
 * Returns the number value
5860
 
 */
5861
 
double
5862
 
xmlXPathCastStringToNumber(const xmlChar * val) {
5863
 
    return(xmlXPathStringEvalNumber(val));
5864
 
}
5865
 
 
5866
 
/**
5867
 
 * xmlXPathCastNodeToNumber:
5868
 
 * @node:  a node
5869
 
 *
5870
 
 * Converts a node to its number value
5871
 
 *
5872
 
 * Returns the number value
5873
 
 */
5874
 
double
5875
 
xmlXPathCastNodeToNumber (xmlNodePtr node) {
5876
 
    xmlChar *strval;
5877
 
    double ret;
5878
 
 
5879
 
    if (node == NULL)
5880
 
        return(xmlXPathNAN);
5881
 
    strval = xmlXPathCastNodeToString(node);
5882
 
    if (strval == NULL)
5883
 
        return(xmlXPathNAN);
5884
 
    ret = xmlXPathCastStringToNumber(strval);
5885
 
    xmlFree(strval);
5886
 
 
5887
 
    return(ret);
5888
 
}
5889
 
 
5890
 
/**
5891
 
 * xmlXPathCastNodeSetToNumber:
5892
 
 * @ns:  a node-set
5893
 
 *
5894
 
 * Converts a node-set to its number value
5895
 
 *
5896
 
 * Returns the number value
5897
 
 */
5898
 
double
5899
 
xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5900
 
    xmlChar *str;
5901
 
    double ret;
5902
 
 
5903
 
    if (ns == NULL)
5904
 
        return(xmlXPathNAN);
5905
 
    str = xmlXPathCastNodeSetToString(ns);
5906
 
    ret = xmlXPathCastStringToNumber(str);
5907
 
    xmlFree(str);
5908
 
    return(ret);
5909
 
}
5910
 
 
5911
 
/**
5912
 
 * xmlXPathCastToNumber:
5913
 
 * @val:  an XPath object
5914
 
 *
5915
 
 * Converts an XPath object to its number value
5916
 
 *
5917
 
 * Returns the number value
5918
 
 */
5919
 
double
5920
 
xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5921
 
    double ret = 0.0;
5922
 
 
5923
 
    if (val == NULL)
5924
 
        return(xmlXPathNAN);
5925
 
    switch (val->type) {
5926
 
    case XPATH_UNDEFINED:
5927
 
#ifdef DEGUB_EXPR
5928
 
        xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5929
 
#endif
5930
 
        ret = xmlXPathNAN;
5931
 
        break;
5932
 
    case XPATH_NODESET:
5933
 
    case XPATH_XSLT_TREE:
5934
 
        ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5935
 
        break;
5936
 
    case XPATH_STRING:
5937
 
        ret = xmlXPathCastStringToNumber(val->stringval);
5938
 
        break;
5939
 
    case XPATH_NUMBER:
5940
 
        ret = val->floatval;
5941
 
        break;
5942
 
    case XPATH_BOOLEAN:
5943
 
        ret = xmlXPathCastBooleanToNumber(val->boolval);
5944
 
        break;
5945
 
    case XPATH_USERS:
5946
 
    case XPATH_POINT:
5947
 
    case XPATH_RANGE:
5948
 
    case XPATH_LOCATIONSET:
5949
 
        TODO;
5950
 
        ret = xmlXPathNAN;
5951
 
        break;
5952
 
    }
5953
 
    return(ret);
5954
 
}
5955
 
 
5956
 
/**
5957
 
 * xmlXPathConvertNumber:
5958
 
 * @val:  an XPath object
5959
 
 *
5960
 
 * Converts an existing object to its number() equivalent
5961
 
 *
5962
 
 * Returns the new object, the old one is freed (or the operation
5963
 
 *         is done directly on @val)
5964
 
 */
5965
 
xmlXPathObjectPtr
5966
 
xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5967
 
    xmlXPathObjectPtr ret;
5968
 
 
5969
 
    if (val == NULL)
5970
 
        return(xmlXPathNewFloat(0.0));
5971
 
    if (val->type == XPATH_NUMBER)
5972
 
        return(val);
5973
 
    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5974
 
    xmlXPathFreeObject(val);
5975
 
    return(ret);
5976
 
}
5977
 
 
5978
 
/**
5979
 
 * xmlXPathCastNumberToBoolean:
5980
 
 * @val:  a number
5981
 
 *
5982
 
 * Converts a number to its boolean value
5983
 
 *
5984
 
 * Returns the boolean value
5985
 
 */
5986
 
int
5987
 
xmlXPathCastNumberToBoolean (double val) {
5988
 
     if (xmlXPathIsNaN(val) || (val == 0.0))
5989
 
         return(0);
5990
 
     return(1);
5991
 
}
5992
 
 
5993
 
/**
5994
 
 * xmlXPathCastStringToBoolean:
5995
 
 * @val:  a string
5996
 
 *
5997
 
 * Converts a string to its boolean value
5998
 
 *
5999
 
 * Returns the boolean value
6000
 
 */
6001
 
int
6002
 
xmlXPathCastStringToBoolean (const xmlChar *val) {
6003
 
    if ((val == NULL) || (xmlStrlen(val) == 0))
6004
 
        return(0);
6005
 
    return(1);
6006
 
}
6007
 
 
6008
 
/**
6009
 
 * xmlXPathCastNodeSetToBoolean:
6010
 
 * @ns:  a node-set
6011
 
 *
6012
 
 * Converts a node-set to its boolean value
6013
 
 *
6014
 
 * Returns the boolean value
6015
 
 */
6016
 
int
6017
 
xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6018
 
    if ((ns == NULL) || (ns->nodeNr == 0))
6019
 
        return(0);
6020
 
    return(1);
6021
 
}
6022
 
 
6023
 
/**
6024
 
 * xmlXPathCastToBoolean:
6025
 
 * @val:  an XPath object
6026
 
 *
6027
 
 * Converts an XPath object to its boolean value
6028
 
 *
6029
 
 * Returns the boolean value
6030
 
 */
6031
 
int
6032
 
xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6033
 
    int ret = 0;
6034
 
 
6035
 
    if (val == NULL)
6036
 
        return(0);
6037
 
    switch (val->type) {
6038
 
    case XPATH_UNDEFINED:
6039
 
#ifdef DEBUG_EXPR
6040
 
        xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6041
 
#endif
6042
 
        ret = 0;
6043
 
        break;
6044
 
    case XPATH_NODESET:
6045
 
    case XPATH_XSLT_TREE:
6046
 
        ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6047
 
        break;
6048
 
    case XPATH_STRING:
6049
 
        ret = xmlXPathCastStringToBoolean(val->stringval);
6050
 
        break;
6051
 
    case XPATH_NUMBER:
6052
 
        ret = xmlXPathCastNumberToBoolean(val->floatval);
6053
 
        break;
6054
 
    case XPATH_BOOLEAN:
6055
 
        ret = val->boolval;
6056
 
        break;
6057
 
    case XPATH_USERS:
6058
 
    case XPATH_POINT:
6059
 
    case XPATH_RANGE:
6060
 
    case XPATH_LOCATIONSET:
6061
 
        TODO;
6062
 
        ret = 0;
6063
 
        break;
6064
 
    }
6065
 
    return(ret);
6066
 
}
6067
 
 
6068
 
 
6069
 
/**
6070
 
 * xmlXPathConvertBoolean:
6071
 
 * @val:  an XPath object
6072
 
 *
6073
 
 * Converts an existing object to its boolean() equivalent
6074
 
 *
6075
 
 * Returns the new object, the old one is freed (or the operation
6076
 
 *         is done directly on @val)
6077
 
 */
6078
 
xmlXPathObjectPtr
6079
 
xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6080
 
    xmlXPathObjectPtr ret;
6081
 
 
6082
 
    if (val == NULL)
6083
 
        return(xmlXPathNewBoolean(0));
6084
 
    if (val->type == XPATH_BOOLEAN)
6085
 
        return(val);
6086
 
    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6087
 
    xmlXPathFreeObject(val);
6088
 
    return(ret);
6089
 
}
6090
 
 
6091
 
/************************************************************************
6092
 
 *                                                                      *
6093
 
 *              Routines to handle XPath contexts                       *
6094
 
 *                                                                      *
6095
 
 ************************************************************************/
6096
 
 
6097
 
/**
6098
 
 * xmlXPathNewContext:
6099
 
 * @doc:  the XML document
6100
 
 *
6101
 
 * Create a new xmlXPathContext
6102
 
 *
6103
 
 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6104
 
 */
6105
 
xmlXPathContextPtr
6106
 
xmlXPathNewContext(xmlDocPtr doc) {
6107
 
    xmlXPathContextPtr ret;
6108
 
 
6109
 
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6110
 
    if (ret == NULL) {
6111
 
        xmlXPathErrMemory(NULL, "creating context\n");
6112
 
        return(NULL);
6113
 
    }
6114
 
    memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6115
 
    ret->doc = doc;
6116
 
    ret->node = NULL;
6117
 
 
6118
 
    ret->varHash = NULL;
6119
 
 
6120
 
    ret->nb_types = 0;
6121
 
    ret->max_types = 0;
6122
 
    ret->types = NULL;
6123
 
 
6124
 
    ret->funcHash = xmlHashCreate(0);
6125
 
 
6126
 
    ret->nb_axis = 0;
6127
 
    ret->max_axis = 0;
6128
 
    ret->axis = NULL;
6129
 
 
6130
 
    ret->nsHash = NULL;
6131
 
    ret->user = NULL;
6132
 
 
6133
 
    ret->contextSize = -1;
6134
 
    ret->proximityPosition = -1;
6135
 
 
6136
 
#ifdef XP_DEFAULT_CACHE_ON
6137
 
    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6138
 
        xmlXPathFreeContext(ret);
6139
 
        return(NULL);
6140
 
    }
6141
 
#endif
6142
 
 
6143
 
    xmlXPathRegisterAllFunctions(ret);
6144
 
 
6145
 
    return(ret);
6146
 
}
6147
 
 
6148
 
/**
6149
 
 * xmlXPathFreeContext:
6150
 
 * @ctxt:  the context to free
6151
 
 *
6152
 
 * Free up an xmlXPathContext
6153
 
 */
6154
 
void
6155
 
xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6156
 
    if (ctxt == NULL) return;
6157
 
 
6158
 
    if (ctxt->cache != NULL)
6159
 
        xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6160
 
    xmlXPathRegisteredNsCleanup(ctxt);
6161
 
    xmlXPathRegisteredFuncsCleanup(ctxt);
6162
 
    xmlXPathRegisteredVariablesCleanup(ctxt);
6163
 
    xmlResetError(&ctxt->lastError);
6164
 
    xmlFree(ctxt);
6165
 
}
6166
 
 
6167
 
/************************************************************************
6168
 
 *                                                                      *
6169
 
 *              Routines to handle XPath parser contexts                *
6170
 
 *                                                                      *
6171
 
 ************************************************************************/
6172
 
 
6173
 
#define CHECK_CTXT(ctxt)                                                \
6174
 
    if (ctxt == NULL) {                                         \
6175
 
        __xmlRaiseError(NULL, NULL, NULL,                               \
6176
 
                NULL, NULL, XML_FROM_XPATH,                             \
6177
 
                XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,                  \
6178
 
                __FILE__, __LINE__,                                     \
6179
 
                NULL, NULL, NULL, 0, 0,                                 \
6180
 
                "NULL context pointer\n");                              \
6181
 
        return(NULL);                                                   \
6182
 
    }                                                                   \
6183
 
 
6184
 
#define CHECK_CTXT_NEG(ctxt)                                            \
6185
 
    if (ctxt == NULL) {                                         \
6186
 
        __xmlRaiseError(NULL, NULL, NULL,                               \
6187
 
                NULL, NULL, XML_FROM_XPATH,                             \
6188
 
                XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,                  \
6189
 
                __FILE__, __LINE__,                                     \
6190
 
                NULL, NULL, NULL, 0, 0,                                 \
6191
 
                "NULL context pointer\n");                              \
6192
 
        return(-1);                                                     \
6193
 
    }                                                                   \
6194
 
 
6195
 
 
6196
 
#define CHECK_CONTEXT(ctxt)                                             \
6197
 
    if ((ctxt == NULL) || (ctxt->doc == NULL) ||                        \
6198
 
        (ctxt->doc->children == NULL)) {                                \
6199
 
        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);    \
6200
 
        return(NULL);                                                   \
6201
 
    }
6202
 
 
6203
 
 
6204
 
/**
6205
 
 * xmlXPathNewParserContext:
6206
 
 * @str:  the XPath expression
6207
 
 * @ctxt:  the XPath context
6208
 
 *
6209
 
 * Create a new xmlXPathParserContext
6210
 
 *
6211
 
 * Returns the xmlXPathParserContext just allocated.
6212
 
 */
6213
 
xmlXPathParserContextPtr
6214
 
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6215
 
    xmlXPathParserContextPtr ret;
6216
 
 
6217
 
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6218
 
    if (ret == NULL) {
6219
 
        xmlXPathErrMemory(ctxt, "creating parser context\n");
6220
 
        return(NULL);
6221
 
    }
6222
 
    memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6223
 
    ret->cur = ret->base = str;
6224
 
    ret->context = ctxt;
6225
 
 
6226
 
    ret->comp = xmlXPathNewCompExpr();
6227
 
    if (ret->comp == NULL) {
6228
 
        xmlFree(ret->valueTab);
6229
 
        xmlFree(ret);
6230
 
        return(NULL);
6231
 
    }
6232
 
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6233
 
        ret->comp->dict = ctxt->dict;
6234
 
        xmlDictReference(ret->comp->dict);
6235
 
    }
6236
 
 
6237
 
    return(ret);
6238
 
}
6239
 
 
6240
 
/**
6241
 
 * xmlXPathCompParserContext:
6242
 
 * @comp:  the XPath compiled expression
6243
 
 * @ctxt:  the XPath context
6244
 
 *
6245
 
 * Create a new xmlXPathParserContext when processing a compiled expression
6246
 
 *
6247
 
 * Returns the xmlXPathParserContext just allocated.
6248
 
 */
6249
 
static xmlXPathParserContextPtr
6250
 
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6251
 
    xmlXPathParserContextPtr ret;
6252
 
 
6253
 
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6254
 
    if (ret == NULL) {
6255
 
        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6256
 
        return(NULL);
6257
 
    }
6258
 
    memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6259
 
 
6260
 
    /* Allocate the value stack */
6261
 
    ret->valueTab = (xmlXPathObjectPtr *)
6262
 
                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6263
 
    if (ret->valueTab == NULL) {
6264
 
        xmlFree(ret);
6265
 
        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6266
 
        return(NULL);
6267
 
    }
6268
 
    ret->valueNr = 0;
6269
 
    ret->valueMax = 10;
6270
 
    ret->value = NULL;
6271
 
    ret->valueFrame = 0;
6272
 
 
6273
 
    ret->context = ctxt;
6274
 
    ret->comp = comp;
6275
 
 
6276
 
    return(ret);
6277
 
}
6278
 
 
6279
 
/**
6280
 
 * xmlXPathFreeParserContext:
6281
 
 * @ctxt:  the context to free
6282
 
 *
6283
 
 * Free up an xmlXPathParserContext
6284
 
 */
6285
 
void
6286
 
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6287
 
    if (ctxt->valueTab != NULL) {
6288
 
        xmlFree(ctxt->valueTab);
6289
 
    }
6290
 
    if (ctxt->comp != NULL) {
6291
 
#ifdef XPATH_STREAMING
6292
 
        if (ctxt->comp->stream != NULL) {
6293
 
            xmlFreePatternList(ctxt->comp->stream);
6294
 
            ctxt->comp->stream = NULL;
6295
 
        }
6296
 
#endif
6297
 
        xmlXPathFreeCompExpr(ctxt->comp);
6298
 
    }
6299
 
    xmlFree(ctxt);
6300
 
}
6301
 
 
6302
 
/************************************************************************
6303
 
 *                                                                      *
6304
 
 *              The implicit core function library                      *
6305
 
 *                                                                      *
6306
 
 ************************************************************************/
6307
 
 
6308
 
/**
6309
 
 * xmlXPathNodeValHash:
6310
 
 * @node:  a node pointer
6311
 
 *
6312
 
 * Function computing the beginning of the string value of the node,
6313
 
 * used to speed up comparisons
6314
 
 *
6315
 
 * Returns an int usable as a hash
6316
 
 */
6317
 
static unsigned int
6318
 
xmlXPathNodeValHash(xmlNodePtr node) {
6319
 
    int len = 2;
6320
 
    const xmlChar * string = NULL;
6321
 
    xmlNodePtr tmp = NULL;
6322
 
    unsigned int ret = 0;
6323
 
 
6324
 
    if (node == NULL)
6325
 
        return(0);
6326
 
 
6327
 
    if (node->type == XML_DOCUMENT_NODE) {
6328
 
        tmp = xmlDocGetRootElement((xmlDocPtr) node);
6329
 
        if (tmp == NULL)
6330
 
            node = node->children;
6331
 
        else
6332
 
            node = tmp;
6333
 
 
6334
 
        if (node == NULL)
6335
 
            return(0);
6336
 
    }
6337
 
 
6338
 
    switch (node->type) {
6339
 
        case XML_COMMENT_NODE:
6340
 
        case XML_PI_NODE:
6341
 
        case XML_CDATA_SECTION_NODE:
6342
 
        case XML_TEXT_NODE:
6343
 
            string = node->content;
6344
 
            if (string == NULL)
6345
 
                return(0);
6346
 
            if (string[0] == 0)
6347
 
                return(0);
6348
 
            return(((unsigned int) string[0]) +
6349
 
                   (((unsigned int) string[1]) << 8));
6350
 
        case XML_NAMESPACE_DECL:
6351
 
            string = ((xmlNsPtr)node)->href;
6352
 
            if (string == NULL)
6353
 
                return(0);
6354
 
            if (string[0] == 0)
6355
 
                return(0);
6356
 
            return(((unsigned int) string[0]) +
6357
 
                   (((unsigned int) string[1]) << 8));
6358
 
        case XML_ATTRIBUTE_NODE:
6359
 
            tmp = ((xmlAttrPtr) node)->children;
6360
 
            break;
6361
 
        case XML_ELEMENT_NODE:
6362
 
            tmp = node->children;
6363
 
            break;
6364
 
        default:
6365
 
            return(0);
6366
 
    }
6367
 
    while (tmp != NULL) {
6368
 
        switch (tmp->type) {
6369
 
            case XML_COMMENT_NODE:
6370
 
            case XML_PI_NODE:
6371
 
            case XML_CDATA_SECTION_NODE:
6372
 
            case XML_TEXT_NODE:
6373
 
                string = tmp->content;
6374
 
                break;
6375
 
            case XML_NAMESPACE_DECL:
6376
 
                string = ((xmlNsPtr)tmp)->href;
6377
 
                break;
6378
 
            default:
6379
 
                break;
6380
 
        }
6381
 
        if ((string != NULL) && (string[0] != 0)) {
6382
 
            if (len == 1) {
6383
 
                return(ret + (((unsigned int) string[0]) << 8));
6384
 
            }
6385
 
            if (string[1] == 0) {
6386
 
                len = 1;
6387
 
                ret = (unsigned int) string[0];
6388
 
            } else {
6389
 
                return(((unsigned int) string[0]) +
6390
 
                       (((unsigned int) string[1]) << 8));
6391
 
            }
6392
 
        }
6393
 
        /*
6394
 
         * Skip to next node
6395
 
         */
6396
 
        if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6397
 
            if (tmp->children->type != XML_ENTITY_DECL) {
6398
 
                tmp = tmp->children;
6399
 
                continue;
6400
 
            }
6401
 
        }
6402
 
        if (tmp == node)
6403
 
            break;
6404
 
 
6405
 
        if (tmp->next != NULL) {
6406
 
            tmp = tmp->next;
6407
 
            continue;
6408
 
        }
6409
 
 
6410
 
        do {
6411
 
            tmp = tmp->parent;
6412
 
            if (tmp == NULL)
6413
 
                break;
6414
 
            if (tmp == node) {
6415
 
                tmp = NULL;
6416
 
                break;
6417
 
            }
6418
 
            if (tmp->next != NULL) {
6419
 
                tmp = tmp->next;
6420
 
                break;
6421
 
            }
6422
 
        } while (tmp != NULL);
6423
 
    }
6424
 
    return(ret);
6425
 
}
6426
 
 
6427
 
/**
6428
 
 * xmlXPathStringHash:
6429
 
 * @string:  a string
6430
 
 *
6431
 
 * Function computing the beginning of the string value of the node,
6432
 
 * used to speed up comparisons
6433
 
 *
6434
 
 * Returns an int usable as a hash
6435
 
 */
6436
 
static unsigned int
6437
 
xmlXPathStringHash(const xmlChar * string) {
6438
 
    if (string == NULL)
6439
 
        return((unsigned int) 0);
6440
 
    if (string[0] == 0)
6441
 
        return(0);
6442
 
    return(((unsigned int) string[0]) +
6443
 
           (((unsigned int) string[1]) << 8));
6444
 
}
6445
 
 
6446
 
/**
6447
 
 * xmlXPathCompareNodeSetFloat:
6448
 
 * @ctxt:  the XPath Parser context
6449
 
 * @inf:  less than (1) or greater than (0)
6450
 
 * @strict:  is the comparison strict
6451
 
 * @arg:  the node set
6452
 
 * @f:  the value
6453
 
 *
6454
 
 * Implement the compare operation between a nodeset and a number
6455
 
 *     @ns < @val    (1, 1, ...
6456
 
 *     @ns <= @val   (1, 0, ...
6457
 
 *     @ns > @val    (0, 1, ...
6458
 
 *     @ns >= @val   (0, 0, ...
6459
 
 *
6460
 
 * If one object to be compared is a node-set and the other is a number,
6461
 
 * then the comparison will be true if and only if there is a node in the
6462
 
 * node-set such that the result of performing the comparison on the number
6463
 
 * to be compared and on the result of converting the string-value of that
6464
 
 * node to a number using the number function is true.
6465
 
 *
6466
 
 * Returns 0 or 1 depending on the results of the test.
6467
 
 */
6468
 
static int
6469
 
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6470
 
                            xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6471
 
    int i, ret = 0;
6472
 
    xmlNodeSetPtr ns;
6473
 
    xmlChar *str2;
6474
 
 
6475
 
    if ((f == NULL) || (arg == NULL) ||
6476
 
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6477
 
        xmlXPathReleaseObject(ctxt->context, arg);
6478
 
        xmlXPathReleaseObject(ctxt->context, f);
6479
 
        return(0);
6480
 
    }
6481
 
    ns = arg->nodesetval;
6482
 
    if (ns != NULL) {
6483
 
        for (i = 0;i < ns->nodeNr;i++) {
6484
 
             str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6485
 
             if (str2 != NULL) {
6486
 
                 valuePush(ctxt,
6487
 
                           xmlXPathCacheNewString(ctxt->context, str2));
6488
 
                 xmlFree(str2);
6489
 
                 xmlXPathNumberFunction(ctxt, 1);
6490
 
                 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6491
 
                 ret = xmlXPathCompareValues(ctxt, inf, strict);
6492
 
                 if (ret)
6493
 
                     break;
6494
 
             }
6495
 
        }
6496
 
    }
6497
 
    xmlXPathReleaseObject(ctxt->context, arg);
6498
 
    xmlXPathReleaseObject(ctxt->context, f);
6499
 
    return(ret);
6500
 
}
6501
 
 
6502
 
/**
6503
 
 * xmlXPathCompareNodeSetString:
6504
 
 * @ctxt:  the XPath Parser context
6505
 
 * @inf:  less than (1) or greater than (0)
6506
 
 * @strict:  is the comparison strict
6507
 
 * @arg:  the node set
6508
 
 * @s:  the value
6509
 
 *
6510
 
 * Implement the compare operation between a nodeset and a string
6511
 
 *     @ns < @val    (1, 1, ...
6512
 
 *     @ns <= @val   (1, 0, ...
6513
 
 *     @ns > @val    (0, 1, ...
6514
 
 *     @ns >= @val   (0, 0, ...
6515
 
 *
6516
 
 * If one object to be compared is a node-set and the other is a string,
6517
 
 * then the comparison will be true if and only if there is a node in
6518
 
 * the node-set such that the result of performing the comparison on the
6519
 
 * string-value of the node and the other string is true.
6520
 
 *
6521
 
 * Returns 0 or 1 depending on the results of the test.
6522
 
 */
6523
 
static int
6524
 
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6525
 
                            xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6526
 
    int i, ret = 0;
6527
 
    xmlNodeSetPtr ns;
6528
 
    xmlChar *str2;
6529
 
 
6530
 
    if ((s == NULL) || (arg == NULL) ||
6531
 
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6532
 
        xmlXPathReleaseObject(ctxt->context, arg);
6533
 
        xmlXPathReleaseObject(ctxt->context, s);
6534
 
        return(0);
6535
 
    }
6536
 
    ns = arg->nodesetval;
6537
 
    if (ns != NULL) {
6538
 
        for (i = 0;i < ns->nodeNr;i++) {
6539
 
             str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6540
 
             if (str2 != NULL) {
6541
 
                 valuePush(ctxt,
6542
 
                           xmlXPathCacheNewString(ctxt->context, str2));
6543
 
                 xmlFree(str2);
6544
 
                 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6545
 
                 ret = xmlXPathCompareValues(ctxt, inf, strict);
6546
 
                 if (ret)
6547
 
                     break;
6548
 
             }
6549
 
        }
6550
 
    }
6551
 
    xmlXPathReleaseObject(ctxt->context, arg);
6552
 
    xmlXPathReleaseObject(ctxt->context, s);
6553
 
    return(ret);
6554
 
}
6555
 
 
6556
 
/**
6557
 
 * xmlXPathCompareNodeSets:
6558
 
 * @inf:  less than (1) or greater than (0)
6559
 
 * @strict:  is the comparison strict
6560
 
 * @arg1:  the first node set object
6561
 
 * @arg2:  the second node set object
6562
 
 *
6563
 
 * Implement the compare operation on nodesets:
6564
 
 *
6565
 
 * If both objects to be compared are node-sets, then the comparison
6566
 
 * will be true if and only if there is a node in the first node-set
6567
 
 * and a node in the second node-set such that the result of performing
6568
 
 * the comparison on the string-values of the two nodes is true.
6569
 
 * ....
6570
 
 * When neither object to be compared is a node-set and the operator
6571
 
 * is <=, <, >= or >, then the objects are compared by converting both
6572
 
 * objects to numbers and comparing the numbers according to IEEE 754.
6573
 
 * ....
6574
 
 * The number function converts its argument to a number as follows:
6575
 
 *  - a string that consists of optional whitespace followed by an
6576
 
 *    optional minus sign followed by a Number followed by whitespace
6577
 
 *    is converted to the IEEE 754 number that is nearest (according
6578
 
 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6579
 
 *    represented by the string; any other string is converted to NaN
6580
 
 *
6581
 
 * Conclusion all nodes need to be converted first to their string value
6582
 
 * and then the comparison must be done when possible
6583
 
 */
6584
 
static int
6585
 
xmlXPathCompareNodeSets(int inf, int strict,
6586
 
                        xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6587
 
    int i, j, init = 0;
6588
 
    double val1;
6589
 
    double *values2;
6590
 
    int ret = 0;
6591
 
    xmlNodeSetPtr ns1;
6592
 
    xmlNodeSetPtr ns2;
6593
 
 
6594
 
    if ((arg1 == NULL) ||
6595
 
        ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6596
 
        xmlXPathFreeObject(arg2);
6597
 
        return(0);
6598
 
    }
6599
 
    if ((arg2 == NULL) ||
6600
 
        ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6601
 
        xmlXPathFreeObject(arg1);
6602
 
        xmlXPathFreeObject(arg2);
6603
 
        return(0);
6604
 
    }
6605
 
 
6606
 
    ns1 = arg1->nodesetval;
6607
 
    ns2 = arg2->nodesetval;
6608
 
 
6609
 
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6610
 
        xmlXPathFreeObject(arg1);
6611
 
        xmlXPathFreeObject(arg2);
6612
 
        return(0);
6613
 
    }
6614
 
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6615
 
        xmlXPathFreeObject(arg1);
6616
 
        xmlXPathFreeObject(arg2);
6617
 
        return(0);
6618
 
    }
6619
 
 
6620
 
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6621
 
    if (values2 == NULL) {
6622
 
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6623
 
        xmlXPathFreeObject(arg1);
6624
 
        xmlXPathFreeObject(arg2);
6625
 
        return(0);
6626
 
    }
6627
 
    for (i = 0;i < ns1->nodeNr;i++) {
6628
 
        val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6629
 
        if (xmlXPathIsNaN(val1))
6630
 
            continue;
6631
 
        for (j = 0;j < ns2->nodeNr;j++) {
6632
 
            if (init == 0) {
6633
 
                values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6634
 
            }
6635
 
            if (xmlXPathIsNaN(values2[j]))
6636
 
                continue;
6637
 
            if (inf && strict)
6638
 
                ret = (val1 < values2[j]);
6639
 
            else if (inf && !strict)
6640
 
                ret = (val1 <= values2[j]);
6641
 
            else if (!inf && strict)
6642
 
                ret = (val1 > values2[j]);
6643
 
            else if (!inf && !strict)
6644
 
                ret = (val1 >= values2[j]);
6645
 
            if (ret)
6646
 
                break;
6647
 
        }
6648
 
        if (ret)
6649
 
            break;
6650
 
        init = 1;
6651
 
    }
6652
 
    xmlFree(values2);
6653
 
    xmlXPathFreeObject(arg1);
6654
 
    xmlXPathFreeObject(arg2);
6655
 
    return(ret);
6656
 
}
6657
 
 
6658
 
/**
6659
 
 * xmlXPathCompareNodeSetValue:
6660
 
 * @ctxt:  the XPath Parser context
6661
 
 * @inf:  less than (1) or greater than (0)
6662
 
 * @strict:  is the comparison strict
6663
 
 * @arg:  the node set
6664
 
 * @val:  the value
6665
 
 *
6666
 
 * Implement the compare operation between a nodeset and a value
6667
 
 *     @ns < @val    (1, 1, ...
6668
 
 *     @ns <= @val   (1, 0, ...
6669
 
 *     @ns > @val    (0, 1, ...
6670
 
 *     @ns >= @val   (0, 0, ...
6671
 
 *
6672
 
 * If one object to be compared is a node-set and the other is a boolean,
6673
 
 * then the comparison will be true if and only if the result of performing
6674
 
 * the comparison on the boolean and on the result of converting
6675
 
 * the node-set to a boolean using the boolean function is true.
6676
 
 *
6677
 
 * Returns 0 or 1 depending on the results of the test.
6678
 
 */
6679
 
static int
6680
 
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6681
 
                            xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6682
 
    if ((val == NULL) || (arg == NULL) ||
6683
 
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6684
 
        return(0);
6685
 
 
6686
 
    switch(val->type) {
6687
 
        case XPATH_NUMBER:
6688
 
            return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6689
 
        case XPATH_NODESET:
6690
 
        case XPATH_XSLT_TREE:
6691
 
            return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6692
 
        case XPATH_STRING:
6693
 
            return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6694
 
        case XPATH_BOOLEAN:
6695
 
            valuePush(ctxt, arg);
6696
 
            xmlXPathBooleanFunction(ctxt, 1);
6697
 
            valuePush(ctxt, val);
6698
 
            return(xmlXPathCompareValues(ctxt, inf, strict));
6699
 
        default:
6700
 
            TODO
6701
 
    }
6702
 
    return(0);
6703
 
}
6704
 
 
6705
 
/**
6706
 
 * xmlXPathEqualNodeSetString:
6707
 
 * @arg:  the nodeset object argument
6708
 
 * @str:  the string to compare to.
6709
 
 * @neq:  flag to show whether for '=' (0) or '!=' (1)
6710
 
 *
6711
 
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6712
 
 * If one object to be compared is a node-set and the other is a string,
6713
 
 * then the comparison will be true if and only if there is a node in
6714
 
 * the node-set such that the result of performing the comparison on the
6715
 
 * string-value of the node and the other string is true.
6716
 
 *
6717
 
 * Returns 0 or 1 depending on the results of the test.
6718
 
 */
6719
 
static int
6720
 
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6721
 
{
6722
 
    int i;
6723
 
    xmlNodeSetPtr ns;
6724
 
    xmlChar *str2;
6725
 
    unsigned int hash;
6726
 
 
6727
 
    if ((str == NULL) || (arg == NULL) ||
6728
 
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6729
 
        return (0);
6730
 
    ns = arg->nodesetval;
6731
 
    /*
6732
 
     * A NULL nodeset compared with a string is always false
6733
 
     * (since there is no node equal, and no node not equal)
6734
 
     */
6735
 
    if ((ns == NULL) || (ns->nodeNr <= 0) )
6736
 
        return (0);
6737
 
    hash = xmlXPathStringHash(str);
6738
 
    for (i = 0; i < ns->nodeNr; i++) {
6739
 
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6740
 
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
6741
 
            if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6742
 
                xmlFree(str2);
6743
 
                if (neq)
6744
 
                    continue;
6745
 
                return (1);
6746
 
            } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6747
 
                if (neq)
6748
 
                    continue;
6749
 
                return (1);
6750
 
            } else if (neq) {
6751
 
                if (str2 != NULL)
6752
 
                    xmlFree(str2);
6753
 
                return (1);
6754
 
            }
6755
 
            if (str2 != NULL)
6756
 
                xmlFree(str2);
6757
 
        } else if (neq)
6758
 
            return (1);
6759
 
    }
6760
 
    return (0);
6761
 
}
6762
 
 
6763
 
/**
6764
 
 * xmlXPathEqualNodeSetFloat:
6765
 
 * @arg:  the nodeset object argument
6766
 
 * @f:  the float to compare to
6767
 
 * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6768
 
 *
6769
 
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6770
 
 * If one object to be compared is a node-set and the other is a number,
6771
 
 * then the comparison will be true if and only if there is a node in
6772
 
 * the node-set such that the result of performing the comparison on the
6773
 
 * number to be compared and on the result of converting the string-value
6774
 
 * of that node to a number using the number function is true.
6775
 
 *
6776
 
 * Returns 0 or 1 depending on the results of the test.
6777
 
 */
6778
 
static int
6779
 
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6780
 
    xmlXPathObjectPtr arg, double f, int neq) {
6781
 
  int i, ret=0;
6782
 
  xmlNodeSetPtr ns;
6783
 
  xmlChar *str2;
6784
 
  xmlXPathObjectPtr val;
6785
 
  double v;
6786
 
 
6787
 
    if ((arg == NULL) ||
6788
 
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6789
 
        return(0);
6790
 
 
6791
 
    ns = arg->nodesetval;
6792
 
    if (ns != NULL) {
6793
 
        for (i=0;i<ns->nodeNr;i++) {
6794
 
            str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6795
 
            if (str2 != NULL) {
6796
 
                valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6797
 
                xmlFree(str2);
6798
 
                xmlXPathNumberFunction(ctxt, 1);
6799
 
                val = valuePop(ctxt);
6800
 
                v = val->floatval;
6801
 
                xmlXPathReleaseObject(ctxt->context, val);
6802
 
                if (!xmlXPathIsNaN(v)) {
6803
 
                    if ((!neq) && (v==f)) {
6804
 
                        ret = 1;
6805
 
                        break;
6806
 
                    } else if ((neq) && (v!=f)) {
6807
 
                        ret = 1;
6808
 
                        break;
6809
 
                    }
6810
 
                } else {        /* NaN is unequal to any value */
6811
 
                    if (neq)
6812
 
                        ret = 1;
6813
 
                }
6814
 
            }
6815
 
        }
6816
 
    }
6817
 
 
6818
 
    return(ret);
6819
 
}
6820
 
 
6821
 
 
6822
 
/**
6823
 
 * xmlXPathEqualNodeSets:
6824
 
 * @arg1:  first nodeset object argument
6825
 
 * @arg2:  second nodeset object argument
6826
 
 * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6827
 
 *
6828
 
 * Implement the equal / not equal operation on XPath nodesets:
6829
 
 * @arg1 == @arg2  or  @arg1 != @arg2
6830
 
 * If both objects to be compared are node-sets, then the comparison
6831
 
 * will be true if and only if there is a node in the first node-set and
6832
 
 * a node in the second node-set such that the result of performing the
6833
 
 * comparison on the string-values of the two nodes is true.
6834
 
 *
6835
 
 * (needless to say, this is a costly operation)
6836
 
 *
6837
 
 * Returns 0 or 1 depending on the results of the test.
6838
 
 */
6839
 
static int
6840
 
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6841
 
    int i, j;
6842
 
    unsigned int *hashs1;
6843
 
    unsigned int *hashs2;
6844
 
    xmlChar **values1;
6845
 
    xmlChar **values2;
6846
 
    int ret = 0;
6847
 
    xmlNodeSetPtr ns1;
6848
 
    xmlNodeSetPtr ns2;
6849
 
 
6850
 
    if ((arg1 == NULL) ||
6851
 
        ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6852
 
        return(0);
6853
 
    if ((arg2 == NULL) ||
6854
 
        ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6855
 
        return(0);
6856
 
 
6857
 
    ns1 = arg1->nodesetval;
6858
 
    ns2 = arg2->nodesetval;
6859
 
 
6860
 
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6861
 
        return(0);
6862
 
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6863
 
        return(0);
6864
 
 
6865
 
    /*
6866
 
     * for equal, check if there is a node pertaining to both sets
6867
 
     */
6868
 
    if (neq == 0)
6869
 
        for (i = 0;i < ns1->nodeNr;i++)
6870
 
            for (j = 0;j < ns2->nodeNr;j++)
6871
 
                if (ns1->nodeTab[i] == ns2->nodeTab[j])
6872
 
                    return(1);
6873
 
 
6874
 
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6875
 
    if (values1 == NULL) {
6876
 
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6877
 
        return(0);
6878
 
    }
6879
 
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6880
 
    if (hashs1 == NULL) {
6881
 
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6882
 
        xmlFree(values1);
6883
 
        return(0);
6884
 
    }
6885
 
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6886
 
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6887
 
    if (values2 == NULL) {
6888
 
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6889
 
        xmlFree(hashs1);
6890
 
        xmlFree(values1);
6891
 
        return(0);
6892
 
    }
6893
 
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6894
 
    if (hashs2 == NULL) {
6895
 
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6896
 
        xmlFree(hashs1);
6897
 
        xmlFree(values1);
6898
 
        xmlFree(values2);
6899
 
        return(0);
6900
 
    }
6901
 
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6902
 
    for (i = 0;i < ns1->nodeNr;i++) {
6903
 
        hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6904
 
        for (j = 0;j < ns2->nodeNr;j++) {
6905
 
            if (i == 0)
6906
 
                hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6907
 
            if (hashs1[i] != hashs2[j]) {
6908
 
                if (neq) {
6909
 
                    ret = 1;
6910
 
                    break;
6911
 
                }
6912
 
            }
6913
 
            else {
6914
 
                if (values1[i] == NULL)
6915
 
                    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6916
 
                if (values2[j] == NULL)
6917
 
                    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6918
 
                ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6919
 
                if (ret)
6920
 
                    break;
6921
 
            }
6922
 
        }
6923
 
        if (ret)
6924
 
            break;
6925
 
    }
6926
 
    for (i = 0;i < ns1->nodeNr;i++)
6927
 
        if (values1[i] != NULL)
6928
 
            xmlFree(values1[i]);
6929
 
    for (j = 0;j < ns2->nodeNr;j++)
6930
 
        if (values2[j] != NULL)
6931
 
            xmlFree(values2[j]);
6932
 
    xmlFree(values1);
6933
 
    xmlFree(values2);
6934
 
    xmlFree(hashs1);
6935
 
    xmlFree(hashs2);
6936
 
    return(ret);
6937
 
}
6938
 
 
6939
 
static int
6940
 
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6941
 
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6942
 
    int ret = 0;
6943
 
    /*
6944
 
     *At this point we are assured neither arg1 nor arg2
6945
 
     *is a nodeset, so we can just pick the appropriate routine.
6946
 
     */
6947
 
    switch (arg1->type) {
6948
 
        case XPATH_UNDEFINED:
6949
 
#ifdef DEBUG_EXPR
6950
 
            xmlGenericError(xmlGenericErrorContext,
6951
 
                    "Equal: undefined\n");
6952
 
#endif
6953
 
            break;
6954
 
        case XPATH_BOOLEAN:
6955
 
            switch (arg2->type) {
6956
 
                case XPATH_UNDEFINED:
6957
 
#ifdef DEBUG_EXPR
6958
 
                    xmlGenericError(xmlGenericErrorContext,
6959
 
                            "Equal: undefined\n");
6960
 
#endif
6961
 
                    break;
6962
 
                case XPATH_BOOLEAN:
6963
 
#ifdef DEBUG_EXPR
6964
 
                    xmlGenericError(xmlGenericErrorContext,
6965
 
                            "Equal: %d boolean %d \n",
6966
 
                            arg1->boolval, arg2->boolval);
6967
 
#endif
6968
 
                    ret = (arg1->boolval == arg2->boolval);
6969
 
                    break;
6970
 
                case XPATH_NUMBER:
6971
 
                    ret = (arg1->boolval ==
6972
 
                           xmlXPathCastNumberToBoolean(arg2->floatval));
6973
 
                    break;
6974
 
                case XPATH_STRING:
6975
 
                    if ((arg2->stringval == NULL) ||
6976
 
                        (arg2->stringval[0] == 0)) ret = 0;
6977
 
                    else
6978
 
                        ret = 1;
6979
 
                    ret = (arg1->boolval == ret);
6980
 
                    break;
6981
 
                case XPATH_USERS:
6982
 
                case XPATH_POINT:
6983
 
                case XPATH_RANGE:
6984
 
                case XPATH_LOCATIONSET:
6985
 
                    TODO
6986
 
                    break;
6987
 
                case XPATH_NODESET:
6988
 
                case XPATH_XSLT_TREE:
6989
 
                    break;
6990
 
            }
6991
 
            break;
6992
 
        case XPATH_NUMBER:
6993
 
            switch (arg2->type) {
6994
 
                case XPATH_UNDEFINED:
6995
 
#ifdef DEBUG_EXPR
6996
 
                    xmlGenericError(xmlGenericErrorContext,
6997
 
                            "Equal: undefined\n");
6998
 
#endif
6999
 
                    break;
7000
 
                case XPATH_BOOLEAN:
7001
 
                    ret = (arg2->boolval==
7002
 
                           xmlXPathCastNumberToBoolean(arg1->floatval));
7003
 
                    break;
7004
 
                case XPATH_STRING:
7005
 
                    valuePush(ctxt, arg2);
7006
 
                    xmlXPathNumberFunction(ctxt, 1);
7007
 
                    arg2 = valuePop(ctxt);
7008
 
                    /* no break on purpose */
7009
 
                case XPATH_NUMBER:
7010
 
                    /* Hand check NaN and Infinity equalities */
7011
 
                    if (xmlXPathIsNaN(arg1->floatval) ||
7012
 
                            xmlXPathIsNaN(arg2->floatval)) {
7013
 
                        ret = 0;
7014
 
                    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7015
 
                        if (xmlXPathIsInf(arg2->floatval) == 1)
7016
 
                            ret = 1;
7017
 
                        else
7018
 
                            ret = 0;
7019
 
                    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7020
 
                        if (xmlXPathIsInf(arg2->floatval) == -1)
7021
 
                            ret = 1;
7022
 
                        else
7023
 
                            ret = 0;
7024
 
                    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7025
 
                        if (xmlXPathIsInf(arg1->floatval) == 1)
7026
 
                            ret = 1;
7027
 
                        else
7028
 
                            ret = 0;
7029
 
                    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7030
 
                        if (xmlXPathIsInf(arg1->floatval) == -1)
7031
 
                            ret = 1;
7032
 
                        else
7033
 
                            ret = 0;
7034
 
                    } else {
7035
 
                        ret = (arg1->floatval == arg2->floatval);
7036
 
                    }
7037
 
                    break;
7038
 
                case XPATH_USERS:
7039
 
                case XPATH_POINT:
7040
 
                case XPATH_RANGE:
7041
 
                case XPATH_LOCATIONSET:
7042
 
                    TODO
7043
 
                    break;
7044
 
                case XPATH_NODESET:
7045
 
                case XPATH_XSLT_TREE:
7046
 
                    break;
7047
 
            }
7048
 
            break;
7049
 
        case XPATH_STRING:
7050
 
            switch (arg2->type) {
7051
 
                case XPATH_UNDEFINED:
7052
 
#ifdef DEBUG_EXPR
7053
 
                    xmlGenericError(xmlGenericErrorContext,
7054
 
                            "Equal: undefined\n");
7055
 
#endif
7056
 
                    break;
7057
 
                case XPATH_BOOLEAN:
7058
 
                    if ((arg1->stringval == NULL) ||
7059
 
                        (arg1->stringval[0] == 0)) ret = 0;
7060
 
                    else
7061
 
                        ret = 1;
7062
 
                    ret = (arg2->boolval == ret);
7063
 
                    break;
7064
 
                case XPATH_STRING:
7065
 
                    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7066
 
                    break;
7067
 
                case XPATH_NUMBER:
7068
 
                    valuePush(ctxt, arg1);
7069
 
                    xmlXPathNumberFunction(ctxt, 1);
7070
 
                    arg1 = valuePop(ctxt);
7071
 
                    /* Hand check NaN and Infinity equalities */
7072
 
                    if (xmlXPathIsNaN(arg1->floatval) ||
7073
 
                            xmlXPathIsNaN(arg2->floatval)) {
7074
 
                        ret = 0;
7075
 
                    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7076
 
                        if (xmlXPathIsInf(arg2->floatval) == 1)
7077
 
                            ret = 1;
7078
 
                        else
7079
 
                            ret = 0;
7080
 
                    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7081
 
                        if (xmlXPathIsInf(arg2->floatval) == -1)
7082
 
                            ret = 1;
7083
 
                        else
7084
 
                            ret = 0;
7085
 
                    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7086
 
                        if (xmlXPathIsInf(arg1->floatval) == 1)
7087
 
                            ret = 1;
7088
 
                        else
7089
 
                            ret = 0;
7090
 
                    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7091
 
                        if (xmlXPathIsInf(arg1->floatval) == -1)
7092
 
                            ret = 1;
7093
 
                        else
7094
 
                            ret = 0;
7095
 
                    } else {
7096
 
                        ret = (arg1->floatval == arg2->floatval);
7097
 
                    }
7098
 
                    break;
7099
 
                case XPATH_USERS:
7100
 
                case XPATH_POINT:
7101
 
                case XPATH_RANGE:
7102
 
                case XPATH_LOCATIONSET:
7103
 
                    TODO
7104
 
                    break;
7105
 
                case XPATH_NODESET:
7106
 
                case XPATH_XSLT_TREE:
7107
 
                    break;
7108
 
            }
7109
 
            break;
7110
 
        case XPATH_USERS:
7111
 
        case XPATH_POINT:
7112
 
        case XPATH_RANGE:
7113
 
        case XPATH_LOCATIONSET:
7114
 
            TODO
7115
 
            break;
7116
 
        case XPATH_NODESET:
7117
 
        case XPATH_XSLT_TREE:
7118
 
            break;
7119
 
    }
7120
 
    xmlXPathReleaseObject(ctxt->context, arg1);
7121
 
    xmlXPathReleaseObject(ctxt->context, arg2);
7122
 
    return(ret);
7123
 
}
7124
 
 
7125
 
/**
7126
 
 * xmlXPathEqualValues:
7127
 
 * @ctxt:  the XPath Parser context
7128
 
 *
7129
 
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7130
 
 *
7131
 
 * Returns 0 or 1 depending on the results of the test.
7132
 
 */
7133
 
int
7134
 
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7135
 
    xmlXPathObjectPtr arg1, arg2, argtmp;
7136
 
    int ret = 0;
7137
 
 
7138
 
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7139
 
    arg2 = valuePop(ctxt);
7140
 
    arg1 = valuePop(ctxt);
7141
 
    if ((arg1 == NULL) || (arg2 == NULL)) {
7142
 
        if (arg1 != NULL)
7143
 
            xmlXPathReleaseObject(ctxt->context, arg1);
7144
 
        else
7145
 
            xmlXPathReleaseObject(ctxt->context, arg2);
7146
 
        XP_ERROR0(XPATH_INVALID_OPERAND);
7147
 
    }
7148
 
 
7149
 
    if (arg1 == arg2) {
7150
 
#ifdef DEBUG_EXPR
7151
 
        xmlGenericError(xmlGenericErrorContext,
7152
 
                "Equal: by pointer\n");
7153
 
#endif
7154
 
        xmlXPathFreeObject(arg1);
7155
 
        return(1);
7156
 
    }
7157
 
 
7158
 
    /*
7159
 
     *If either argument is a nodeset, it's a 'special case'
7160
 
     */
7161
 
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7162
 
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7163
 
        /*
7164
 
         *Hack it to assure arg1 is the nodeset
7165
 
         */
7166
 
        if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7167
 
                argtmp = arg2;
7168
 
                arg2 = arg1;
7169
 
                arg1 = argtmp;
7170
 
        }
7171
 
        switch (arg2->type) {
7172
 
            case XPATH_UNDEFINED:
7173
 
#ifdef DEBUG_EXPR
7174
 
                xmlGenericError(xmlGenericErrorContext,
7175
 
                        "Equal: undefined\n");
7176
 
#endif
7177
 
                break;
7178
 
            case XPATH_NODESET:
7179
 
            case XPATH_XSLT_TREE:
7180
 
                ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7181
 
                break;
7182
 
            case XPATH_BOOLEAN:
7183
 
                if ((arg1->nodesetval == NULL) ||
7184
 
                  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7185
 
                else
7186
 
                    ret = 1;
7187
 
                ret = (ret == arg2->boolval);
7188
 
                break;
7189
 
            case XPATH_NUMBER:
7190
 
                ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7191
 
                break;
7192
 
            case XPATH_STRING:
7193
 
                ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7194
 
                break;
7195
 
            case XPATH_USERS:
7196
 
            case XPATH_POINT:
7197
 
            case XPATH_RANGE:
7198
 
            case XPATH_LOCATIONSET:
7199
 
                TODO
7200
 
                break;
7201
 
        }
7202
 
        xmlXPathReleaseObject(ctxt->context, arg1);
7203
 
        xmlXPathReleaseObject(ctxt->context, arg2);
7204
 
        return(ret);
7205
 
    }
7206
 
 
7207
 
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7208
 
}
7209
 
 
7210
 
/**
7211
 
 * xmlXPathNotEqualValues:
7212
 
 * @ctxt:  the XPath Parser context
7213
 
 *
7214
 
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7215
 
 *
7216
 
 * Returns 0 or 1 depending on the results of the test.
7217
 
 */
7218
 
int
7219
 
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7220
 
    xmlXPathObjectPtr arg1, arg2, argtmp;
7221
 
    int ret = 0;
7222
 
 
7223
 
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7224
 
    arg2 = valuePop(ctxt);
7225
 
    arg1 = valuePop(ctxt);
7226
 
    if ((arg1 == NULL) || (arg2 == NULL)) {
7227
 
        if (arg1 != NULL)
7228
 
            xmlXPathReleaseObject(ctxt->context, arg1);
7229
 
        else
7230
 
            xmlXPathReleaseObject(ctxt->context, arg2);
7231
 
        XP_ERROR0(XPATH_INVALID_OPERAND);
7232
 
    }
7233
 
 
7234
 
    if (arg1 == arg2) {
7235
 
#ifdef DEBUG_EXPR
7236
 
        xmlGenericError(xmlGenericErrorContext,
7237
 
                "NotEqual: by pointer\n");
7238
 
#endif
7239
 
        xmlXPathReleaseObject(ctxt->context, arg1);
7240
 
        return(0);
7241
 
    }
7242
 
 
7243
 
    /*
7244
 
     *If either argument is a nodeset, it's a 'special case'
7245
 
     */
7246
 
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7247
 
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7248
 
        /*
7249
 
         *Hack it to assure arg1 is the nodeset
7250
 
         */
7251
 
        if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7252
 
                argtmp = arg2;
7253
 
                arg2 = arg1;
7254
 
                arg1 = argtmp;
7255
 
        }
7256
 
        switch (arg2->type) {
7257
 
            case XPATH_UNDEFINED:
7258
 
#ifdef DEBUG_EXPR
7259
 
                xmlGenericError(xmlGenericErrorContext,
7260
 
                        "NotEqual: undefined\n");
7261
 
#endif
7262
 
                break;
7263
 
            case XPATH_NODESET:
7264
 
            case XPATH_XSLT_TREE:
7265
 
                ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7266
 
                break;
7267
 
            case XPATH_BOOLEAN:
7268
 
                if ((arg1->nodesetval == NULL) ||
7269
 
                  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7270
 
                else
7271
 
                    ret = 1;
7272
 
                ret = (ret != arg2->boolval);
7273
 
                break;
7274
 
            case XPATH_NUMBER:
7275
 
                ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7276
 
                break;
7277
 
            case XPATH_STRING:
7278
 
                ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7279
 
                break;
7280
 
            case XPATH_USERS:
7281
 
            case XPATH_POINT:
7282
 
            case XPATH_RANGE:
7283
 
            case XPATH_LOCATIONSET:
7284
 
                TODO
7285
 
                break;
7286
 
        }
7287
 
        xmlXPathReleaseObject(ctxt->context, arg1);
7288
 
        xmlXPathReleaseObject(ctxt->context, arg2);
7289
 
        return(ret);
7290
 
    }
7291
 
 
7292
 
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7293
 
}
7294
 
 
7295
 
/**
7296
 
 * xmlXPathCompareValues:
7297
 
 * @ctxt:  the XPath Parser context
7298
 
 * @inf:  less than (1) or greater than (0)
7299
 
 * @strict:  is the comparison strict
7300
 
 *
7301
 
 * Implement the compare operation on XPath objects:
7302
 
 *     @arg1 < @arg2    (1, 1, ...
7303
 
 *     @arg1 <= @arg2   (1, 0, ...
7304
 
 *     @arg1 > @arg2    (0, 1, ...
7305
 
 *     @arg1 >= @arg2   (0, 0, ...
7306
 
 *
7307
 
 * When neither object to be compared is a node-set and the operator is
7308
 
 * <=, <, >=, >, then the objects are compared by converted both objects
7309
 
 * to numbers and comparing the numbers according to IEEE 754. The <
7310
 
 * comparison will be true if and only if the first number is less than the
7311
 
 * second number. The <= comparison will be true if and only if the first
7312
 
 * number is less than or equal to the second number. The > comparison
7313
 
 * will be true if and only if the first number is greater than the second
7314
 
 * number. The >= comparison will be true if and only if the first number
7315
 
 * is greater than or equal to the second number.
7316
 
 *
7317
 
 * Returns 1 if the comparison succeeded, 0 if it failed
7318
 
 */
7319
 
int
7320
 
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7321
 
    int ret = 0, arg1i = 0, arg2i = 0;
7322
 
    xmlXPathObjectPtr arg1, arg2;
7323
 
 
7324
 
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7325
 
    arg2 = valuePop(ctxt);
7326
 
    arg1 = valuePop(ctxt);
7327
 
    if ((arg1 == NULL) || (arg2 == NULL)) {
7328
 
        if (arg1 != NULL)
7329
 
            xmlXPathReleaseObject(ctxt->context, arg1);
7330
 
        else
7331
 
            xmlXPathReleaseObject(ctxt->context, arg2);
7332
 
        XP_ERROR0(XPATH_INVALID_OPERAND);
7333
 
    }
7334
 
 
7335
 
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7336
 
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7337
 
        /*
7338
 
         * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7339
 
         * are not freed from within this routine; they will be freed from the
7340
 
         * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7341
 
         */
7342
 
        if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7343
 
          ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7344
 
            ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7345
 
        } else {
7346
 
            if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7347
 
                ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7348
 
                                                  arg1, arg2);
7349
 
            } else {
7350
 
                ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7351
 
                                                  arg2, arg1);
7352
 
            }
7353
 
        }
7354
 
        return(ret);
7355
 
    }
7356
 
 
7357
 
    if (arg1->type != XPATH_NUMBER) {
7358
 
        valuePush(ctxt, arg1);
7359
 
        xmlXPathNumberFunction(ctxt, 1);
7360
 
        arg1 = valuePop(ctxt);
7361
 
    }
7362
 
    if (arg1->type != XPATH_NUMBER) {
7363
 
        xmlXPathFreeObject(arg1);
7364
 
        xmlXPathFreeObject(arg2);
7365
 
        XP_ERROR0(XPATH_INVALID_OPERAND);
7366
 
    }
7367
 
    if (arg2->type != XPATH_NUMBER) {
7368
 
        valuePush(ctxt, arg2);
7369
 
        xmlXPathNumberFunction(ctxt, 1);
7370
 
        arg2 = valuePop(ctxt);
7371
 
    }
7372
 
    if (arg2->type != XPATH_NUMBER) {
7373
 
        xmlXPathReleaseObject(ctxt->context, arg1);
7374
 
        xmlXPathReleaseObject(ctxt->context, arg2);
7375
 
        XP_ERROR0(XPATH_INVALID_OPERAND);
7376
 
    }
7377
 
    /*
7378
 
     * Add tests for infinity and nan
7379
 
     * => feedback on 3.4 for Inf and NaN
7380
 
     */
7381
 
    /* Hand check NaN and Infinity comparisons */
7382
 
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7383
 
        ret=0;
7384
 
    } else {
7385
 
        arg1i=xmlXPathIsInf(arg1->floatval);
7386
 
        arg2i=xmlXPathIsInf(arg2->floatval);
7387
 
        if (inf && strict) {
7388
 
            if ((arg1i == -1 && arg2i != -1) ||
7389
 
                (arg2i == 1 && arg1i != 1)) {
7390
 
                ret = 1;
7391
 
            } else if (arg1i == 0 && arg2i == 0) {
7392
 
                ret = (arg1->floatval < arg2->floatval);
7393
 
            } else {
7394
 
                ret = 0;
7395
 
            }
7396
 
        }
7397
 
        else if (inf && !strict) {
7398
 
            if (arg1i == -1 || arg2i == 1) {
7399
 
                ret = 1;
7400
 
            } else if (arg1i == 0 && arg2i == 0) {
7401
 
                ret = (arg1->floatval <= arg2->floatval);
7402
 
            } else {
7403
 
                ret = 0;
7404
 
            }
7405
 
        }
7406
 
        else if (!inf && strict) {
7407
 
            if ((arg1i == 1 && arg2i != 1) ||
7408
 
                (arg2i == -1 && arg1i != -1)) {
7409
 
                ret = 1;
7410
 
            } else if (arg1i == 0 && arg2i == 0) {
7411
 
                ret = (arg1->floatval > arg2->floatval);
7412
 
            } else {
7413
 
                ret = 0;
7414
 
            }
7415
 
        }
7416
 
        else if (!inf && !strict) {
7417
 
            if (arg1i == 1 || arg2i == -1) {
7418
 
                ret = 1;
7419
 
            } else if (arg1i == 0 && arg2i == 0) {
7420
 
                ret = (arg1->floatval >= arg2->floatval);
7421
 
            } else {
7422
 
                ret = 0;
7423
 
            }
7424
 
        }
7425
 
    }
7426
 
    xmlXPathReleaseObject(ctxt->context, arg1);
7427
 
    xmlXPathReleaseObject(ctxt->context, arg2);
7428
 
    return(ret);
7429
 
}
7430
 
 
7431
 
/**
7432
 
 * xmlXPathValueFlipSign:
7433
 
 * @ctxt:  the XPath Parser context
7434
 
 *
7435
 
 * Implement the unary - operation on an XPath object
7436
 
 * The numeric operators convert their operands to numbers as if
7437
 
 * by calling the number function.
7438
 
 */
7439
 
void
7440
 
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7441
 
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7442
 
    CAST_TO_NUMBER;
7443
 
    CHECK_TYPE(XPATH_NUMBER);
7444
 
    if (xmlXPathIsNaN(ctxt->value->floatval))
7445
 
        ctxt->value->floatval=xmlXPathNAN;
7446
 
    else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7447
 
        ctxt->value->floatval=xmlXPathNINF;
7448
 
    else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7449
 
        ctxt->value->floatval=xmlXPathPINF;
7450
 
    else if (ctxt->value->floatval == 0) {
7451
 
        if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7452
 
            ctxt->value->floatval = xmlXPathNZERO;
7453
 
        else
7454
 
            ctxt->value->floatval = 0;
7455
 
    }
7456
 
    else
7457
 
        ctxt->value->floatval = - ctxt->value->floatval;
7458
 
}
7459
 
 
7460
 
/**
7461
 
 * xmlXPathAddValues:
7462
 
 * @ctxt:  the XPath Parser context
7463
 
 *
7464
 
 * Implement the add operation on XPath objects:
7465
 
 * The numeric operators convert their operands to numbers as if
7466
 
 * by calling the number function.
7467
 
 */
7468
 
void
7469
 
xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7470
 
    xmlXPathObjectPtr arg;
7471
 
    double val;
7472
 
 
7473
 
    arg = valuePop(ctxt);
7474
 
    if (arg == NULL)
7475
 
        XP_ERROR(XPATH_INVALID_OPERAND);
7476
 
    val = xmlXPathCastToNumber(arg);
7477
 
    xmlXPathReleaseObject(ctxt->context, arg);
7478
 
    CAST_TO_NUMBER;
7479
 
    CHECK_TYPE(XPATH_NUMBER);
7480
 
    ctxt->value->floatval += val;
7481
 
}
7482
 
 
7483
 
/**
7484
 
 * xmlXPathSubValues:
7485
 
 * @ctxt:  the XPath Parser context
7486
 
 *
7487
 
 * Implement the subtraction operation on XPath objects:
7488
 
 * The numeric operators convert their operands to numbers as if
7489
 
 * by calling the number function.
7490
 
 */
7491
 
void
7492
 
xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7493
 
    xmlXPathObjectPtr arg;
7494
 
    double val;
7495
 
 
7496
 
    arg = valuePop(ctxt);
7497
 
    if (arg == NULL)
7498
 
        XP_ERROR(XPATH_INVALID_OPERAND);
7499
 
    val = xmlXPathCastToNumber(arg);
7500
 
    xmlXPathReleaseObject(ctxt->context, arg);
7501
 
    CAST_TO_NUMBER;
7502
 
    CHECK_TYPE(XPATH_NUMBER);
7503
 
    ctxt->value->floatval -= val;
7504
 
}
7505
 
 
7506
 
/**
7507
 
 * xmlXPathMultValues:
7508
 
 * @ctxt:  the XPath Parser context
7509
 
 *
7510
 
 * Implement the multiply operation on XPath objects:
7511
 
 * The numeric operators convert their operands to numbers as if
7512
 
 * by calling the number function.
7513
 
 */
7514
 
void
7515
 
xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7516
 
    xmlXPathObjectPtr arg;
7517
 
    double val;
7518
 
 
7519
 
    arg = valuePop(ctxt);
7520
 
    if (arg == NULL)
7521
 
        XP_ERROR(XPATH_INVALID_OPERAND);
7522
 
    val = xmlXPathCastToNumber(arg);
7523
 
    xmlXPathReleaseObject(ctxt->context, arg);
7524
 
    CAST_TO_NUMBER;
7525
 
    CHECK_TYPE(XPATH_NUMBER);
7526
 
    ctxt->value->floatval *= val;
7527
 
}
7528
 
 
7529
 
/**
7530
 
 * xmlXPathDivValues:
7531
 
 * @ctxt:  the XPath Parser context
7532
 
 *
7533
 
 * Implement the div operation on XPath objects @arg1 / @arg2:
7534
 
 * The numeric operators convert their operands to numbers as if
7535
 
 * by calling the number function.
7536
 
 */
7537
 
void
7538
 
xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7539
 
    xmlXPathObjectPtr arg;
7540
 
    double val;
7541
 
 
7542
 
    arg = valuePop(ctxt);
7543
 
    if (arg == NULL)
7544
 
        XP_ERROR(XPATH_INVALID_OPERAND);
7545
 
    val = xmlXPathCastToNumber(arg);
7546
 
    xmlXPathReleaseObject(ctxt->context, arg);
7547
 
    CAST_TO_NUMBER;
7548
 
    CHECK_TYPE(XPATH_NUMBER);
7549
 
    if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7550
 
        ctxt->value->floatval = xmlXPathNAN;
7551
 
    else if (val == 0 && xmlXPathGetSign(val) != 0) {
7552
 
        if (ctxt->value->floatval == 0)
7553
 
            ctxt->value->floatval = xmlXPathNAN;
7554
 
        else if (ctxt->value->floatval > 0)
7555
 
            ctxt->value->floatval = xmlXPathNINF;
7556
 
        else if (ctxt->value->floatval < 0)
7557
 
            ctxt->value->floatval = xmlXPathPINF;
7558
 
    }
7559
 
    else if (val == 0) {
7560
 
        if (ctxt->value->floatval == 0)
7561
 
            ctxt->value->floatval = xmlXPathNAN;
7562
 
        else if (ctxt->value->floatval > 0)
7563
 
            ctxt->value->floatval = xmlXPathPINF;
7564
 
        else if (ctxt->value->floatval < 0)
7565
 
            ctxt->value->floatval = xmlXPathNINF;
7566
 
    } else
7567
 
        ctxt->value->floatval /= val;
7568
 
}
7569
 
 
7570
 
/**
7571
 
 * xmlXPathModValues:
7572
 
 * @ctxt:  the XPath Parser context
7573
 
 *
7574
 
 * Implement the mod operation on XPath objects: @arg1 / @arg2
7575
 
 * The numeric operators convert their operands to numbers as if
7576
 
 * by calling the number function.
7577
 
 */
7578
 
void
7579
 
xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7580
 
    xmlXPathObjectPtr arg;
7581
 
    double arg1, arg2;
7582
 
 
7583
 
    arg = valuePop(ctxt);
7584
 
    if (arg == NULL)
7585
 
        XP_ERROR(XPATH_INVALID_OPERAND);
7586
 
    arg2 = xmlXPathCastToNumber(arg);
7587
 
    xmlXPathReleaseObject(ctxt->context, arg);
7588
 
    CAST_TO_NUMBER;
7589
 
    CHECK_TYPE(XPATH_NUMBER);
7590
 
    arg1 = ctxt->value->floatval;
7591
 
    if (arg2 == 0)
7592
 
        ctxt->value->floatval = xmlXPathNAN;
7593
 
    else {
7594
 
        ctxt->value->floatval = fmod(arg1, arg2);
7595
 
    }
7596
 
}
7597
 
 
7598
 
/************************************************************************
7599
 
 *                                                                      *
7600
 
 *              The traversal functions                                 *
7601
 
 *                                                                      *
7602
 
 ************************************************************************/
7603
 
 
7604
 
/*
7605
 
 * A traversal function enumerates nodes along an axis.
7606
 
 * Initially it must be called with NULL, and it indicates
7607
 
 * termination on the axis by returning NULL.
7608
 
 */
7609
 
typedef xmlNodePtr (*xmlXPathTraversalFunction)
7610
 
                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7611
 
 
7612
 
/*
7613
 
 * xmlXPathTraversalFunctionExt:
7614
 
 * A traversal function enumerates nodes along an axis.
7615
 
 * Initially it must be called with NULL, and it indicates
7616
 
 * termination on the axis by returning NULL.
7617
 
 * The context node of the traversal is specified via @contextNode.
7618
 
 */
7619
 
typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7620
 
                    (xmlNodePtr cur, xmlNodePtr contextNode);
7621
 
 
7622
 
/*
7623
 
 * xmlXPathNodeSetMergeFunction:
7624
 
 * Used for merging node sets in xmlXPathCollectAndTest().
7625
 
 */
7626
 
typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7627
 
                    (xmlNodeSetPtr, xmlNodeSetPtr, int);
7628
 
 
7629
 
 
7630
 
/**
7631
 
 * xmlXPathNextSelf:
7632
 
 * @ctxt:  the XPath Parser context
7633
 
 * @cur:  the current node in the traversal
7634
 
 *
7635
 
 * Traversal function for the "self" direction
7636
 
 * The self axis contains just the context node itself
7637
 
 *
7638
 
 * Returns the next element following that axis
7639
 
 */
7640
 
xmlNodePtr
7641
 
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7642
 
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7643
 
    if (cur == NULL)
7644
 
        return(ctxt->context->node);
7645
 
    return(NULL);
7646
 
}
7647
 
 
7648
 
/**
7649
 
 * xmlXPathNextChild:
7650
 
 * @ctxt:  the XPath Parser context
7651
 
 * @cur:  the current node in the traversal
7652
 
 *
7653
 
 * Traversal function for the "child" direction
7654
 
 * The child axis contains the children of the context node in document order.
7655
 
 *
7656
 
 * Returns the next element following that axis
7657
 
 */
7658
 
xmlNodePtr
7659
 
xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7660
 
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7661
 
    if (cur == NULL) {
7662
 
        if (ctxt->context->node == NULL) return(NULL);
7663
 
        switch (ctxt->context->node->type) {
7664
 
            case XML_ELEMENT_NODE:
7665
 
            case XML_TEXT_NODE:
7666
 
            case XML_CDATA_SECTION_NODE:
7667
 
            case XML_ENTITY_REF_NODE:
7668
 
            case XML_ENTITY_NODE:
7669
 
            case XML_PI_NODE:
7670
 
            case XML_COMMENT_NODE:
7671
 
            case XML_NOTATION_NODE:
7672
 
            case XML_DTD_NODE:
7673
 
                return(ctxt->context->node->children);
7674
 
            case XML_DOCUMENT_NODE:
7675
 
            case XML_DOCUMENT_TYPE_NODE:
7676
 
            case XML_DOCUMENT_FRAG_NODE:
7677
 
            case XML_HTML_DOCUMENT_NODE:
7678
 
#ifdef LIBXML_DOCB_ENABLED
7679
 
            case XML_DOCB_DOCUMENT_NODE:
7680
 
#endif
7681
 
                return(((xmlDocPtr) ctxt->context->node)->children);
7682
 
            case XML_ELEMENT_DECL:
7683
 
            case XML_ATTRIBUTE_DECL:
7684
 
            case XML_ENTITY_DECL:
7685
 
            case XML_ATTRIBUTE_NODE:
7686
 
            case XML_NAMESPACE_DECL:
7687
 
            case XML_XINCLUDE_START:
7688
 
            case XML_XINCLUDE_END:
7689
 
                return(NULL);
7690
 
        }
7691
 
        return(NULL);
7692
 
    }
7693
 
    if ((cur->type == XML_DOCUMENT_NODE) ||
7694
 
        (cur->type == XML_HTML_DOCUMENT_NODE))
7695
 
        return(NULL);
7696
 
    return(cur->next);
7697
 
}
7698
 
 
7699
 
/**
7700
 
 * xmlXPathNextChildElement:
7701
 
 * @ctxt:  the XPath Parser context
7702
 
 * @cur:  the current node in the traversal
7703
 
 *
7704
 
 * Traversal function for the "child" direction and nodes of type element.
7705
 
 * The child axis contains the children of the context node in document order.
7706
 
 *
7707
 
 * Returns the next element following that axis
7708
 
 */
7709
 
static xmlNodePtr
7710
 
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7711
 
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7712
 
    if (cur == NULL) {
7713
 
        cur = ctxt->context->node;
7714
 
        if (cur == NULL) return(NULL);
7715
 
        /*
7716
 
        * Get the first element child.
7717
 
        */
7718
 
        switch (cur->type) {
7719
 
            case XML_ELEMENT_NODE:
7720
 
            case XML_DOCUMENT_FRAG_NODE:
7721
 
            case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7722
 
            case XML_ENTITY_NODE:
7723
 
                cur = cur->children;
7724
 
                if (cur != NULL) {
7725
 
                    if (cur->type == XML_ELEMENT_NODE)
7726
 
                        return(cur);
7727
 
                    do {
7728
 
                        cur = cur->next;
7729
 
                    } while ((cur != NULL) &&
7730
 
                        (cur->type != XML_ELEMENT_NODE));
7731
 
                    return(cur);
7732
 
                }
7733
 
                return(NULL);
7734
 
            case XML_DOCUMENT_NODE:
7735
 
            case XML_HTML_DOCUMENT_NODE:
7736
 
#ifdef LIBXML_DOCB_ENABLED
7737
 
            case XML_DOCB_DOCUMENT_NODE:
7738
 
#endif
7739
 
                return(xmlDocGetRootElement((xmlDocPtr) cur));
7740
 
            default:
7741
 
                return(NULL);
7742
 
        }
7743
 
        return(NULL);
7744
 
    }
7745
 
    /*
7746
 
    * Get the next sibling element node.
7747
 
    */
7748
 
    switch (cur->type) {
7749
 
        case XML_ELEMENT_NODE:
7750
 
        case XML_TEXT_NODE:
7751
 
        case XML_ENTITY_REF_NODE:
7752
 
        case XML_ENTITY_NODE:
7753
 
        case XML_CDATA_SECTION_NODE:
7754
 
        case XML_PI_NODE:
7755
 
        case XML_COMMENT_NODE:
7756
 
        case XML_XINCLUDE_END:
7757
 
            break;
7758
 
        /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7759
 
        default:
7760
 
            return(NULL);
7761
 
    }
7762
 
    if (cur->next != NULL) {
7763
 
        if (cur->next->type == XML_ELEMENT_NODE)
7764
 
            return(cur->next);
7765
 
        cur = cur->next;
7766
 
        do {
7767
 
            cur = cur->next;
7768
 
        } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7769
 
        return(cur);
7770
 
    }
7771
 
    return(NULL);
7772
 
}
7773
 
 
7774
 
#if 0
7775
 
/**
7776
 
 * xmlXPathNextDescendantOrSelfElemParent:
7777
 
 * @ctxt:  the XPath Parser context
7778
 
 * @cur:  the current node in the traversal
7779
 
 *
7780
 
 * Traversal function for the "descendant-or-self" axis.
7781
 
 * Additionally it returns only nodes which can be parents of
7782
 
 * element nodes.
7783
 
 *
7784
 
 *
7785
 
 * Returns the next element following that axis
7786
 
 */
7787
 
static xmlNodePtr
7788
 
xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7789
 
                                       xmlNodePtr contextNode)
7790
 
{
7791
 
    if (cur == NULL) {
7792
 
        if (contextNode == NULL)
7793
 
            return(NULL);
7794
 
        switch (contextNode->type) {
7795
 
            case XML_ELEMENT_NODE:
7796
 
            case XML_XINCLUDE_START:
7797
 
            case XML_DOCUMENT_FRAG_NODE:
7798
 
            case XML_DOCUMENT_NODE:
7799
 
#ifdef LIBXML_DOCB_ENABLED
7800
 
            case XML_DOCB_DOCUMENT_NODE:
7801
 
#endif
7802
 
            case XML_HTML_DOCUMENT_NODE:
7803
 
                return(contextNode);
7804
 
            default:
7805
 
                return(NULL);
7806
 
        }
7807
 
        return(NULL);
7808
 
    } else {
7809
 
        xmlNodePtr start = cur;
7810
 
 
7811
 
        while (cur != NULL) {
7812
 
            switch (cur->type) {
7813
 
                case XML_ELEMENT_NODE:
7814
 
                /* TODO: OK to have XInclude here? */
7815
 
                case XML_XINCLUDE_START:
7816
 
                case XML_DOCUMENT_FRAG_NODE:
7817
 
                    if (cur != start)
7818
 
                        return(cur);
7819
 
                    if (cur->children != NULL) {
7820
 
                        cur = cur->children;
7821
 
                        continue;
7822
 
                    }
7823
 
                    break;
7824
 
                /* Not sure if we need those here. */
7825
 
                case XML_DOCUMENT_NODE:
7826
 
#ifdef LIBXML_DOCB_ENABLED
7827
 
                case XML_DOCB_DOCUMENT_NODE:
7828
 
#endif
7829
 
                case XML_HTML_DOCUMENT_NODE:
7830
 
                    if (cur != start)
7831
 
                        return(cur);
7832
 
                    return(xmlDocGetRootElement((xmlDocPtr) cur));
7833
 
                default:
7834
 
                    break;
7835
 
            }
7836
 
 
7837
 
next_sibling:
7838
 
            if ((cur == NULL) || (cur == contextNode))
7839
 
                return(NULL);
7840
 
            if (cur->next != NULL) {
7841
 
                cur = cur->next;
7842
 
            } else {
7843
 
                cur = cur->parent;
7844
 
                goto next_sibling;
7845
 
            }
7846
 
        }
7847
 
    }
7848
 
    return(NULL);
7849
 
}
7850
 
#endif
7851
 
 
7852
 
/**
7853
 
 * xmlXPathNextDescendant:
7854
 
 * @ctxt:  the XPath Parser context
7855
 
 * @cur:  the current node in the traversal
7856
 
 *
7857
 
 * Traversal function for the "descendant" direction
7858
 
 * the descendant axis contains the descendants of the context node in document
7859
 
 * order; a descendant is a child or a child of a child and so on.
7860
 
 *
7861
 
 * Returns the next element following that axis
7862
 
 */
7863
 
xmlNodePtr
7864
 
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7865
 
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7866
 
    if (cur == NULL) {
7867
 
        if (ctxt->context->node == NULL)
7868
 
            return(NULL);
7869
 
        if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7870
 
            (ctxt->context->node->type == XML_NAMESPACE_DECL))
7871
 
            return(NULL);
7872
 
 
7873
 
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7874
 
            return(ctxt->context->doc->children);
7875
 
        return(ctxt->context->node->children);
7876
 
    }
7877
 
 
7878
 
    if (cur->type == XML_NAMESPACE_DECL)
7879
 
        return(NULL);
7880
 
    if (cur->children != NULL) {
7881
 
        /*
7882
 
         * Do not descend on entities declarations
7883
 
         */
7884
 
        if (cur->children->type != XML_ENTITY_DECL) {
7885
 
            cur = cur->children;
7886
 
            /*
7887
 
             * Skip DTDs
7888
 
             */
7889
 
            if (cur->type != XML_DTD_NODE)
7890
 
                return(cur);
7891
 
        }
7892
 
    }
7893
 
 
7894
 
    if (cur == ctxt->context->node) return(NULL);
7895
 
 
7896
 
    while (cur->next != NULL) {
7897
 
        cur = cur->next;
7898
 
        if ((cur->type != XML_ENTITY_DECL) &&
7899
 
            (cur->type != XML_DTD_NODE))
7900
 
            return(cur);
7901
 
    }
7902
 
 
7903
 
    do {
7904
 
        cur = cur->parent;
7905
 
        if (cur == NULL) break;
7906
 
        if (cur == ctxt->context->node) return(NULL);
7907
 
        if (cur->next != NULL) {
7908
 
            cur = cur->next;
7909
 
            return(cur);
7910
 
        }
7911
 
    } while (cur != NULL);
7912
 
    return(cur);
7913
 
}
7914
 
 
7915
 
/**
7916
 
 * xmlXPathNextDescendantOrSelf:
7917
 
 * @ctxt:  the XPath Parser context
7918
 
 * @cur:  the current node in the traversal
7919
 
 *
7920
 
 * Traversal function for the "descendant-or-self" direction
7921
 
 * the descendant-or-self axis contains the context node and the descendants
7922
 
 * of the context node in document order; thus the context node is the first
7923
 
 * node on the axis, and the first child of the context node is the second node
7924
 
 * on the axis
7925
 
 *
7926
 
 * Returns the next element following that axis
7927
 
 */
7928
 
xmlNodePtr
7929
 
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7930
 
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7931
 
    if (cur == NULL) {
7932
 
        if (ctxt->context->node == NULL)
7933
 
            return(NULL);
7934
 
        if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7935
 
            (ctxt->context->node->type == XML_NAMESPACE_DECL))
7936
 
            return(NULL);
7937
 
        return(ctxt->context->node);
7938
 
    }
7939
 
 
7940
 
    return(xmlXPathNextDescendant(ctxt, cur));
7941
 
}
7942
 
 
7943
 
/**
7944
 
 * xmlXPathNextParent:
7945
 
 * @ctxt:  the XPath Parser context
7946
 
 * @cur:  the current node in the traversal
7947
 
 *
7948
 
 * Traversal function for the "parent" direction
7949
 
 * The parent axis contains the parent of the context node, if there is one.
7950
 
 *
7951
 
 * Returns the next element following that axis
7952
 
 */
7953
 
xmlNodePtr
7954
 
xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7955
 
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7956
 
    /*
7957
 
     * the parent of an attribute or namespace node is the element
7958
 
     * to which the attribute or namespace node is attached
7959
 
     * Namespace handling !!!
7960
 
     */
7961
 
    if (cur == NULL) {
7962
 
        if (ctxt->context->node == NULL) return(NULL);
7963
 
        switch (ctxt->context->node->type) {
7964
 
            case XML_ELEMENT_NODE:
7965
 
            case XML_TEXT_NODE:
7966
 
            case XML_CDATA_SECTION_NODE:
7967
 
            case XML_ENTITY_REF_NODE:
7968
 
            case XML_ENTITY_NODE:
7969
 
            case XML_PI_NODE:
7970
 
            case XML_COMMENT_NODE:
7971
 
            case XML_NOTATION_NODE:
7972
 
            case XML_DTD_NODE:
7973
 
            case XML_ELEMENT_DECL:
7974
 
            case XML_ATTRIBUTE_DECL:
7975
 
            case XML_XINCLUDE_START:
7976
 
            case XML_XINCLUDE_END:
7977
 
            case XML_ENTITY_DECL:
7978
 
                if (ctxt->context->node->parent == NULL)
7979
 
                    return((xmlNodePtr) ctxt->context->doc);
7980
 
                if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7981
 
                    ((ctxt->context->node->parent->name[0] == ' ') ||
7982
 
                     (xmlStrEqual(ctxt->context->node->parent->name,
7983
 
                                 BAD_CAST "fake node libxslt"))))
7984
 
                    return(NULL);
7985
 
                return(ctxt->context->node->parent);
7986
 
            case XML_ATTRIBUTE_NODE: {
7987
 
                xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7988
 
 
7989
 
                return(att->parent);
7990
 
            }
7991
 
            case XML_DOCUMENT_NODE:
7992
 
            case XML_DOCUMENT_TYPE_NODE:
7993
 
            case XML_DOCUMENT_FRAG_NODE:
7994
 
            case XML_HTML_DOCUMENT_NODE:
7995
 
#ifdef LIBXML_DOCB_ENABLED
7996
 
            case XML_DOCB_DOCUMENT_NODE:
7997
 
#endif
7998
 
                return(NULL);
7999
 
            case XML_NAMESPACE_DECL: {
8000
 
                xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8001
 
 
8002
 
                if ((ns->next != NULL) &&
8003
 
                    (ns->next->type != XML_NAMESPACE_DECL))
8004
 
                    return((xmlNodePtr) ns->next);
8005
 
                return(NULL);
8006
 
            }
8007
 
        }
8008
 
    }
8009
 
    return(NULL);
8010
 
}
8011
 
 
8012
 
/**
8013
 
 * xmlXPathNextAncestor:
8014
 
 * @ctxt:  the XPath Parser context
8015
 
 * @cur:  the current node in the traversal
8016
 
 *
8017
 
 * Traversal function for the "ancestor" direction
8018
 
 * the ancestor axis contains the ancestors of the context node; the ancestors
8019
 
 * of the context node consist of the parent of context node and the parent's
8020
 
 * parent and so on; the nodes are ordered in reverse document order; thus the
8021
 
 * parent is the first node on the axis, and the parent's parent is the second
8022
 
 * node on the axis
8023
 
 *
8024
 
 * Returns the next element following that axis
8025
 
 */
8026
 
xmlNodePtr
8027
 
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8028
 
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8029
 
    /*
8030
 
     * the parent of an attribute or namespace node is the element
8031
 
     * to which the attribute or namespace node is attached
8032
 
     * !!!!!!!!!!!!!
8033
 
     */
8034
 
    if (cur == NULL) {
8035
 
        if (ctxt->context->node == NULL) return(NULL);
8036
 
        switch (ctxt->context->node->type) {
8037
 
            case XML_ELEMENT_NODE:
8038
 
            case XML_TEXT_NODE:
8039
 
            case XML_CDATA_SECTION_NODE:
8040
 
            case XML_ENTITY_REF_NODE:
8041
 
            case XML_ENTITY_NODE:
8042
 
            case XML_PI_NODE:
8043
 
            case XML_COMMENT_NODE:
8044
 
            case XML_DTD_NODE:
8045
 
            case XML_ELEMENT_DECL:
8046
 
            case XML_ATTRIBUTE_DECL:
8047
 
            case XML_ENTITY_DECL:
8048
 
            case XML_NOTATION_NODE:
8049
 
            case XML_XINCLUDE_START:
8050
 
            case XML_XINCLUDE_END:
8051
 
                if (ctxt->context->node->parent == NULL)
8052
 
                    return((xmlNodePtr) ctxt->context->doc);
8053
 
                if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8054
 
                    ((ctxt->context->node->parent->name[0] == ' ') ||
8055
 
                     (xmlStrEqual(ctxt->context->node->parent->name,
8056
 
                                 BAD_CAST "fake node libxslt"))))
8057
 
                    return(NULL);
8058
 
                return(ctxt->context->node->parent);
8059
 
            case XML_ATTRIBUTE_NODE: {
8060
 
                xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8061
 
 
8062
 
                return(tmp->parent);
8063
 
            }
8064
 
            case XML_DOCUMENT_NODE:
8065
 
            case XML_DOCUMENT_TYPE_NODE:
8066
 
            case XML_DOCUMENT_FRAG_NODE:
8067
 
            case XML_HTML_DOCUMENT_NODE:
8068
 
#ifdef LIBXML_DOCB_ENABLED
8069
 
            case XML_DOCB_DOCUMENT_NODE:
8070
 
#endif
8071
 
                return(NULL);
8072
 
            case XML_NAMESPACE_DECL: {
8073
 
                xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8074
 
 
8075
 
                if ((ns->next != NULL) &&
8076
 
                    (ns->next->type != XML_NAMESPACE_DECL))
8077
 
                    return((xmlNodePtr) ns->next);
8078
 
                /* Bad, how did that namespace end up here ? */
8079
 
                return(NULL);
8080
 
            }
8081
 
        }
8082
 
        return(NULL);
8083
 
    }
8084
 
    if (cur == ctxt->context->doc->children)
8085
 
        return((xmlNodePtr) ctxt->context->doc);
8086
 
    if (cur == (xmlNodePtr) ctxt->context->doc)
8087
 
        return(NULL);
8088
 
    switch (cur->type) {
8089
 
        case XML_ELEMENT_NODE:
8090
 
        case XML_TEXT_NODE:
8091
 
        case XML_CDATA_SECTION_NODE:
8092
 
        case XML_ENTITY_REF_NODE:
8093
 
        case XML_ENTITY_NODE:
8094
 
        case XML_PI_NODE:
8095
 
        case XML_COMMENT_NODE:
8096
 
        case XML_NOTATION_NODE:
8097
 
        case XML_DTD_NODE:
8098
 
        case XML_ELEMENT_DECL:
8099
 
        case XML_ATTRIBUTE_DECL:
8100
 
        case XML_ENTITY_DECL:
8101
 
        case XML_XINCLUDE_START:
8102
 
        case XML_XINCLUDE_END:
8103
 
            if (cur->parent == NULL)
8104
 
                return(NULL);
8105
 
            if ((cur->parent->type == XML_ELEMENT_NODE) &&
8106
 
                ((cur->parent->name[0] == ' ') ||
8107
 
                 (xmlStrEqual(cur->parent->name,
8108
 
                              BAD_CAST "fake node libxslt"))))
8109
 
                return(NULL);
8110
 
            return(cur->parent);
8111
 
        case XML_ATTRIBUTE_NODE: {
8112
 
            xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8113
 
 
8114
 
            return(att->parent);
8115
 
        }
8116
 
        case XML_NAMESPACE_DECL: {
8117
 
            xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8118
 
 
8119
 
            if ((ns->next != NULL) &&
8120
 
                (ns->next->type != XML_NAMESPACE_DECL))
8121
 
                return((xmlNodePtr) ns->next);
8122
 
            /* Bad, how did that namespace end up here ? */
8123
 
            return(NULL);
8124
 
        }
8125
 
        case XML_DOCUMENT_NODE:
8126
 
        case XML_DOCUMENT_TYPE_NODE:
8127
 
        case XML_DOCUMENT_FRAG_NODE:
8128
 
        case XML_HTML_DOCUMENT_NODE:
8129
 
#ifdef LIBXML_DOCB_ENABLED
8130
 
        case XML_DOCB_DOCUMENT_NODE:
8131
 
#endif
8132
 
            return(NULL);
8133
 
    }
8134
 
    return(NULL);
8135
 
}
8136
 
 
8137
 
/**
8138
 
 * xmlXPathNextAncestorOrSelf:
8139
 
 * @ctxt:  the XPath Parser context
8140
 
 * @cur:  the current node in the traversal
8141
 
 *
8142
 
 * Traversal function for the "ancestor-or-self" direction
8143
 
 * he ancestor-or-self axis contains the context node and ancestors of
8144
 
 * the context node in reverse document order; thus the context node is
8145
 
 * the first node on the axis, and the context node's parent the second;
8146
 
 * parent here is defined the same as with the parent axis.
8147
 
 *
8148
 
 * Returns the next element following that axis
8149
 
 */
8150
 
xmlNodePtr
8151
 
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8152
 
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8153
 
    if (cur == NULL)
8154
 
        return(ctxt->context->node);
8155
 
    return(xmlXPathNextAncestor(ctxt, cur));
8156
 
}
8157
 
 
8158
 
/**
8159
 
 * xmlXPathNextFollowingSibling:
8160
 
 * @ctxt:  the XPath Parser context
8161
 
 * @cur:  the current node in the traversal
8162
 
 *
8163
 
 * Traversal function for the "following-sibling" direction
8164
 
 * The following-sibling axis contains the following siblings of the context
8165
 
 * node in document order.
8166
 
 *
8167
 
 * Returns the next element following that axis
8168
 
 */
8169
 
xmlNodePtr
8170
 
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8171
 
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8172
 
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8173
 
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
8174
 
        return(NULL);
8175
 
    if (cur == (xmlNodePtr) ctxt->context->doc)
8176
 
        return(NULL);
8177
 
    if (cur == NULL)
8178
 
        return(ctxt->context->node->next);
8179
 
    return(cur->next);
8180
 
}
8181
 
 
8182
 
/**
8183
 
 * xmlXPathNextPrecedingSibling:
8184
 
 * @ctxt:  the XPath Parser context
8185
 
 * @cur:  the current node in the traversal
8186
 
 *
8187
 
 * Traversal function for the "preceding-sibling" direction
8188
 
 * The preceding-sibling axis contains the preceding siblings of the context
8189
 
 * node in reverse document order; the first preceding sibling is first on the
8190
 
 * axis; the sibling preceding that node is the second on the axis and so on.
8191
 
 *
8192
 
 * Returns the next element following that axis
8193
 
 */
8194
 
xmlNodePtr
8195
 
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8196
 
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8197
 
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8198
 
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
8199
 
        return(NULL);
8200
 
    if (cur == (xmlNodePtr) ctxt->context->doc)
8201
 
        return(NULL);
8202
 
    if (cur == NULL)
8203
 
        return(ctxt->context->node->prev);
8204
 
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8205
 
        cur = cur->prev;
8206
 
        if (cur == NULL)
8207
 
            return(ctxt->context->node->prev);
8208
 
    }
8209
 
    return(cur->prev);
8210
 
}
8211
 
 
8212
 
/**
8213
 
 * xmlXPathNextFollowing:
8214
 
 * @ctxt:  the XPath Parser context
8215
 
 * @cur:  the current node in the traversal
8216
 
 *
8217
 
 * Traversal function for the "following" direction
8218
 
 * The following axis contains all nodes in the same document as the context
8219
 
 * node that are after the context node in document order, excluding any
8220
 
 * descendants and excluding attribute nodes and namespace nodes; the nodes
8221
 
 * are ordered in document order
8222
 
 *
8223
 
 * Returns the next element following that axis
8224
 
 */
8225
 
xmlNodePtr
8226
 
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8227
 
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8228
 
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8229
 
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8230
 
        return(cur->children);
8231
 
 
8232
 
    if (cur == NULL) {
8233
 
        cur = ctxt->context->node;
8234
 
        if (cur->type == XML_NAMESPACE_DECL)
8235
 
            return(NULL);
8236
 
        if (cur->type == XML_ATTRIBUTE_NODE)
8237
 
            cur = cur->parent;
8238
 
    }
8239
 
    if (cur == NULL) return(NULL) ; /* ERROR */
8240
 
    if (cur->next != NULL) return(cur->next) ;
8241
 
    do {
8242
 
        cur = cur->parent;
8243
 
        if (cur == NULL) break;
8244
 
        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8245
 
        if (cur->next != NULL) return(cur->next);
8246
 
    } while (cur != NULL);
8247
 
    return(cur);
8248
 
}
8249
 
 
8250
 
/*
8251
 
 * xmlXPathIsAncestor:
8252
 
 * @ancestor:  the ancestor node
8253
 
 * @node:  the current node
8254
 
 *
8255
 
 * Check that @ancestor is a @node's ancestor
8256
 
 *
8257
 
 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8258
 
 */
8259
 
static int
8260
 
xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8261
 
    if ((ancestor == NULL) || (node == NULL)) return(0);
8262
 
    if (node->type == XML_NAMESPACE_DECL)
8263
 
        return(0);
8264
 
    if (ancestor->type == XML_NAMESPACE_DECL)
8265
 
        return(0);
8266
 
    /* nodes need to be in the same document */
8267
 
    if (ancestor->doc != node->doc) return(0);
8268
 
    /* avoid searching if ancestor or node is the root node */
8269
 
    if (ancestor == (xmlNodePtr) node->doc) return(1);
8270
 
    if (node == (xmlNodePtr) ancestor->doc) return(0);
8271
 
    while (node->parent != NULL) {
8272
 
        if (node->parent == ancestor)
8273
 
            return(1);
8274
 
        node = node->parent;
8275
 
    }
8276
 
    return(0);
8277
 
}
8278
 
 
8279
 
/**
8280
 
 * xmlXPathNextPreceding:
8281
 
 * @ctxt:  the XPath Parser context
8282
 
 * @cur:  the current node in the traversal
8283
 
 *
8284
 
 * Traversal function for the "preceding" direction
8285
 
 * the preceding axis contains all nodes in the same document as the context
8286
 
 * node that are before the context node in document order, excluding any
8287
 
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8288
 
 * ordered in reverse document order
8289
 
 *
8290
 
 * Returns the next element following that axis
8291
 
 */
8292
 
xmlNodePtr
8293
 
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8294
 
{
8295
 
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8296
 
    if (cur == NULL) {
8297
 
        cur = ctxt->context->node;
8298
 
        if (cur->type == XML_NAMESPACE_DECL)
8299
 
            return(NULL);
8300
 
        if (cur->type == XML_ATTRIBUTE_NODE)
8301
 
            return(cur->parent);
8302
 
    }
8303
 
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8304
 
        return (NULL);
8305
 
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8306
 
        cur = cur->prev;
8307
 
    do {
8308
 
        if (cur->prev != NULL) {
8309
 
            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8310
 
            return (cur);
8311
 
        }
8312
 
 
8313
 
        cur = cur->parent;
8314
 
        if (cur == NULL)
8315
 
            return (NULL);
8316
 
        if (cur == ctxt->context->doc->children)
8317
 
            return (NULL);
8318
 
    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8319
 
    return (cur);
8320
 
}
8321
 
 
8322
 
/**
8323
 
 * xmlXPathNextPrecedingInternal:
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
 
 * This is a faster implementation but internal only since it requires a
8333
 
 * state kept in the parser context: ctxt->ancestor.
8334
 
 *
8335
 
 * Returns the next element following that axis
8336
 
 */
8337
 
static xmlNodePtr
8338
 
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8339
 
                              xmlNodePtr cur)
8340
 
{
8341
 
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8342
 
    if (cur == NULL) {
8343
 
        cur = ctxt->context->node;
8344
 
        if (cur == NULL)
8345
 
            return (NULL);
8346
 
        if (cur->type == XML_NAMESPACE_DECL)
8347
 
            return (NULL);
8348
 
        ctxt->ancestor = cur->parent;
8349
 
    }
8350
 
    if (cur->type == XML_NAMESPACE_DECL)
8351
 
        return(NULL);
8352
 
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8353
 
        cur = cur->prev;
8354
 
    while (cur->prev == NULL) {
8355
 
        cur = cur->parent;
8356
 
        if (cur == NULL)
8357
 
            return (NULL);
8358
 
        if (cur == ctxt->context->doc->children)
8359
 
            return (NULL);
8360
 
        if (cur != ctxt->ancestor)
8361
 
            return (cur);
8362
 
        ctxt->ancestor = cur->parent;
8363
 
    }
8364
 
    cur = cur->prev;
8365
 
    while (cur->last != NULL)
8366
 
        cur = cur->last;
8367
 
    return (cur);
8368
 
}
8369
 
 
8370
 
/**
8371
 
 * xmlXPathNextNamespace:
8372
 
 * @ctxt:  the XPath Parser context
8373
 
 * @cur:  the current attribute in the traversal
8374
 
 *
8375
 
 * Traversal function for the "namespace" direction
8376
 
 * the namespace axis contains the namespace nodes of the context node;
8377
 
 * the order of nodes on this axis is implementation-defined; the axis will
8378
 
 * be empty unless the context node is an element
8379
 
 *
8380
 
 * We keep the XML namespace node at the end of the list.
8381
 
 *
8382
 
 * Returns the next element following that axis
8383
 
 */
8384
 
xmlNodePtr
8385
 
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8386
 
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8387
 
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8388
 
    if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
8389
 
        if (ctxt->context->tmpNsList != NULL)
8390
 
            xmlFree(ctxt->context->tmpNsList);
8391
 
        ctxt->context->tmpNsList =
8392
 
            xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8393
 
        ctxt->context->tmpNsNr = 0;
8394
 
        if (ctxt->context->tmpNsList != NULL) {
8395
 
            while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8396
 
                ctxt->context->tmpNsNr++;
8397
 
            }
8398
 
        }
8399
 
        return((xmlNodePtr) xmlXPathXMLNamespace);
8400
 
    }
8401
 
    if (ctxt->context->tmpNsNr > 0) {
8402
 
        return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8403
 
    } else {
8404
 
        if (ctxt->context->tmpNsList != NULL)
8405
 
            xmlFree(ctxt->context->tmpNsList);
8406
 
        ctxt->context->tmpNsList = NULL;
8407
 
        return(NULL);
8408
 
    }
8409
 
}
8410
 
 
8411
 
/**
8412
 
 * xmlXPathNextAttribute:
8413
 
 * @ctxt:  the XPath Parser context
8414
 
 * @cur:  the current attribute in the traversal
8415
 
 *
8416
 
 * Traversal function for the "attribute" direction
8417
 
 * TODO: support DTD inherited default attributes
8418
 
 *
8419
 
 * Returns the next element following that axis
8420
 
 */
8421
 
xmlNodePtr
8422
 
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8423
 
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8424
 
    if (ctxt->context->node == NULL)
8425
 
        return(NULL);
8426
 
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
8427
 
        return(NULL);
8428
 
    if (cur == NULL) {
8429
 
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8430
 
            return(NULL);
8431
 
        return((xmlNodePtr)ctxt->context->node->properties);
8432
 
    }
8433
 
    return((xmlNodePtr)cur->next);
8434
 
}
8435
 
 
8436
 
/************************************************************************
8437
 
 *                                                                      *
8438
 
 *              NodeTest Functions                                      *
8439
 
 *                                                                      *
8440
 
 ************************************************************************/
8441
 
 
8442
 
#define IS_FUNCTION                     200
8443
 
 
8444
 
 
8445
 
/************************************************************************
8446
 
 *                                                                      *
8447
 
 *              Implicit tree core function library                     *
8448
 
 *                                                                      *
8449
 
 ************************************************************************/
8450
 
 
8451
 
/**
8452
 
 * xmlXPathRoot:
8453
 
 * @ctxt:  the XPath Parser context
8454
 
 *
8455
 
 * Initialize the context to the root of the document
8456
 
 */
8457
 
void
8458
 
xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8459
 
    if ((ctxt == NULL) || (ctxt->context == NULL))
8460
 
        return;
8461
 
    ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8462
 
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8463
 
        ctxt->context->node));
8464
 
}
8465
 
 
8466
 
/************************************************************************
8467
 
 *                                                                      *
8468
 
 *              The explicit core function library                      *
8469
 
 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8470
 
 *                                                                      *
8471
 
 ************************************************************************/
8472
 
 
8473
 
 
8474
 
/**
8475
 
 * xmlXPathLastFunction:
8476
 
 * @ctxt:  the XPath Parser context
8477
 
 * @nargs:  the number of arguments
8478
 
 *
8479
 
 * Implement the last() XPath function
8480
 
 *    number last()
8481
 
 * The last function returns the number of nodes in the context node list.
8482
 
 */
8483
 
void
8484
 
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8485
 
    CHECK_ARITY(0);
8486
 
    if (ctxt->context->contextSize >= 0) {
8487
 
        valuePush(ctxt,
8488
 
            xmlXPathCacheNewFloat(ctxt->context,
8489
 
                (double) ctxt->context->contextSize));
8490
 
#ifdef DEBUG_EXPR
8491
 
        xmlGenericError(xmlGenericErrorContext,
8492
 
                "last() : %d\n", ctxt->context->contextSize);
8493
 
#endif
8494
 
    } else {
8495
 
        XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8496
 
    }
8497
 
}
8498
 
 
8499
 
/**
8500
 
 * xmlXPathPositionFunction:
8501
 
 * @ctxt:  the XPath Parser context
8502
 
 * @nargs:  the number of arguments
8503
 
 *
8504
 
 * Implement the position() XPath function
8505
 
 *    number position()
8506
 
 * The position function returns the position of the context node in the
8507
 
 * context node list. The first position is 1, and so the last position
8508
 
 * will be equal to last().
8509
 
 */
8510
 
void
8511
 
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8512
 
    CHECK_ARITY(0);
8513
 
    if (ctxt->context->proximityPosition >= 0) {
8514
 
        valuePush(ctxt,
8515
 
              xmlXPathCacheNewFloat(ctxt->context,
8516
 
                (double) ctxt->context->proximityPosition));
8517
 
#ifdef DEBUG_EXPR
8518
 
        xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8519
 
                ctxt->context->proximityPosition);
8520
 
#endif
8521
 
    } else {
8522
 
        XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8523
 
    }
8524
 
}
8525
 
 
8526
 
/**
8527
 
 * xmlXPathCountFunction:
8528
 
 * @ctxt:  the XPath Parser context
8529
 
 * @nargs:  the number of arguments
8530
 
 *
8531
 
 * Implement the count() XPath function
8532
 
 *    number count(node-set)
8533
 
 */
8534
 
void
8535
 
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8536
 
    xmlXPathObjectPtr cur;
8537
 
 
8538
 
    CHECK_ARITY(1);
8539
 
    if ((ctxt->value == NULL) ||
8540
 
        ((ctxt->value->type != XPATH_NODESET) &&
8541
 
         (ctxt->value->type != XPATH_XSLT_TREE)))
8542
 
        XP_ERROR(XPATH_INVALID_TYPE);
8543
 
    cur = valuePop(ctxt);
8544
 
 
8545
 
    if ((cur == NULL) || (cur->nodesetval == NULL))
8546
 
        valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8547
 
    else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8548
 
        valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8549
 
            (double) cur->nodesetval->nodeNr));
8550
 
    } else {
8551
 
        if ((cur->nodesetval->nodeNr != 1) ||
8552
 
            (cur->nodesetval->nodeTab == NULL)) {
8553
 
            valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8554
 
        } else {
8555
 
            xmlNodePtr tmp;
8556
 
            int i = 0;
8557
 
 
8558
 
            tmp = cur->nodesetval->nodeTab[0];
8559
 
            if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
8560
 
                tmp = tmp->children;
8561
 
                while (tmp != NULL) {
8562
 
                    tmp = tmp->next;
8563
 
                    i++;
8564
 
                }
8565
 
            }
8566
 
            valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8567
 
        }
8568
 
    }
8569
 
    xmlXPathReleaseObject(ctxt->context, cur);
8570
 
}
8571
 
 
8572
 
/**
8573
 
 * xmlXPathGetElementsByIds:
8574
 
 * @doc:  the document
8575
 
 * @ids:  a whitespace separated list of IDs
8576
 
 *
8577
 
 * Selects elements by their unique ID.
8578
 
 *
8579
 
 * Returns a node-set of selected elements.
8580
 
 */
8581
 
static xmlNodeSetPtr
8582
 
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8583
 
    xmlNodeSetPtr ret;
8584
 
    const xmlChar *cur = ids;
8585
 
    xmlChar *ID;
8586
 
    xmlAttrPtr attr;
8587
 
    xmlNodePtr elem = NULL;
8588
 
 
8589
 
    if (ids == NULL) return(NULL);
8590
 
 
8591
 
    ret = xmlXPathNodeSetCreate(NULL);
8592
 
    if (ret == NULL)
8593
 
        return(ret);
8594
 
 
8595
 
    while (IS_BLANK_CH(*cur)) cur++;
8596
 
    while (*cur != 0) {
8597
 
        while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8598
 
            cur++;
8599
 
 
8600
 
        ID = xmlStrndup(ids, cur - ids);
8601
 
        if (ID != NULL) {
8602
 
            /*
8603
 
             * We used to check the fact that the value passed
8604
 
             * was an NCName, but this generated much troubles for
8605
 
             * me and Aleksey Sanin, people blatantly violated that
8606
 
             * constaint, like Visa3D spec.
8607
 
             * if (xmlValidateNCName(ID, 1) == 0)
8608
 
             */
8609
 
            attr = xmlGetID(doc, ID);
8610
 
            if (attr != NULL) {
8611
 
                if (attr->type == XML_ATTRIBUTE_NODE)
8612
 
                    elem = attr->parent;
8613
 
                else if (attr->type == XML_ELEMENT_NODE)
8614
 
                    elem = (xmlNodePtr) attr;
8615
 
                else
8616
 
                    elem = NULL;
8617
 
                if (elem != NULL)
8618
 
                    xmlXPathNodeSetAdd(ret, elem);
8619
 
            }
8620
 
            xmlFree(ID);
8621
 
        }
8622
 
 
8623
 
        while (IS_BLANK_CH(*cur)) cur++;
8624
 
        ids = cur;
8625
 
    }
8626
 
    return(ret);
8627
 
}
8628
 
 
8629
 
/**
8630
 
 * xmlXPathIdFunction:
8631
 
 * @ctxt:  the XPath Parser context
8632
 
 * @nargs:  the number of arguments
8633
 
 *
8634
 
 * Implement the id() XPath function
8635
 
 *    node-set id(object)
8636
 
 * The id function selects elements by their unique ID
8637
 
 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8638
 
 * then the result is the union of the result of applying id to the
8639
 
 * string value of each of the nodes in the argument node-set. When the
8640
 
 * argument to id is of any other type, the argument is converted to a
8641
 
 * string as if by a call to the string function; the string is split
8642
 
 * into a whitespace-separated list of tokens (whitespace is any sequence
8643
 
 * of characters matching the production S); the result is a node-set
8644
 
 * containing the elements in the same document as the context node that
8645
 
 * have a unique ID equal to any of the tokens in the list.
8646
 
 */
8647
 
void
8648
 
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8649
 
    xmlChar *tokens;
8650
 
    xmlNodeSetPtr ret;
8651
 
    xmlXPathObjectPtr obj;
8652
 
 
8653
 
    CHECK_ARITY(1);
8654
 
    obj = valuePop(ctxt);
8655
 
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8656
 
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8657
 
        xmlNodeSetPtr ns;
8658
 
        int i;
8659
 
 
8660
 
        ret = xmlXPathNodeSetCreate(NULL);
8661
 
        /*
8662
 
         * FIXME -- in an out-of-memory condition this will behave badly.
8663
 
         * The solution is not clear -- we already popped an item from
8664
 
         * ctxt, so the object is in a corrupt state.
8665
 
         */
8666
 
 
8667
 
        if (obj->nodesetval != NULL) {
8668
 
            for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8669
 
                tokens =
8670
 
                    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8671
 
                ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8672
 
                ret = xmlXPathNodeSetMerge(ret, ns);
8673
 
                xmlXPathFreeNodeSet(ns);
8674
 
                if (tokens != NULL)
8675
 
                    xmlFree(tokens);
8676
 
            }
8677
 
        }
8678
 
        xmlXPathReleaseObject(ctxt->context, obj);
8679
 
        valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8680
 
        return;
8681
 
    }
8682
 
    obj = xmlXPathCacheConvertString(ctxt->context, obj);
8683
 
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8684
 
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8685
 
    xmlXPathReleaseObject(ctxt->context, obj);
8686
 
    return;
8687
 
}
8688
 
 
8689
 
/**
8690
 
 * xmlXPathLocalNameFunction:
8691
 
 * @ctxt:  the XPath Parser context
8692
 
 * @nargs:  the number of arguments
8693
 
 *
8694
 
 * Implement the local-name() XPath function
8695
 
 *    string local-name(node-set?)
8696
 
 * The local-name function returns a string containing the local part
8697
 
 * of the name of the node in the argument node-set that is first in
8698
 
 * document order. If the node-set is empty or the first node has no
8699
 
 * name, an empty string is returned. If the argument is omitted it
8700
 
 * defaults to the context node.
8701
 
 */
8702
 
void
8703
 
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8704
 
    xmlXPathObjectPtr cur;
8705
 
 
8706
 
    if (ctxt == NULL) return;
8707
 
 
8708
 
    if (nargs == 0) {
8709
 
        valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8710
 
            ctxt->context->node));
8711
 
        nargs = 1;
8712
 
    }
8713
 
 
8714
 
    CHECK_ARITY(1);
8715
 
    if ((ctxt->value == NULL) ||
8716
 
        ((ctxt->value->type != XPATH_NODESET) &&
8717
 
         (ctxt->value->type != XPATH_XSLT_TREE)))
8718
 
        XP_ERROR(XPATH_INVALID_TYPE);
8719
 
    cur = valuePop(ctxt);
8720
 
 
8721
 
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8722
 
        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8723
 
    } else {
8724
 
        int i = 0; /* Should be first in document order !!!!! */
8725
 
        switch (cur->nodesetval->nodeTab[i]->type) {
8726
 
        case XML_ELEMENT_NODE:
8727
 
        case XML_ATTRIBUTE_NODE:
8728
 
        case XML_PI_NODE:
8729
 
            if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8730
 
                valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8731
 
            else
8732
 
                valuePush(ctxt,
8733
 
                      xmlXPathCacheNewString(ctxt->context,
8734
 
                        cur->nodesetval->nodeTab[i]->name));
8735
 
            break;
8736
 
        case XML_NAMESPACE_DECL:
8737
 
            valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8738
 
                        ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8739
 
            break;
8740
 
        default:
8741
 
            valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8742
 
        }
8743
 
    }
8744
 
    xmlXPathReleaseObject(ctxt->context, cur);
8745
 
}
8746
 
 
8747
 
/**
8748
 
 * xmlXPathNamespaceURIFunction:
8749
 
 * @ctxt:  the XPath Parser context
8750
 
 * @nargs:  the number of arguments
8751
 
 *
8752
 
 * Implement the namespace-uri() XPath function
8753
 
 *    string namespace-uri(node-set?)
8754
 
 * The namespace-uri function returns a string containing the
8755
 
 * namespace URI of the expanded name of the node in the argument
8756
 
 * node-set that is first in document order. If the node-set is empty,
8757
 
 * the first node has no name, or the expanded name has no namespace
8758
 
 * URI, an empty string is returned. If the argument is omitted it
8759
 
 * defaults to the context node.
8760
 
 */
8761
 
void
8762
 
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8763
 
    xmlXPathObjectPtr cur;
8764
 
 
8765
 
    if (ctxt == NULL) return;
8766
 
 
8767
 
    if (nargs == 0) {
8768
 
        valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8769
 
            ctxt->context->node));
8770
 
        nargs = 1;
8771
 
    }
8772
 
    CHECK_ARITY(1);
8773
 
    if ((ctxt->value == NULL) ||
8774
 
        ((ctxt->value->type != XPATH_NODESET) &&
8775
 
         (ctxt->value->type != XPATH_XSLT_TREE)))
8776
 
        XP_ERROR(XPATH_INVALID_TYPE);
8777
 
    cur = valuePop(ctxt);
8778
 
 
8779
 
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8780
 
        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8781
 
    } else {
8782
 
        int i = 0; /* Should be first in document order !!!!! */
8783
 
        switch (cur->nodesetval->nodeTab[i]->type) {
8784
 
        case XML_ELEMENT_NODE:
8785
 
        case XML_ATTRIBUTE_NODE:
8786
 
            if (cur->nodesetval->nodeTab[i]->ns == NULL)
8787
 
                valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8788
 
            else
8789
 
                valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8790
 
                          cur->nodesetval->nodeTab[i]->ns->href));
8791
 
            break;
8792
 
        default:
8793
 
            valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8794
 
        }
8795
 
    }
8796
 
    xmlXPathReleaseObject(ctxt->context, cur);
8797
 
}
8798
 
 
8799
 
/**
8800
 
 * xmlXPathNameFunction:
8801
 
 * @ctxt:  the XPath Parser context
8802
 
 * @nargs:  the number of arguments
8803
 
 *
8804
 
 * Implement the name() XPath function
8805
 
 *    string name(node-set?)
8806
 
 * The name function returns a string containing a QName representing
8807
 
 * the name of the node in the argument node-set that is first in document
8808
 
 * order. The QName must represent the name with respect to the namespace
8809
 
 * declarations in effect on the node whose name is being represented.
8810
 
 * Typically, this will be the form in which the name occurred in the XML
8811
 
 * source. This need not be the case if there are namespace declarations
8812
 
 * in effect on the node that associate multiple prefixes with the same
8813
 
 * namespace. However, an implementation may include information about
8814
 
 * the original prefix in its representation of nodes; in this case, an
8815
 
 * implementation can ensure that the returned string is always the same
8816
 
 * as the QName used in the XML source. If the argument it omitted it
8817
 
 * defaults to the context node.
8818
 
 * Libxml keep the original prefix so the "real qualified name" used is
8819
 
 * returned.
8820
 
 */
8821
 
static void
8822
 
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8823
 
{
8824
 
    xmlXPathObjectPtr cur;
8825
 
 
8826
 
    if (nargs == 0) {
8827
 
        valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8828
 
            ctxt->context->node));
8829
 
        nargs = 1;
8830
 
    }
8831
 
 
8832
 
    CHECK_ARITY(1);
8833
 
    if ((ctxt->value == NULL) ||
8834
 
        ((ctxt->value->type != XPATH_NODESET) &&
8835
 
         (ctxt->value->type != XPATH_XSLT_TREE)))
8836
 
        XP_ERROR(XPATH_INVALID_TYPE);
8837
 
    cur = valuePop(ctxt);
8838
 
 
8839
 
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8840
 
        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8841
 
    } else {
8842
 
        int i = 0;              /* Should be first in document order !!!!! */
8843
 
 
8844
 
        switch (cur->nodesetval->nodeTab[i]->type) {
8845
 
            case XML_ELEMENT_NODE:
8846
 
            case XML_ATTRIBUTE_NODE:
8847
 
                if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8848
 
                    valuePush(ctxt,
8849
 
                        xmlXPathCacheNewCString(ctxt->context, ""));
8850
 
                else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8851
 
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8852
 
                    valuePush(ctxt,
8853
 
                        xmlXPathCacheNewString(ctxt->context,
8854
 
                            cur->nodesetval->nodeTab[i]->name));
8855
 
                } else {
8856
 
                    xmlChar *fullname;
8857
 
 
8858
 
                    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8859
 
                                     cur->nodesetval->nodeTab[i]->ns->prefix,
8860
 
                                     NULL, 0);
8861
 
                    if (fullname == cur->nodesetval->nodeTab[i]->name)
8862
 
                        fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8863
 
                    if (fullname == NULL) {
8864
 
                        XP_ERROR(XPATH_MEMORY_ERROR);
8865
 
                    }
8866
 
                    valuePush(ctxt, xmlXPathCacheWrapString(
8867
 
                        ctxt->context, fullname));
8868
 
                }
8869
 
                break;
8870
 
            default:
8871
 
                valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8872
 
                    cur->nodesetval->nodeTab[i]));
8873
 
                xmlXPathLocalNameFunction(ctxt, 1);
8874
 
        }
8875
 
    }
8876
 
    xmlXPathReleaseObject(ctxt->context, cur);
8877
 
}
8878
 
 
8879
 
 
8880
 
/**
8881
 
 * xmlXPathStringFunction:
8882
 
 * @ctxt:  the XPath Parser context
8883
 
 * @nargs:  the number of arguments
8884
 
 *
8885
 
 * Implement the string() XPath function
8886
 
 *    string string(object?)
8887
 
 * The string function converts an object to a string as follows:
8888
 
 *    - A node-set is converted to a string by returning the value of
8889
 
 *      the node in the node-set that is first in document order.
8890
 
 *      If the node-set is empty, an empty string is returned.
8891
 
 *    - A number is converted to a string as follows
8892
 
 *      + NaN is converted to the string NaN
8893
 
 *      + positive zero is converted to the string 0
8894
 
 *      + negative zero is converted to the string 0
8895
 
 *      + positive infinity is converted to the string Infinity
8896
 
 *      + negative infinity is converted to the string -Infinity
8897
 
 *      + if the number is an integer, the number is represented in
8898
 
 *        decimal form as a Number with no decimal point and no leading
8899
 
 *        zeros, preceded by a minus sign (-) if the number is negative
8900
 
 *      + otherwise, the number is represented in decimal form as a
8901
 
 *        Number including a decimal point with at least one digit
8902
 
 *        before the decimal point and at least one digit after the
8903
 
 *        decimal point, preceded by a minus sign (-) if the number
8904
 
 *        is negative; there must be no leading zeros before the decimal
8905
 
 *        point apart possibly from the one required digit immediately
8906
 
 *        before the decimal point; beyond the one required digit
8907
 
 *        after the decimal point there must be as many, but only as
8908
 
 *        many, more digits as are needed to uniquely distinguish the
8909
 
 *        number from all other IEEE 754 numeric values.
8910
 
 *    - The boolean false value is converted to the string false.
8911
 
 *      The boolean true value is converted to the string true.
8912
 
 *
8913
 
 * If the argument is omitted, it defaults to a node-set with the
8914
 
 * context node as its only member.
8915
 
 */
8916
 
void
8917
 
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8918
 
    xmlXPathObjectPtr cur;
8919
 
 
8920
 
    if (ctxt == NULL) return;
8921
 
    if (nargs == 0) {
8922
 
    valuePush(ctxt,
8923
 
        xmlXPathCacheWrapString(ctxt->context,
8924
 
            xmlXPathCastNodeToString(ctxt->context->node)));
8925
 
        return;
8926
 
    }
8927
 
 
8928
 
    CHECK_ARITY(1);
8929
 
    cur = valuePop(ctxt);
8930
 
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8931
 
    valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8932
 
}
8933
 
 
8934
 
/**
8935
 
 * xmlXPathStringLengthFunction:
8936
 
 * @ctxt:  the XPath Parser context
8937
 
 * @nargs:  the number of arguments
8938
 
 *
8939
 
 * Implement the string-length() XPath function
8940
 
 *    number string-length(string?)
8941
 
 * The string-length returns the number of characters in the string
8942
 
 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8943
 
 * the context node converted to a string, in other words the value
8944
 
 * of the context node.
8945
 
 */
8946
 
void
8947
 
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8948
 
    xmlXPathObjectPtr cur;
8949
 
 
8950
 
    if (nargs == 0) {
8951
 
        if ((ctxt == NULL) || (ctxt->context == NULL))
8952
 
            return;
8953
 
        if (ctxt->context->node == NULL) {
8954
 
            valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8955
 
        } else {
8956
 
            xmlChar *content;
8957
 
 
8958
 
            content = xmlXPathCastNodeToString(ctxt->context->node);
8959
 
            valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8960
 
                xmlUTF8Strlen(content)));
8961
 
            xmlFree(content);
8962
 
        }
8963
 
        return;
8964
 
    }
8965
 
    CHECK_ARITY(1);
8966
 
    CAST_TO_STRING;
8967
 
    CHECK_TYPE(XPATH_STRING);
8968
 
    cur = valuePop(ctxt);
8969
 
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8970
 
        xmlUTF8Strlen(cur->stringval)));
8971
 
    xmlXPathReleaseObject(ctxt->context, cur);
8972
 
}
8973
 
 
8974
 
/**
8975
 
 * xmlXPathConcatFunction:
8976
 
 * @ctxt:  the XPath Parser context
8977
 
 * @nargs:  the number of arguments
8978
 
 *
8979
 
 * Implement the concat() XPath function
8980
 
 *    string concat(string, string, string*)
8981
 
 * The concat function returns the concatenation of its arguments.
8982
 
 */
8983
 
void
8984
 
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8985
 
    xmlXPathObjectPtr cur, newobj;
8986
 
    xmlChar *tmp;
8987
 
 
8988
 
    if (ctxt == NULL) return;
8989
 
    if (nargs < 2) {
8990
 
        CHECK_ARITY(2);
8991
 
    }
8992
 
 
8993
 
    CAST_TO_STRING;
8994
 
    cur = valuePop(ctxt);
8995
 
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8996
 
        xmlXPathReleaseObject(ctxt->context, cur);
8997
 
        return;
8998
 
    }
8999
 
    nargs--;
9000
 
 
9001
 
    while (nargs > 0) {
9002
 
        CAST_TO_STRING;
9003
 
        newobj = valuePop(ctxt);
9004
 
        if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
9005
 
            xmlXPathReleaseObject(ctxt->context, newobj);
9006
 
            xmlXPathReleaseObject(ctxt->context, cur);
9007
 
            XP_ERROR(XPATH_INVALID_TYPE);
9008
 
        }
9009
 
        tmp = xmlStrcat(newobj->stringval, cur->stringval);
9010
 
        newobj->stringval = cur->stringval;
9011
 
        cur->stringval = tmp;
9012
 
        xmlXPathReleaseObject(ctxt->context, newobj);
9013
 
        nargs--;
9014
 
    }
9015
 
    valuePush(ctxt, cur);
9016
 
}
9017
 
 
9018
 
/**
9019
 
 * xmlXPathContainsFunction:
9020
 
 * @ctxt:  the XPath Parser context
9021
 
 * @nargs:  the number of arguments
9022
 
 *
9023
 
 * Implement the contains() XPath function
9024
 
 *    boolean contains(string, string)
9025
 
 * The contains function returns true if the first argument string
9026
 
 * contains the second argument string, and otherwise returns false.
9027
 
 */
9028
 
void
9029
 
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9030
 
    xmlXPathObjectPtr hay, needle;
9031
 
 
9032
 
    CHECK_ARITY(2);
9033
 
    CAST_TO_STRING;
9034
 
    CHECK_TYPE(XPATH_STRING);
9035
 
    needle = valuePop(ctxt);
9036
 
    CAST_TO_STRING;
9037
 
    hay = valuePop(ctxt);
9038
 
 
9039
 
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9040
 
        xmlXPathReleaseObject(ctxt->context, hay);
9041
 
        xmlXPathReleaseObject(ctxt->context, needle);
9042
 
        XP_ERROR(XPATH_INVALID_TYPE);
9043
 
    }
9044
 
    if (xmlStrstr(hay->stringval, needle->stringval))
9045
 
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9046
 
    else
9047
 
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9048
 
    xmlXPathReleaseObject(ctxt->context, hay);
9049
 
    xmlXPathReleaseObject(ctxt->context, needle);
9050
 
}
9051
 
 
9052
 
/**
9053
 
 * xmlXPathStartsWithFunction:
9054
 
 * @ctxt:  the XPath Parser context
9055
 
 * @nargs:  the number of arguments
9056
 
 *
9057
 
 * Implement the starts-with() XPath function
9058
 
 *    boolean starts-with(string, string)
9059
 
 * The starts-with function returns true if the first argument string
9060
 
 * starts with the second argument string, and otherwise returns false.
9061
 
 */
9062
 
void
9063
 
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9064
 
    xmlXPathObjectPtr hay, needle;
9065
 
    int n;
9066
 
 
9067
 
    CHECK_ARITY(2);
9068
 
    CAST_TO_STRING;
9069
 
    CHECK_TYPE(XPATH_STRING);
9070
 
    needle = valuePop(ctxt);
9071
 
    CAST_TO_STRING;
9072
 
    hay = valuePop(ctxt);
9073
 
 
9074
 
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9075
 
        xmlXPathReleaseObject(ctxt->context, hay);
9076
 
        xmlXPathReleaseObject(ctxt->context, needle);
9077
 
        XP_ERROR(XPATH_INVALID_TYPE);
9078
 
    }
9079
 
    n = xmlStrlen(needle->stringval);
9080
 
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
9081
 
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9082
 
    else
9083
 
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9084
 
    xmlXPathReleaseObject(ctxt->context, hay);
9085
 
    xmlXPathReleaseObject(ctxt->context, needle);
9086
 
}
9087
 
 
9088
 
/**
9089
 
 * xmlXPathSubstringFunction:
9090
 
 * @ctxt:  the XPath Parser context
9091
 
 * @nargs:  the number of arguments
9092
 
 *
9093
 
 * Implement the substring() XPath function
9094
 
 *    string substring(string, number, number?)
9095
 
 * The substring function returns the substring of the first argument
9096
 
 * starting at the position specified in the second argument with
9097
 
 * length specified in the third argument. For example,
9098
 
 * substring("12345",2,3) returns "234". If the third argument is not
9099
 
 * specified, it returns the substring starting at the position specified
9100
 
 * in the second argument and continuing to the end of the string. For
9101
 
 * example, substring("12345",2) returns "2345".  More precisely, each
9102
 
 * character in the string (see [3.6 Strings]) is considered to have a
9103
 
 * numeric position: the position of the first character is 1, the position
9104
 
 * of the second character is 2 and so on. The returned substring contains
9105
 
 * those characters for which the position of the character is greater than
9106
 
 * or equal to the second argument and, if the third argument is specified,
9107
 
 * less than the sum of the second and third arguments; the comparisons
9108
 
 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9109
 
 *  - substring("12345", 1.5, 2.6) returns "234"
9110
 
 *  - substring("12345", 0, 3) returns "12"
9111
 
 *  - substring("12345", 0 div 0, 3) returns ""
9112
 
 *  - substring("12345", 1, 0 div 0) returns ""
9113
 
 *  - substring("12345", -42, 1 div 0) returns "12345"
9114
 
 *  - substring("12345", -1 div 0, 1 div 0) returns ""
9115
 
 */
9116
 
void
9117
 
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9118
 
    xmlXPathObjectPtr str, start, len;
9119
 
    double le=0, in;
9120
 
    int i, l, m;
9121
 
    xmlChar *ret;
9122
 
 
9123
 
    if (nargs < 2) {
9124
 
        CHECK_ARITY(2);
9125
 
    }
9126
 
    if (nargs > 3) {
9127
 
        CHECK_ARITY(3);
9128
 
    }
9129
 
    /*
9130
 
     * take care of possible last (position) argument
9131
 
    */
9132
 
    if (nargs == 3) {
9133
 
        CAST_TO_NUMBER;
9134
 
        CHECK_TYPE(XPATH_NUMBER);
9135
 
        len = valuePop(ctxt);
9136
 
        le = len->floatval;
9137
 
        xmlXPathReleaseObject(ctxt->context, len);
9138
 
    }
9139
 
 
9140
 
    CAST_TO_NUMBER;
9141
 
    CHECK_TYPE(XPATH_NUMBER);
9142
 
    start = valuePop(ctxt);
9143
 
    in = start->floatval;
9144
 
    xmlXPathReleaseObject(ctxt->context, start);
9145
 
    CAST_TO_STRING;
9146
 
    CHECK_TYPE(XPATH_STRING);
9147
 
    str = valuePop(ctxt);
9148
 
    m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9149
 
 
9150
 
    /*
9151
 
     * If last pos not present, calculate last position
9152
 
    */
9153
 
    if (nargs != 3) {
9154
 
        le = (double)m;
9155
 
        if (in < 1.0)
9156
 
            in = 1.0;
9157
 
    }
9158
 
 
9159
 
    /* Need to check for the special cases where either
9160
 
     * the index is NaN, the length is NaN, or both
9161
 
     * arguments are infinity (relying on Inf + -Inf = NaN)
9162
 
     */
9163
 
    if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9164
 
        /*
9165
 
         * To meet the requirements of the spec, the arguments
9166
 
         * must be converted to integer format before
9167
 
         * initial index calculations are done
9168
 
         *
9169
 
         * First we go to integer form, rounding up
9170
 
         * and checking for special cases
9171
 
         */
9172
 
        i = (int) in;
9173
 
        if (((double)i)+0.5 <= in) i++;
9174
 
 
9175
 
        if (xmlXPathIsInf(le) == 1) {
9176
 
            l = m;
9177
 
            if (i < 1)
9178
 
                i = 1;
9179
 
        }
9180
 
        else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9181
 
            l = 0;
9182
 
        else {
9183
 
            l = (int) le;
9184
 
            if (((double)l)+0.5 <= le) l++;
9185
 
        }
9186
 
 
9187
 
        /* Now we normalize inidices */
9188
 
        i -= 1;
9189
 
        l += i;
9190
 
        if (i < 0)
9191
 
            i = 0;
9192
 
        if (l > m)
9193
 
            l = m;
9194
 
 
9195
 
        /* number of chars to copy */
9196
 
        l -= i;
9197
 
 
9198
 
        ret = xmlUTF8Strsub(str->stringval, i, l);
9199
 
    }
9200
 
    else {
9201
 
        ret = NULL;
9202
 
    }
9203
 
    if (ret == NULL)
9204
 
        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9205
 
    else {
9206
 
        valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9207
 
        xmlFree(ret);
9208
 
    }
9209
 
    xmlXPathReleaseObject(ctxt->context, str);
9210
 
}
9211
 
 
9212
 
/**
9213
 
 * xmlXPathSubstringBeforeFunction:
9214
 
 * @ctxt:  the XPath Parser context
9215
 
 * @nargs:  the number of arguments
9216
 
 *
9217
 
 * Implement the substring-before() XPath function
9218
 
 *    string substring-before(string, string)
9219
 
 * The substring-before function returns the substring of the first
9220
 
 * argument string that precedes the first occurrence of the second
9221
 
 * argument string in the first argument string, or the empty string
9222
 
 * if the first argument string does not contain the second argument
9223
 
 * string. For example, substring-before("1999/04/01","/") returns 1999.
9224
 
 */
9225
 
void
9226
 
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9227
 
  xmlXPathObjectPtr str;
9228
 
  xmlXPathObjectPtr find;
9229
 
  xmlBufPtr target;
9230
 
  const xmlChar *point;
9231
 
  int offset;
9232
 
 
9233
 
  CHECK_ARITY(2);
9234
 
  CAST_TO_STRING;
9235
 
  find = valuePop(ctxt);
9236
 
  CAST_TO_STRING;
9237
 
  str = valuePop(ctxt);
9238
 
 
9239
 
  target = xmlBufCreate();
9240
 
  if (target) {
9241
 
    point = xmlStrstr(str->stringval, find->stringval);
9242
 
    if (point) {
9243
 
      offset = (int)(point - str->stringval);
9244
 
      xmlBufAdd(target, str->stringval, offset);
9245
 
    }
9246
 
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9247
 
        xmlBufContent(target)));
9248
 
    xmlBufFree(target);
9249
 
  }
9250
 
  xmlXPathReleaseObject(ctxt->context, str);
9251
 
  xmlXPathReleaseObject(ctxt->context, find);
9252
 
}
9253
 
 
9254
 
/**
9255
 
 * xmlXPathSubstringAfterFunction:
9256
 
 * @ctxt:  the XPath Parser context
9257
 
 * @nargs:  the number of arguments
9258
 
 *
9259
 
 * Implement the substring-after() XPath function
9260
 
 *    string substring-after(string, string)
9261
 
 * The substring-after function returns the substring of the first
9262
 
 * argument string that follows the first occurrence of the second
9263
 
 * argument string in the first argument string, or the empty stringi
9264
 
 * if the first argument string does not contain the second argument
9265
 
 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9266
 
 * and substring-after("1999/04/01","19") returns 99/04/01.
9267
 
 */
9268
 
void
9269
 
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9270
 
  xmlXPathObjectPtr str;
9271
 
  xmlXPathObjectPtr find;
9272
 
  xmlBufPtr target;
9273
 
  const xmlChar *point;
9274
 
  int offset;
9275
 
 
9276
 
  CHECK_ARITY(2);
9277
 
  CAST_TO_STRING;
9278
 
  find = valuePop(ctxt);
9279
 
  CAST_TO_STRING;
9280
 
  str = valuePop(ctxt);
9281
 
 
9282
 
  target = xmlBufCreate();
9283
 
  if (target) {
9284
 
    point = xmlStrstr(str->stringval, find->stringval);
9285
 
    if (point) {
9286
 
      offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9287
 
      xmlBufAdd(target, &str->stringval[offset],
9288
 
                   xmlStrlen(str->stringval) - offset);
9289
 
    }
9290
 
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9291
 
        xmlBufContent(target)));
9292
 
    xmlBufFree(target);
9293
 
  }
9294
 
  xmlXPathReleaseObject(ctxt->context, str);
9295
 
  xmlXPathReleaseObject(ctxt->context, find);
9296
 
}
9297
 
 
9298
 
/**
9299
 
 * xmlXPathNormalizeFunction:
9300
 
 * @ctxt:  the XPath Parser context
9301
 
 * @nargs:  the number of arguments
9302
 
 *
9303
 
 * Implement the normalize-space() XPath function
9304
 
 *    string normalize-space(string?)
9305
 
 * The normalize-space function returns the argument string with white
9306
 
 * space normalized by stripping leading and trailing whitespace
9307
 
 * and replacing sequences of whitespace characters by a single
9308
 
 * space. Whitespace characters are the same allowed by the S production
9309
 
 * in XML. If the argument is omitted, it defaults to the context
9310
 
 * node converted to a string, in other words the value of the context node.
9311
 
 */
9312
 
void
9313
 
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9314
 
  xmlXPathObjectPtr obj = NULL;
9315
 
  xmlChar *source = NULL;
9316
 
  xmlBufPtr target;
9317
 
  xmlChar blank;
9318
 
 
9319
 
  if (ctxt == NULL) return;
9320
 
  if (nargs == 0) {
9321
 
    /* Use current context node */
9322
 
      valuePush(ctxt,
9323
 
          xmlXPathCacheWrapString(ctxt->context,
9324
 
            xmlXPathCastNodeToString(ctxt->context->node)));
9325
 
    nargs = 1;
9326
 
  }
9327
 
 
9328
 
  CHECK_ARITY(1);
9329
 
  CAST_TO_STRING;
9330
 
  CHECK_TYPE(XPATH_STRING);
9331
 
  obj = valuePop(ctxt);
9332
 
  source = obj->stringval;
9333
 
 
9334
 
  target = xmlBufCreate();
9335
 
  if (target && source) {
9336
 
 
9337
 
    /* Skip leading whitespaces */
9338
 
    while (IS_BLANK_CH(*source))
9339
 
      source++;
9340
 
 
9341
 
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9342
 
    blank = 0;
9343
 
    while (*source) {
9344
 
      if (IS_BLANK_CH(*source)) {
9345
 
        blank = 0x20;
9346
 
      } else {
9347
 
        if (blank) {
9348
 
          xmlBufAdd(target, &blank, 1);
9349
 
          blank = 0;
9350
 
        }
9351
 
        xmlBufAdd(target, source, 1);
9352
 
      }
9353
 
      source++;
9354
 
    }
9355
 
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9356
 
        xmlBufContent(target)));
9357
 
    xmlBufFree(target);
9358
 
  }
9359
 
  xmlXPathReleaseObject(ctxt->context, obj);
9360
 
}
9361
 
 
9362
 
/**
9363
 
 * xmlXPathTranslateFunction:
9364
 
 * @ctxt:  the XPath Parser context
9365
 
 * @nargs:  the number of arguments
9366
 
 *
9367
 
 * Implement the translate() XPath function
9368
 
 *    string translate(string, string, string)
9369
 
 * The translate function returns the first argument string with
9370
 
 * occurrences of characters in the second argument string replaced
9371
 
 * by the character at the corresponding position in the third argument
9372
 
 * string. For example, translate("bar","abc","ABC") returns the string
9373
 
 * BAr. If there is a character in the second argument string with no
9374
 
 * character at a corresponding position in the third argument string
9375
 
 * (because the second argument string is longer than the third argument
9376
 
 * string), then occurrences of that character in the first argument
9377
 
 * string are removed. For example, translate("--aaa--","abc-","ABC")
9378
 
 * returns "AAA". If a character occurs more than once in second
9379
 
 * argument string, then the first occurrence determines the replacement
9380
 
 * character. If the third argument string is longer than the second
9381
 
 * argument string, then excess characters are ignored.
9382
 
 */
9383
 
void
9384
 
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9385
 
    xmlXPathObjectPtr str;
9386
 
    xmlXPathObjectPtr from;
9387
 
    xmlXPathObjectPtr to;
9388
 
    xmlBufPtr target;
9389
 
    int offset, max;
9390
 
    xmlChar ch;
9391
 
    const xmlChar *point;
9392
 
    xmlChar *cptr;
9393
 
 
9394
 
    CHECK_ARITY(3);
9395
 
 
9396
 
    CAST_TO_STRING;
9397
 
    to = valuePop(ctxt);
9398
 
    CAST_TO_STRING;
9399
 
    from = valuePop(ctxt);
9400
 
    CAST_TO_STRING;
9401
 
    str = valuePop(ctxt);
9402
 
 
9403
 
    target = xmlBufCreate();
9404
 
    if (target) {
9405
 
        max = xmlUTF8Strlen(to->stringval);
9406
 
        for (cptr = str->stringval; (ch=*cptr); ) {
9407
 
            offset = xmlUTF8Strloc(from->stringval, cptr);
9408
 
            if (offset >= 0) {
9409
 
                if (offset < max) {
9410
 
                    point = xmlUTF8Strpos(to->stringval, offset);
9411
 
                    if (point)
9412
 
                        xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9413
 
                }
9414
 
            } else
9415
 
                xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9416
 
 
9417
 
            /* Step to next character in input */
9418
 
            cptr++;
9419
 
            if ( ch & 0x80 ) {
9420
 
                /* if not simple ascii, verify proper format */
9421
 
                if ( (ch & 0xc0) != 0xc0 ) {
9422
 
                    xmlGenericError(xmlGenericErrorContext,
9423
 
                        "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9424
 
                    /* not asserting an XPath error is probably better */
9425
 
                    break;
9426
 
                }
9427
 
                /* then skip over remaining bytes for this char */
9428
 
                while ( (ch <<= 1) & 0x80 )
9429
 
                    if ( (*cptr++ & 0xc0) != 0x80 ) {
9430
 
                        xmlGenericError(xmlGenericErrorContext,
9431
 
                            "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9432
 
                        /* not asserting an XPath error is probably better */
9433
 
                        break;
9434
 
                    }
9435
 
                if (ch & 0x80) /* must have had error encountered */
9436
 
                    break;
9437
 
            }
9438
 
        }
9439
 
    }
9440
 
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9441
 
        xmlBufContent(target)));
9442
 
    xmlBufFree(target);
9443
 
    xmlXPathReleaseObject(ctxt->context, str);
9444
 
    xmlXPathReleaseObject(ctxt->context, from);
9445
 
    xmlXPathReleaseObject(ctxt->context, to);
9446
 
}
9447
 
 
9448
 
/**
9449
 
 * xmlXPathBooleanFunction:
9450
 
 * @ctxt:  the XPath Parser context
9451
 
 * @nargs:  the number of arguments
9452
 
 *
9453
 
 * Implement the boolean() XPath function
9454
 
 *    boolean boolean(object)
9455
 
 * The boolean function converts its argument to a boolean as follows:
9456
 
 *    - a number is true if and only if it is neither positive or
9457
 
 *      negative zero nor NaN
9458
 
 *    - a node-set is true if and only if it is non-empty
9459
 
 *    - a string is true if and only if its length is non-zero
9460
 
 */
9461
 
void
9462
 
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9463
 
    xmlXPathObjectPtr cur;
9464
 
 
9465
 
    CHECK_ARITY(1);
9466
 
    cur = valuePop(ctxt);
9467
 
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9468
 
    cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9469
 
    valuePush(ctxt, cur);
9470
 
}
9471
 
 
9472
 
/**
9473
 
 * xmlXPathNotFunction:
9474
 
 * @ctxt:  the XPath Parser context
9475
 
 * @nargs:  the number of arguments
9476
 
 *
9477
 
 * Implement the not() XPath function
9478
 
 *    boolean not(boolean)
9479
 
 * The not function returns true if its argument is false,
9480
 
 * and false otherwise.
9481
 
 */
9482
 
void
9483
 
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9484
 
    CHECK_ARITY(1);
9485
 
    CAST_TO_BOOLEAN;
9486
 
    CHECK_TYPE(XPATH_BOOLEAN);
9487
 
    ctxt->value->boolval = ! ctxt->value->boolval;
9488
 
}
9489
 
 
9490
 
/**
9491
 
 * xmlXPathTrueFunction:
9492
 
 * @ctxt:  the XPath Parser context
9493
 
 * @nargs:  the number of arguments
9494
 
 *
9495
 
 * Implement the true() XPath function
9496
 
 *    boolean true()
9497
 
 */
9498
 
void
9499
 
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9500
 
    CHECK_ARITY(0);
9501
 
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9502
 
}
9503
 
 
9504
 
/**
9505
 
 * xmlXPathFalseFunction:
9506
 
 * @ctxt:  the XPath Parser context
9507
 
 * @nargs:  the number of arguments
9508
 
 *
9509
 
 * Implement the false() XPath function
9510
 
 *    boolean false()
9511
 
 */
9512
 
void
9513
 
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9514
 
    CHECK_ARITY(0);
9515
 
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9516
 
}
9517
 
 
9518
 
/**
9519
 
 * xmlXPathLangFunction:
9520
 
 * @ctxt:  the XPath Parser context
9521
 
 * @nargs:  the number of arguments
9522
 
 *
9523
 
 * Implement the lang() XPath function
9524
 
 *    boolean lang(string)
9525
 
 * The lang function returns true or false depending on whether the
9526
 
 * language of the context node as specified by xml:lang attributes
9527
 
 * is the same as or is a sublanguage of the language specified by
9528
 
 * the argument string. The language of the context node is determined
9529
 
 * by the value of the xml:lang attribute on the context node, or, if
9530
 
 * the context node has no xml:lang attribute, by the value of the
9531
 
 * xml:lang attribute on the nearest ancestor of the context node that
9532
 
 * has an xml:lang attribute. If there is no such attribute, then lang
9533
 
 * returns false. If there is such an attribute, then lang returns
9534
 
 * true if the attribute value is equal to the argument ignoring case,
9535
 
 * or if there is some suffix starting with - such that the attribute
9536
 
 * value is equal to the argument ignoring that suffix of the attribute
9537
 
 * value and ignoring case.
9538
 
 */
9539
 
void
9540
 
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9541
 
    xmlXPathObjectPtr val = NULL;
9542
 
    const xmlChar *theLang = NULL;
9543
 
    const xmlChar *lang;
9544
 
    int ret = 0;
9545
 
    int i;
9546
 
 
9547
 
    CHECK_ARITY(1);
9548
 
    CAST_TO_STRING;
9549
 
    CHECK_TYPE(XPATH_STRING);
9550
 
    val = valuePop(ctxt);
9551
 
    lang = val->stringval;
9552
 
    theLang = xmlNodeGetLang(ctxt->context->node);
9553
 
    if ((theLang != NULL) && (lang != NULL)) {
9554
 
        for (i = 0;lang[i] != 0;i++)
9555
 
            if (toupper(lang[i]) != toupper(theLang[i]))
9556
 
                goto not_equal;
9557
 
        if ((theLang[i] == 0) || (theLang[i] == '-'))
9558
 
            ret = 1;
9559
 
    }
9560
 
not_equal:
9561
 
    if (theLang != NULL)
9562
 
        xmlFree((void *)theLang);
9563
 
 
9564
 
    xmlXPathReleaseObject(ctxt->context, val);
9565
 
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9566
 
}
9567
 
 
9568
 
/**
9569
 
 * xmlXPathNumberFunction:
9570
 
 * @ctxt:  the XPath Parser context
9571
 
 * @nargs:  the number of arguments
9572
 
 *
9573
 
 * Implement the number() XPath function
9574
 
 *    number number(object?)
9575
 
 */
9576
 
void
9577
 
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9578
 
    xmlXPathObjectPtr cur;
9579
 
    double res;
9580
 
 
9581
 
    if (ctxt == NULL) return;
9582
 
    if (nargs == 0) {
9583
 
        if (ctxt->context->node == NULL) {
9584
 
            valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9585
 
        } else {
9586
 
            xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9587
 
 
9588
 
            res = xmlXPathStringEvalNumber(content);
9589
 
            valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9590
 
            xmlFree(content);
9591
 
        }
9592
 
        return;
9593
 
    }
9594
 
 
9595
 
    CHECK_ARITY(1);
9596
 
    cur = valuePop(ctxt);
9597
 
    valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9598
 
}
9599
 
 
9600
 
/**
9601
 
 * xmlXPathSumFunction:
9602
 
 * @ctxt:  the XPath Parser context
9603
 
 * @nargs:  the number of arguments
9604
 
 *
9605
 
 * Implement the sum() XPath function
9606
 
 *    number sum(node-set)
9607
 
 * The sum function returns the sum of the values of the nodes in
9608
 
 * the argument node-set.
9609
 
 */
9610
 
void
9611
 
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9612
 
    xmlXPathObjectPtr cur;
9613
 
    int i;
9614
 
    double res = 0.0;
9615
 
 
9616
 
    CHECK_ARITY(1);
9617
 
    if ((ctxt->value == NULL) ||
9618
 
        ((ctxt->value->type != XPATH_NODESET) &&
9619
 
         (ctxt->value->type != XPATH_XSLT_TREE)))
9620
 
        XP_ERROR(XPATH_INVALID_TYPE);
9621
 
    cur = valuePop(ctxt);
9622
 
 
9623
 
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9624
 
        for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9625
 
            res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9626
 
        }
9627
 
    }
9628
 
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9629
 
    xmlXPathReleaseObject(ctxt->context, cur);
9630
 
}
9631
 
 
9632
 
/*
9633
 
 * To assure working code on multiple platforms, we want to only depend
9634
 
 * upon the characteristic truncation of converting a floating point value
9635
 
 * to an integer.  Unfortunately, because of the different storage sizes
9636
 
 * of our internal floating point value (double) and integer (int), we
9637
 
 * can't directly convert (see bug 301162).  This macro is a messy
9638
 
 * 'workaround'
9639
 
 */
9640
 
#define XTRUNC(f, v)            \
9641
 
    f = fmod((v), INT_MAX);     \
9642
 
    f = (v) - (f) + (double)((int)(f));
9643
 
 
9644
 
/**
9645
 
 * xmlXPathFloorFunction:
9646
 
 * @ctxt:  the XPath Parser context
9647
 
 * @nargs:  the number of arguments
9648
 
 *
9649
 
 * Implement the floor() XPath function
9650
 
 *    number floor(number)
9651
 
 * The floor function returns the largest (closest to positive infinity)
9652
 
 * number that is not greater than the argument and that is an integer.
9653
 
 */
9654
 
void
9655
 
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9656
 
    double f;
9657
 
 
9658
 
    CHECK_ARITY(1);
9659
 
    CAST_TO_NUMBER;
9660
 
    CHECK_TYPE(XPATH_NUMBER);
9661
 
 
9662
 
    XTRUNC(f, ctxt->value->floatval);
9663
 
    if (f != ctxt->value->floatval) {
9664
 
        if (ctxt->value->floatval > 0)
9665
 
            ctxt->value->floatval = f;
9666
 
        else
9667
 
            ctxt->value->floatval = f - 1;
9668
 
    }
9669
 
}
9670
 
 
9671
 
/**
9672
 
 * xmlXPathCeilingFunction:
9673
 
 * @ctxt:  the XPath Parser context
9674
 
 * @nargs:  the number of arguments
9675
 
 *
9676
 
 * Implement the ceiling() XPath function
9677
 
 *    number ceiling(number)
9678
 
 * The ceiling function returns the smallest (closest to negative infinity)
9679
 
 * number that is not less than the argument and that is an integer.
9680
 
 */
9681
 
void
9682
 
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9683
 
    double f;
9684
 
 
9685
 
    CHECK_ARITY(1);
9686
 
    CAST_TO_NUMBER;
9687
 
    CHECK_TYPE(XPATH_NUMBER);
9688
 
 
9689
 
#if 0
9690
 
    ctxt->value->floatval = ceil(ctxt->value->floatval);
9691
 
#else
9692
 
    XTRUNC(f, ctxt->value->floatval);
9693
 
    if (f != ctxt->value->floatval) {
9694
 
        if (ctxt->value->floatval > 0)
9695
 
            ctxt->value->floatval = f + 1;
9696
 
        else {
9697
 
            if (ctxt->value->floatval < 0 && f == 0)
9698
 
                ctxt->value->floatval = xmlXPathNZERO;
9699
 
            else
9700
 
                ctxt->value->floatval = f;
9701
 
        }
9702
 
 
9703
 
    }
9704
 
#endif
9705
 
}
9706
 
 
9707
 
/**
9708
 
 * xmlXPathRoundFunction:
9709
 
 * @ctxt:  the XPath Parser context
9710
 
 * @nargs:  the number of arguments
9711
 
 *
9712
 
 * Implement the round() XPath function
9713
 
 *    number round(number)
9714
 
 * The round function returns the number that is closest to the
9715
 
 * argument and that is an integer. If there are two such numbers,
9716
 
 * then the one that is even is returned.
9717
 
 */
9718
 
void
9719
 
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9720
 
    double f;
9721
 
 
9722
 
    CHECK_ARITY(1);
9723
 
    CAST_TO_NUMBER;
9724
 
    CHECK_TYPE(XPATH_NUMBER);
9725
 
 
9726
 
    if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9727
 
        (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9728
 
        (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
9729
 
        (ctxt->value->floatval == 0.0))
9730
 
        return;
9731
 
 
9732
 
    XTRUNC(f, ctxt->value->floatval);
9733
 
    if (ctxt->value->floatval < 0) {
9734
 
        if (ctxt->value->floatval < f - 0.5)
9735
 
            ctxt->value->floatval = f - 1;
9736
 
        else
9737
 
            ctxt->value->floatval = f;
9738
 
        if (ctxt->value->floatval == 0)
9739
 
            ctxt->value->floatval = xmlXPathNZERO;
9740
 
    } else {
9741
 
        if (ctxt->value->floatval < f + 0.5)
9742
 
            ctxt->value->floatval = f;
9743
 
        else
9744
 
            ctxt->value->floatval = f + 1;
9745
 
    }
9746
 
}
9747
 
 
9748
 
/************************************************************************
9749
 
 *                                                                      *
9750
 
 *                      The Parser                                      *
9751
 
 *                                                                      *
9752
 
 ************************************************************************/
9753
 
 
9754
 
/*
9755
 
 * a few forward declarations since we use a recursive call based
9756
 
 * implementation.
9757
 
 */
9758
 
static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9759
 
static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9760
 
static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9761
 
static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9762
 
static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9763
 
                                          int qualified);
9764
 
 
9765
 
/**
9766
 
 * xmlXPathCurrentChar:
9767
 
 * @ctxt:  the XPath parser context
9768
 
 * @cur:  pointer to the beginning of the char
9769
 
 * @len:  pointer to the length of the char read
9770
 
 *
9771
 
 * The current char value, if using UTF-8 this may actually span multiple
9772
 
 * bytes in the input buffer.
9773
 
 *
9774
 
 * Returns the current char value and its length
9775
 
 */
9776
 
 
9777
 
static int
9778
 
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9779
 
    unsigned char c;
9780
 
    unsigned int val;
9781
 
    const xmlChar *cur;
9782
 
 
9783
 
    if (ctxt == NULL)
9784
 
        return(0);
9785
 
    cur = ctxt->cur;
9786
 
 
9787
 
    /*
9788
 
     * We are supposed to handle UTF8, check it's valid
9789
 
     * From rfc2044: encoding of the Unicode values on UTF-8:
9790
 
     *
9791
 
     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9792
 
     * 0000 0000-0000 007F   0xxxxxxx
9793
 
     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9794
 
     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9795
 
     *
9796
 
     * Check for the 0x110000 limit too
9797
 
     */
9798
 
    c = *cur;
9799
 
    if (c & 0x80) {
9800
 
        if ((cur[1] & 0xc0) != 0x80)
9801
 
            goto encoding_error;
9802
 
        if ((c & 0xe0) == 0xe0) {
9803
 
 
9804
 
            if ((cur[2] & 0xc0) != 0x80)
9805
 
                goto encoding_error;
9806
 
            if ((c & 0xf0) == 0xf0) {
9807
 
                if (((c & 0xf8) != 0xf0) ||
9808
 
                    ((cur[3] & 0xc0) != 0x80))
9809
 
                    goto encoding_error;
9810
 
                /* 4-byte code */
9811
 
                *len = 4;
9812
 
                val = (cur[0] & 0x7) << 18;
9813
 
                val |= (cur[1] & 0x3f) << 12;
9814
 
                val |= (cur[2] & 0x3f) << 6;
9815
 
                val |= cur[3] & 0x3f;
9816
 
            } else {
9817
 
              /* 3-byte code */
9818
 
                *len = 3;
9819
 
                val = (cur[0] & 0xf) << 12;
9820
 
                val |= (cur[1] & 0x3f) << 6;
9821
 
                val |= cur[2] & 0x3f;
9822
 
            }
9823
 
        } else {
9824
 
          /* 2-byte code */
9825
 
            *len = 2;
9826
 
            val = (cur[0] & 0x1f) << 6;
9827
 
            val |= cur[1] & 0x3f;
9828
 
        }
9829
 
        if (!IS_CHAR(val)) {
9830
 
            XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9831
 
        }
9832
 
        return(val);
9833
 
    } else {
9834
 
        /* 1-byte code */
9835
 
        *len = 1;
9836
 
        return((int) *cur);
9837
 
    }
9838
 
encoding_error:
9839
 
    /*
9840
 
     * If we detect an UTF8 error that probably means that the
9841
 
     * input encoding didn't get properly advertised in the
9842
 
     * declaration header. Report the error and switch the encoding
9843
 
     * to ISO-Latin-1 (if you don't like this policy, just declare the
9844
 
     * encoding !)
9845
 
     */
9846
 
    *len = 0;
9847
 
    XP_ERROR0(XPATH_ENCODING_ERROR);
9848
 
}
9849
 
 
9850
 
/**
9851
 
 * xmlXPathParseNCName:
9852
 
 * @ctxt:  the XPath Parser context
9853
 
 *
9854
 
 * parse an XML namespace non qualified name.
9855
 
 *
9856
 
 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9857
 
 *
9858
 
 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9859
 
 *                       CombiningChar | Extender
9860
 
 *
9861
 
 * Returns the namespace name or NULL
9862
 
 */
9863
 
 
9864
 
xmlChar *
9865
 
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9866
 
    const xmlChar *in;
9867
 
    xmlChar *ret;
9868
 
    int count = 0;
9869
 
 
9870
 
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9871
 
    /*
9872
 
     * Accelerator for simple ASCII names
9873
 
     */
9874
 
    in = ctxt->cur;
9875
 
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9876
 
        ((*in >= 0x41) && (*in <= 0x5A)) ||
9877
 
        (*in == '_')) {
9878
 
        in++;
9879
 
        while (((*in >= 0x61) && (*in <= 0x7A)) ||
9880
 
               ((*in >= 0x41) && (*in <= 0x5A)) ||
9881
 
               ((*in >= 0x30) && (*in <= 0x39)) ||
9882
 
               (*in == '_') || (*in == '.') ||
9883
 
               (*in == '-'))
9884
 
            in++;
9885
 
        if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9886
 
            (*in == '[') || (*in == ']') || (*in == ':') ||
9887
 
            (*in == '@') || (*in == '*')) {
9888
 
            count = in - ctxt->cur;
9889
 
            if (count == 0)
9890
 
                return(NULL);
9891
 
            ret = xmlStrndup(ctxt->cur, count);
9892
 
            ctxt->cur = in;
9893
 
            return(ret);
9894
 
        }
9895
 
    }
9896
 
    return(xmlXPathParseNameComplex(ctxt, 0));
9897
 
}
9898
 
 
9899
 
 
9900
 
/**
9901
 
 * xmlXPathParseQName:
9902
 
 * @ctxt:  the XPath Parser context
9903
 
 * @prefix:  a xmlChar **
9904
 
 *
9905
 
 * parse an XML qualified name
9906
 
 *
9907
 
 * [NS 5] QName ::= (Prefix ':')? LocalPart
9908
 
 *
9909
 
 * [NS 6] Prefix ::= NCName
9910
 
 *
9911
 
 * [NS 7] LocalPart ::= NCName
9912
 
 *
9913
 
 * Returns the function returns the local part, and prefix is updated
9914
 
 *   to get the Prefix if any.
9915
 
 */
9916
 
 
9917
 
static xmlChar *
9918
 
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9919
 
    xmlChar *ret = NULL;
9920
 
 
9921
 
    *prefix = NULL;
9922
 
    ret = xmlXPathParseNCName(ctxt);
9923
 
    if (ret && CUR == ':') {
9924
 
        *prefix = ret;
9925
 
        NEXT;
9926
 
        ret = xmlXPathParseNCName(ctxt);
9927
 
    }
9928
 
    return(ret);
9929
 
}
9930
 
 
9931
 
/**
9932
 
 * xmlXPathParseName:
9933
 
 * @ctxt:  the XPath Parser context
9934
 
 *
9935
 
 * parse an XML name
9936
 
 *
9937
 
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9938
 
 *                  CombiningChar | Extender
9939
 
 *
9940
 
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9941
 
 *
9942
 
 * Returns the namespace name or NULL
9943
 
 */
9944
 
 
9945
 
xmlChar *
9946
 
xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9947
 
    const xmlChar *in;
9948
 
    xmlChar *ret;
9949
 
    size_t count = 0;
9950
 
 
9951
 
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9952
 
    /*
9953
 
     * Accelerator for simple ASCII names
9954
 
     */
9955
 
    in = ctxt->cur;
9956
 
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9957
 
        ((*in >= 0x41) && (*in <= 0x5A)) ||
9958
 
        (*in == '_') || (*in == ':')) {
9959
 
        in++;
9960
 
        while (((*in >= 0x61) && (*in <= 0x7A)) ||
9961
 
               ((*in >= 0x41) && (*in <= 0x5A)) ||
9962
 
               ((*in >= 0x30) && (*in <= 0x39)) ||
9963
 
               (*in == '_') || (*in == '-') ||
9964
 
               (*in == ':') || (*in == '.'))
9965
 
            in++;
9966
 
        if ((*in > 0) && (*in < 0x80)) {
9967
 
            count = in - ctxt->cur;
9968
 
            if (count > XML_MAX_NAME_LENGTH) {
9969
 
                ctxt->cur = in;
9970
 
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9971
 
            }
9972
 
            ret = xmlStrndup(ctxt->cur, count);
9973
 
            ctxt->cur = in;
9974
 
            return(ret);
9975
 
        }
9976
 
    }
9977
 
    return(xmlXPathParseNameComplex(ctxt, 1));
9978
 
}
9979
 
 
9980
 
static xmlChar *
9981
 
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9982
 
    xmlChar buf[XML_MAX_NAMELEN + 5];
9983
 
    int len = 0, l;
9984
 
    int c;
9985
 
 
9986
 
    /*
9987
 
     * Handler for more complex cases
9988
 
     */
9989
 
    c = CUR_CHAR(l);
9990
 
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9991
 
        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9992
 
        (c == '*') || /* accelerators */
9993
 
        (!IS_LETTER(c) && (c != '_') &&
9994
 
         ((qualified) && (c != ':')))) {
9995
 
        return(NULL);
9996
 
    }
9997
 
 
9998
 
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9999
 
           ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10000
 
            (c == '.') || (c == '-') ||
10001
 
            (c == '_') || ((qualified) && (c == ':')) ||
10002
 
            (IS_COMBINING(c)) ||
10003
 
            (IS_EXTENDER(c)))) {
10004
 
        COPY_BUF(l,buf,len,c);
10005
 
        NEXTL(l);
10006
 
        c = CUR_CHAR(l);
10007
 
        if (len >= XML_MAX_NAMELEN) {
10008
 
            /*
10009
 
             * Okay someone managed to make a huge name, so he's ready to pay
10010
 
             * for the processing speed.
10011
 
             */
10012
 
            xmlChar *buffer;
10013
 
            int max = len * 2;
10014
 
 
10015
 
            if (len > XML_MAX_NAME_LENGTH) {
10016
 
                XP_ERRORNULL(XPATH_EXPR_ERROR);
10017
 
            }
10018
 
            buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
10019
 
            if (buffer == NULL) {
10020
 
                XP_ERRORNULL(XPATH_MEMORY_ERROR);
10021
 
            }
10022
 
            memcpy(buffer, buf, len);
10023
 
            while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
10024
 
                   (c == '.') || (c == '-') ||
10025
 
                   (c == '_') || ((qualified) && (c == ':')) ||
10026
 
                   (IS_COMBINING(c)) ||
10027
 
                   (IS_EXTENDER(c))) {
10028
 
                if (len + 10 > max) {
10029
 
                    if (max > XML_MAX_NAME_LENGTH) {
10030
 
                        XP_ERRORNULL(XPATH_EXPR_ERROR);
10031
 
                    }
10032
 
                    max *= 2;
10033
 
                    buffer = (xmlChar *) xmlRealloc(buffer,
10034
 
                                                    max * sizeof(xmlChar));
10035
 
                    if (buffer == NULL) {
10036
 
                        XP_ERRORNULL(XPATH_MEMORY_ERROR);
10037
 
                    }
10038
 
                }
10039
 
                COPY_BUF(l,buffer,len,c);
10040
 
                NEXTL(l);
10041
 
                c = CUR_CHAR(l);
10042
 
            }
10043
 
            buffer[len] = 0;
10044
 
            return(buffer);
10045
 
        }
10046
 
    }
10047
 
    if (len == 0)
10048
 
        return(NULL);
10049
 
    return(xmlStrndup(buf, len));
10050
 
}
10051
 
 
10052
 
#define MAX_FRAC 20
10053
 
 
10054
 
/*
10055
 
 * These are used as divisors for the fractional part of a number.
10056
 
 * Since the table includes 1.0 (representing '0' fractional digits),
10057
 
 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
10058
 
 */
10059
 
static double my_pow10[MAX_FRAC+1] = {
10060
 
    1.0, 10.0, 100.0, 1000.0, 10000.0,
10061
 
    100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
10062
 
    10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
10063
 
    100000000000000.0,
10064
 
    1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
10065
 
    1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
10066
 
};
10067
 
 
10068
 
/**
10069
 
 * xmlXPathStringEvalNumber:
10070
 
 * @str:  A string to scan
10071
 
 *
10072
 
 *  [30a]  Float  ::= Number ('e' Digits?)?
10073
 
 *
10074
 
 *  [30]   Number ::=   Digits ('.' Digits?)?
10075
 
 *                    | '.' Digits
10076
 
 *  [31]   Digits ::=   [0-9]+
10077
 
 *
10078
 
 * Compile a Number in the string
10079
 
 * In complement of the Number expression, this function also handles
10080
 
 * negative values : '-' Number.
10081
 
 *
10082
 
 * Returns the double value.
10083
 
 */
10084
 
double
10085
 
xmlXPathStringEvalNumber(const xmlChar *str) {
10086
 
    const xmlChar *cur = str;
10087
 
    double ret;
10088
 
    int ok = 0;
10089
 
    int isneg = 0;
10090
 
    int exponent = 0;
10091
 
    int is_exponent_negative = 0;
10092
 
#ifdef __GNUC__
10093
 
    unsigned long tmp = 0;
10094
 
    double temp;
10095
 
#endif
10096
 
    if (cur == NULL) return(0);
10097
 
    while (IS_BLANK_CH(*cur)) cur++;
10098
 
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10099
 
        return(xmlXPathNAN);
10100
 
    }
10101
 
    if (*cur == '-') {
10102
 
        isneg = 1;
10103
 
        cur++;
10104
 
    }
10105
 
 
10106
 
#ifdef __GNUC__
10107
 
    /*
10108
 
     * tmp/temp is a workaround against a gcc compiler bug
10109
 
     * http://veillard.com/gcc.bug
10110
 
     */
10111
 
    ret = 0;
10112
 
    while ((*cur >= '0') && (*cur <= '9')) {
10113
 
        ret = ret * 10;
10114
 
        tmp = (*cur - '0');
10115
 
        ok = 1;
10116
 
        cur++;
10117
 
        temp = (double) tmp;
10118
 
        ret = ret + temp;
10119
 
    }
10120
 
#else
10121
 
    ret = 0;
10122
 
    while ((*cur >= '0') && (*cur <= '9')) {
10123
 
        ret = ret * 10 + (*cur - '0');
10124
 
        ok = 1;
10125
 
        cur++;
10126
 
    }
10127
 
#endif
10128
 
 
10129
 
    if (*cur == '.') {
10130
 
        int v, frac = 0;
10131
 
        double fraction = 0;
10132
 
 
10133
 
        cur++;
10134
 
        if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10135
 
            return(xmlXPathNAN);
10136
 
        }
10137
 
        while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10138
 
            v = (*cur - '0');
10139
 
            fraction = fraction * 10 + v;
10140
 
            frac = frac + 1;
10141
 
            cur++;
10142
 
        }
10143
 
        fraction /= my_pow10[frac];
10144
 
        ret = ret + fraction;
10145
 
        while ((*cur >= '0') && (*cur <= '9'))
10146
 
            cur++;
10147
 
    }
10148
 
    if ((*cur == 'e') || (*cur == 'E')) {
10149
 
      cur++;
10150
 
      if (*cur == '-') {
10151
 
        is_exponent_negative = 1;
10152
 
        cur++;
10153
 
      } else if (*cur == '+') {
10154
 
        cur++;
10155
 
      }
10156
 
      while ((*cur >= '0') && (*cur <= '9')) {
10157
 
        exponent = exponent * 10 + (*cur - '0');
10158
 
        cur++;
10159
 
      }
10160
 
    }
10161
 
    while (IS_BLANK_CH(*cur)) cur++;
10162
 
    if (*cur != 0) return(xmlXPathNAN);
10163
 
    if (isneg) ret = -ret;
10164
 
    if (is_exponent_negative) exponent = -exponent;
10165
 
    ret *= pow(10.0, (double)exponent);
10166
 
    return(ret);
10167
 
}
10168
 
 
10169
 
/**
10170
 
 * xmlXPathCompNumber:
10171
 
 * @ctxt:  the XPath Parser context
10172
 
 *
10173
 
 *  [30]   Number ::=   Digits ('.' Digits?)?
10174
 
 *                    | '.' Digits
10175
 
 *  [31]   Digits ::=   [0-9]+
10176
 
 *
10177
 
 * Compile a Number, then push it on the stack
10178
 
 *
10179
 
 */
10180
 
static void
10181
 
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10182
 
{
10183
 
    double ret = 0.0;
10184
 
    int ok = 0;
10185
 
    int exponent = 0;
10186
 
    int is_exponent_negative = 0;
10187
 
#ifdef __GNUC__
10188
 
    unsigned long tmp = 0;
10189
 
    double temp;
10190
 
#endif
10191
 
 
10192
 
    CHECK_ERROR;
10193
 
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10194
 
        XP_ERROR(XPATH_NUMBER_ERROR);
10195
 
    }
10196
 
#ifdef __GNUC__
10197
 
    /*
10198
 
     * tmp/temp is a workaround against a gcc compiler bug
10199
 
     * http://veillard.com/gcc.bug
10200
 
     */
10201
 
    ret = 0;
10202
 
    while ((CUR >= '0') && (CUR <= '9')) {
10203
 
        ret = ret * 10;
10204
 
        tmp = (CUR - '0');
10205
 
        ok = 1;
10206
 
        NEXT;
10207
 
        temp = (double) tmp;
10208
 
        ret = ret + temp;
10209
 
    }
10210
 
#else
10211
 
    ret = 0;
10212
 
    while ((CUR >= '0') && (CUR <= '9')) {
10213
 
        ret = ret * 10 + (CUR - '0');
10214
 
        ok = 1;
10215
 
        NEXT;
10216
 
    }
10217
 
#endif
10218
 
    if (CUR == '.') {
10219
 
        int v, frac = 0;
10220
 
        double fraction = 0;
10221
 
 
10222
 
        NEXT;
10223
 
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10224
 
            XP_ERROR(XPATH_NUMBER_ERROR);
10225
 
        }
10226
 
        while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
10227
 
            v = (CUR - '0');
10228
 
            fraction = fraction * 10 + v;
10229
 
            frac = frac + 1;
10230
 
            NEXT;
10231
 
        }
10232
 
        fraction /= my_pow10[frac];
10233
 
        ret = ret + fraction;
10234
 
        while ((CUR >= '0') && (CUR <= '9'))
10235
 
            NEXT;
10236
 
    }
10237
 
    if ((CUR == 'e') || (CUR == 'E')) {
10238
 
        NEXT;
10239
 
        if (CUR == '-') {
10240
 
            is_exponent_negative = 1;
10241
 
            NEXT;
10242
 
        } else if (CUR == '+') {
10243
 
            NEXT;
10244
 
        }
10245
 
        while ((CUR >= '0') && (CUR <= '9')) {
10246
 
            exponent = exponent * 10 + (CUR - '0');
10247
 
            NEXT;
10248
 
        }
10249
 
        if (is_exponent_negative)
10250
 
            exponent = -exponent;
10251
 
        ret *= pow(10.0, (double) exponent);
10252
 
    }
10253
 
    PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10254
 
                   xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10255
 
}
10256
 
 
10257
 
/**
10258
 
 * xmlXPathParseLiteral:
10259
 
 * @ctxt:  the XPath Parser context
10260
 
 *
10261
 
 * Parse a Literal
10262
 
 *
10263
 
 *  [29]   Literal ::=   '"' [^"]* '"'
10264
 
 *                    | "'" [^']* "'"
10265
 
 *
10266
 
 * Returns the value found or NULL in case of error
10267
 
 */
10268
 
static xmlChar *
10269
 
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10270
 
    const xmlChar *q;
10271
 
    xmlChar *ret = NULL;
10272
 
 
10273
 
    if (CUR == '"') {
10274
 
        NEXT;
10275
 
        q = CUR_PTR;
10276
 
        while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10277
 
            NEXT;
10278
 
        if (!IS_CHAR_CH(CUR)) {
10279
 
            XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10280
 
        } else {
10281
 
            ret = xmlStrndup(q, CUR_PTR - q);
10282
 
            NEXT;
10283
 
        }
10284
 
    } else if (CUR == '\'') {
10285
 
        NEXT;
10286
 
        q = CUR_PTR;
10287
 
        while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10288
 
            NEXT;
10289
 
        if (!IS_CHAR_CH(CUR)) {
10290
 
            XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10291
 
        } else {
10292
 
            ret = xmlStrndup(q, CUR_PTR - q);
10293
 
            NEXT;
10294
 
        }
10295
 
    } else {
10296
 
        XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10297
 
    }
10298
 
    return(ret);
10299
 
}
10300
 
 
10301
 
/**
10302
 
 * xmlXPathCompLiteral:
10303
 
 * @ctxt:  the XPath Parser context
10304
 
 *
10305
 
 * Parse a Literal and push it on the stack.
10306
 
 *
10307
 
 *  [29]   Literal ::=   '"' [^"]* '"'
10308
 
 *                    | "'" [^']* "'"
10309
 
 *
10310
 
 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10311
 
 */
10312
 
static void
10313
 
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10314
 
    const xmlChar *q;
10315
 
    xmlChar *ret = NULL;
10316
 
 
10317
 
    if (CUR == '"') {
10318
 
        NEXT;
10319
 
        q = CUR_PTR;
10320
 
        while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10321
 
            NEXT;
10322
 
        if (!IS_CHAR_CH(CUR)) {
10323
 
            XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10324
 
        } else {
10325
 
            ret = xmlStrndup(q, CUR_PTR - q);
10326
 
            NEXT;
10327
 
        }
10328
 
    } else if (CUR == '\'') {
10329
 
        NEXT;
10330
 
        q = CUR_PTR;
10331
 
        while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10332
 
            NEXT;
10333
 
        if (!IS_CHAR_CH(CUR)) {
10334
 
            XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10335
 
        } else {
10336
 
            ret = xmlStrndup(q, CUR_PTR - q);
10337
 
            NEXT;
10338
 
        }
10339
 
    } else {
10340
 
        XP_ERROR(XPATH_START_LITERAL_ERROR);
10341
 
    }
10342
 
    if (ret == NULL) return;
10343
 
    PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10344
 
                   xmlXPathCacheNewString(ctxt->context, ret), NULL);
10345
 
    xmlFree(ret);
10346
 
}
10347
 
 
10348
 
/**
10349
 
 * xmlXPathCompVariableReference:
10350
 
 * @ctxt:  the XPath Parser context
10351
 
 *
10352
 
 * Parse a VariableReference, evaluate it and push it on the stack.
10353
 
 *
10354
 
 * The variable bindings consist of a mapping from variable names
10355
 
 * to variable values. The value of a variable is an object, which can be
10356
 
 * of any of the types that are possible for the value of an expression,
10357
 
 * and may also be of additional types not specified here.
10358
 
 *
10359
 
 * Early evaluation is possible since:
10360
 
 * The variable bindings [...] used to evaluate a subexpression are
10361
 
 * always the same as those used to evaluate the containing expression.
10362
 
 *
10363
 
 *  [36]   VariableReference ::=   '$' QName
10364
 
 */
10365
 
static void
10366
 
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10367
 
    xmlChar *name;
10368
 
    xmlChar *prefix;
10369
 
 
10370
 
    SKIP_BLANKS;
10371
 
    if (CUR != '$') {
10372
 
        XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10373
 
    }
10374
 
    NEXT;
10375
 
    name = xmlXPathParseQName(ctxt, &prefix);
10376
 
    if (name == NULL) {
10377
 
        XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10378
 
    }
10379
 
    ctxt->comp->last = -1;
10380
 
    PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10381
 
                   name, prefix);
10382
 
    SKIP_BLANKS;
10383
 
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10384
 
        XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10385
 
    }
10386
 
}
10387
 
 
10388
 
/**
10389
 
 * xmlXPathIsNodeType:
10390
 
 * @name:  a name string
10391
 
 *
10392
 
 * Is the name given a NodeType one.
10393
 
 *
10394
 
 *  [38]   NodeType ::=   'comment'
10395
 
 *                    | 'text'
10396
 
 *                    | 'processing-instruction'
10397
 
 *                    | 'node'
10398
 
 *
10399
 
 * Returns 1 if true 0 otherwise
10400
 
 */
10401
 
int
10402
 
xmlXPathIsNodeType(const xmlChar *name) {
10403
 
    if (name == NULL)
10404
 
        return(0);
10405
 
 
10406
 
    if (xmlStrEqual(name, BAD_CAST "node"))
10407
 
        return(1);
10408
 
    if (xmlStrEqual(name, BAD_CAST "text"))
10409
 
        return(1);
10410
 
    if (xmlStrEqual(name, BAD_CAST "comment"))
10411
 
        return(1);
10412
 
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10413
 
        return(1);
10414
 
    return(0);
10415
 
}
10416
 
 
10417
 
/**
10418
 
 * xmlXPathCompFunctionCall:
10419
 
 * @ctxt:  the XPath Parser context
10420
 
 *
10421
 
 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10422
 
 *  [17]   Argument ::=   Expr
10423
 
 *
10424
 
 * Compile a function call, the evaluation of all arguments are
10425
 
 * pushed on the stack
10426
 
 */
10427
 
static void
10428
 
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10429
 
    xmlChar *name;
10430
 
    xmlChar *prefix;
10431
 
    int nbargs = 0;
10432
 
    int sort = 1;
10433
 
 
10434
 
    name = xmlXPathParseQName(ctxt, &prefix);
10435
 
    if (name == NULL) {
10436
 
        xmlFree(prefix);
10437
 
        XP_ERROR(XPATH_EXPR_ERROR);
10438
 
    }
10439
 
    SKIP_BLANKS;
10440
 
#ifdef DEBUG_EXPR
10441
 
    if (prefix == NULL)
10442
 
        xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10443
 
                        name);
10444
 
    else
10445
 
        xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10446
 
                        prefix, name);
10447
 
#endif
10448
 
 
10449
 
    if (CUR != '(') {
10450
 
        XP_ERROR(XPATH_EXPR_ERROR);
10451
 
    }
10452
 
    NEXT;
10453
 
    SKIP_BLANKS;
10454
 
 
10455
 
    /*
10456
 
    * Optimization for count(): we don't need the node-set to be sorted.
10457
 
    */
10458
 
    if ((prefix == NULL) && (name[0] == 'c') &&
10459
 
        xmlStrEqual(name, BAD_CAST "count"))
10460
 
    {
10461
 
        sort = 0;
10462
 
    }
10463
 
    ctxt->comp->last = -1;
10464
 
    if (CUR != ')') {
10465
 
        while (CUR != 0) {
10466
 
            int op1 = ctxt->comp->last;
10467
 
            ctxt->comp->last = -1;
10468
 
            xmlXPathCompileExpr(ctxt, sort);
10469
 
            if (ctxt->error != XPATH_EXPRESSION_OK) {
10470
 
                xmlFree(name);
10471
 
                xmlFree(prefix);
10472
 
                return;
10473
 
            }
10474
 
            PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10475
 
            nbargs++;
10476
 
            if (CUR == ')') break;
10477
 
            if (CUR != ',') {
10478
 
                XP_ERROR(XPATH_EXPR_ERROR);
10479
 
            }
10480
 
            NEXT;
10481
 
            SKIP_BLANKS;
10482
 
        }
10483
 
    }
10484
 
    PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10485
 
                   name, prefix);
10486
 
    NEXT;
10487
 
    SKIP_BLANKS;
10488
 
}
10489
 
 
10490
 
/**
10491
 
 * xmlXPathCompPrimaryExpr:
10492
 
 * @ctxt:  the XPath Parser context
10493
 
 *
10494
 
 *  [15]   PrimaryExpr ::=   VariableReference
10495
 
 *                | '(' Expr ')'
10496
 
 *                | Literal
10497
 
 *                | Number
10498
 
 *                | FunctionCall
10499
 
 *
10500
 
 * Compile a primary expression.
10501
 
 */
10502
 
static void
10503
 
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10504
 
    SKIP_BLANKS;
10505
 
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10506
 
    else if (CUR == '(') {
10507
 
        NEXT;
10508
 
        SKIP_BLANKS;
10509
 
        xmlXPathCompileExpr(ctxt, 1);
10510
 
        CHECK_ERROR;
10511
 
        if (CUR != ')') {
10512
 
            XP_ERROR(XPATH_EXPR_ERROR);
10513
 
        }
10514
 
        NEXT;
10515
 
        SKIP_BLANKS;
10516
 
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10517
 
        xmlXPathCompNumber(ctxt);
10518
 
    } else if ((CUR == '\'') || (CUR == '"')) {
10519
 
        xmlXPathCompLiteral(ctxt);
10520
 
    } else {
10521
 
        xmlXPathCompFunctionCall(ctxt);
10522
 
    }
10523
 
    SKIP_BLANKS;
10524
 
}
10525
 
 
10526
 
/**
10527
 
 * xmlXPathCompFilterExpr:
10528
 
 * @ctxt:  the XPath Parser context
10529
 
 *
10530
 
 *  [20]   FilterExpr ::=   PrimaryExpr
10531
 
 *               | FilterExpr Predicate
10532
 
 *
10533
 
 * Compile a filter expression.
10534
 
 * Square brackets are used to filter expressions in the same way that
10535
 
 * they are used in location paths. It is an error if the expression to
10536
 
 * be filtered does not evaluate to a node-set. The context node list
10537
 
 * used for evaluating the expression in square brackets is the node-set
10538
 
 * to be filtered listed in document order.
10539
 
 */
10540
 
 
10541
 
static void
10542
 
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10543
 
    xmlXPathCompPrimaryExpr(ctxt);
10544
 
    CHECK_ERROR;
10545
 
    SKIP_BLANKS;
10546
 
 
10547
 
    while (CUR == '[') {
10548
 
        xmlXPathCompPredicate(ctxt, 1);
10549
 
        SKIP_BLANKS;
10550
 
    }
10551
 
 
10552
 
 
10553
 
}
10554
 
 
10555
 
/**
10556
 
 * xmlXPathScanName:
10557
 
 * @ctxt:  the XPath Parser context
10558
 
 *
10559
 
 * Trickery: parse an XML name but without consuming the input flow
10560
 
 * Needed to avoid insanity in the parser state.
10561
 
 *
10562
 
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10563
 
 *                  CombiningChar | Extender
10564
 
 *
10565
 
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10566
 
 *
10567
 
 * [6] Names ::= Name (S Name)*
10568
 
 *
10569
 
 * Returns the Name parsed or NULL
10570
 
 */
10571
 
 
10572
 
static xmlChar *
10573
 
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10574
 
    int len = 0, l;
10575
 
    int c;
10576
 
    const xmlChar *cur;
10577
 
    xmlChar *ret;
10578
 
 
10579
 
    cur = ctxt->cur;
10580
 
 
10581
 
    c = CUR_CHAR(l);
10582
 
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10583
 
        (!IS_LETTER(c) && (c != '_') &&
10584
 
         (c != ':'))) {
10585
 
        return(NULL);
10586
 
    }
10587
 
 
10588
 
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10589
 
           ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10590
 
            (c == '.') || (c == '-') ||
10591
 
            (c == '_') || (c == ':') ||
10592
 
            (IS_COMBINING(c)) ||
10593
 
            (IS_EXTENDER(c)))) {
10594
 
        len += l;
10595
 
        NEXTL(l);
10596
 
        c = CUR_CHAR(l);
10597
 
    }
10598
 
    ret = xmlStrndup(cur, ctxt->cur - cur);
10599
 
    ctxt->cur = cur;
10600
 
    return(ret);
10601
 
}
10602
 
 
10603
 
/**
10604
 
 * xmlXPathCompPathExpr:
10605
 
 * @ctxt:  the XPath Parser context
10606
 
 *
10607
 
 *  [19]   PathExpr ::=   LocationPath
10608
 
 *               | FilterExpr
10609
 
 *               | FilterExpr '/' RelativeLocationPath
10610
 
 *               | FilterExpr '//' RelativeLocationPath
10611
 
 *
10612
 
 * Compile a path expression.
10613
 
 * The / operator and // operators combine an arbitrary expression
10614
 
 * and a relative location path. It is an error if the expression
10615
 
 * does not evaluate to a node-set.
10616
 
 * The / operator does composition in the same way as when / is
10617
 
 * used in a location path. As in location paths, // is short for
10618
 
 * /descendant-or-self::node()/.
10619
 
 */
10620
 
 
10621
 
static void
10622
 
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10623
 
    int lc = 1;           /* Should we branch to LocationPath ?         */
10624
 
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
10625
 
 
10626
 
    SKIP_BLANKS;
10627
 
    if ((CUR == '$') || (CUR == '(') ||
10628
 
        (IS_ASCII_DIGIT(CUR)) ||
10629
 
        (CUR == '\'') || (CUR == '"') ||
10630
 
        (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10631
 
        lc = 0;
10632
 
    } else if (CUR == '*') {
10633
 
        /* relative or absolute location path */
10634
 
        lc = 1;
10635
 
    } else if (CUR == '/') {
10636
 
        /* relative or absolute location path */
10637
 
        lc = 1;
10638
 
    } else if (CUR == '@') {
10639
 
        /* relative abbreviated attribute location path */
10640
 
        lc = 1;
10641
 
    } else if (CUR == '.') {
10642
 
        /* relative abbreviated attribute location path */
10643
 
        lc = 1;
10644
 
    } else {
10645
 
        /*
10646
 
         * Problem is finding if we have a name here whether it's:
10647
 
         *   - a nodetype
10648
 
         *   - a function call in which case it's followed by '('
10649
 
         *   - an axis in which case it's followed by ':'
10650
 
         *   - a element name
10651
 
         * We do an a priori analysis here rather than having to
10652
 
         * maintain parsed token content through the recursive function
10653
 
         * calls. This looks uglier but makes the code easier to
10654
 
         * read/write/debug.
10655
 
         */
10656
 
        SKIP_BLANKS;
10657
 
        name = xmlXPathScanName(ctxt);
10658
 
        if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10659
 
#ifdef DEBUG_STEP
10660
 
            xmlGenericError(xmlGenericErrorContext,
10661
 
                    "PathExpr: Axis\n");
10662
 
#endif
10663
 
            lc = 1;
10664
 
            xmlFree(name);
10665
 
        } else if (name != NULL) {
10666
 
            int len =xmlStrlen(name);
10667
 
 
10668
 
 
10669
 
            while (NXT(len) != 0) {
10670
 
                if (NXT(len) == '/') {
10671
 
                    /* element name */
10672
 
#ifdef DEBUG_STEP
10673
 
                    xmlGenericError(xmlGenericErrorContext,
10674
 
                            "PathExpr: AbbrRelLocation\n");
10675
 
#endif
10676
 
                    lc = 1;
10677
 
                    break;
10678
 
                } else if (IS_BLANK_CH(NXT(len))) {
10679
 
                    /* ignore blanks */
10680
 
                    ;
10681
 
                } else if (NXT(len) == ':') {
10682
 
#ifdef DEBUG_STEP
10683
 
                    xmlGenericError(xmlGenericErrorContext,
10684
 
                            "PathExpr: AbbrRelLocation\n");
10685
 
#endif
10686
 
                    lc = 1;
10687
 
                    break;
10688
 
                } else if ((NXT(len) == '(')) {
10689
 
                    /* Note Type or Function */
10690
 
                    if (xmlXPathIsNodeType(name)) {
10691
 
#ifdef DEBUG_STEP
10692
 
                        xmlGenericError(xmlGenericErrorContext,
10693
 
                                "PathExpr: Type search\n");
10694
 
#endif
10695
 
                        lc = 1;
10696
 
                    } else {
10697
 
#ifdef DEBUG_STEP
10698
 
                        xmlGenericError(xmlGenericErrorContext,
10699
 
                                "PathExpr: function call\n");
10700
 
#endif
10701
 
                        lc = 0;
10702
 
                    }
10703
 
                    break;
10704
 
                } else if ((NXT(len) == '[')) {
10705
 
                    /* element name */
10706
 
#ifdef DEBUG_STEP
10707
 
                    xmlGenericError(xmlGenericErrorContext,
10708
 
                            "PathExpr: AbbrRelLocation\n");
10709
 
#endif
10710
 
                    lc = 1;
10711
 
                    break;
10712
 
                } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10713
 
                           (NXT(len) == '=')) {
10714
 
                    lc = 1;
10715
 
                    break;
10716
 
                } else {
10717
 
                    lc = 1;
10718
 
                    break;
10719
 
                }
10720
 
                len++;
10721
 
            }
10722
 
            if (NXT(len) == 0) {
10723
 
#ifdef DEBUG_STEP
10724
 
                xmlGenericError(xmlGenericErrorContext,
10725
 
                        "PathExpr: AbbrRelLocation\n");
10726
 
#endif
10727
 
                /* element name */
10728
 
                lc = 1;
10729
 
            }
10730
 
            xmlFree(name);
10731
 
        } else {
10732
 
            /* make sure all cases are covered explicitly */
10733
 
            XP_ERROR(XPATH_EXPR_ERROR);
10734
 
        }
10735
 
    }
10736
 
 
10737
 
    if (lc) {
10738
 
        if (CUR == '/') {
10739
 
            PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10740
 
        } else {
10741
 
            PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10742
 
        }
10743
 
        xmlXPathCompLocationPath(ctxt);
10744
 
    } else {
10745
 
        xmlXPathCompFilterExpr(ctxt);
10746
 
        CHECK_ERROR;
10747
 
        if ((CUR == '/') && (NXT(1) == '/')) {
10748
 
            SKIP(2);
10749
 
            SKIP_BLANKS;
10750
 
 
10751
 
            PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10752
 
                    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10753
 
            PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10754
 
 
10755
 
            xmlXPathCompRelativeLocationPath(ctxt);
10756
 
        } else if (CUR == '/') {
10757
 
            xmlXPathCompRelativeLocationPath(ctxt);
10758
 
        }
10759
 
    }
10760
 
    SKIP_BLANKS;
10761
 
}
10762
 
 
10763
 
/**
10764
 
 * xmlXPathCompUnionExpr:
10765
 
 * @ctxt:  the XPath Parser context
10766
 
 *
10767
 
 *  [18]   UnionExpr ::=   PathExpr
10768
 
 *               | UnionExpr '|' PathExpr
10769
 
 *
10770
 
 * Compile an union expression.
10771
 
 */
10772
 
 
10773
 
static void
10774
 
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10775
 
    xmlXPathCompPathExpr(ctxt);
10776
 
    CHECK_ERROR;
10777
 
    SKIP_BLANKS;
10778
 
    while (CUR == '|') {
10779
 
        int op1 = ctxt->comp->last;
10780
 
        PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10781
 
 
10782
 
        NEXT;
10783
 
        SKIP_BLANKS;
10784
 
        xmlXPathCompPathExpr(ctxt);
10785
 
 
10786
 
        PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10787
 
 
10788
 
        SKIP_BLANKS;
10789
 
    }
10790
 
}
10791
 
 
10792
 
/**
10793
 
 * xmlXPathCompUnaryExpr:
10794
 
 * @ctxt:  the XPath Parser context
10795
 
 *
10796
 
 *  [27]   UnaryExpr ::=   UnionExpr
10797
 
 *                   | '-' UnaryExpr
10798
 
 *
10799
 
 * Compile an unary expression.
10800
 
 */
10801
 
 
10802
 
static void
10803
 
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10804
 
    int minus = 0;
10805
 
    int found = 0;
10806
 
 
10807
 
    SKIP_BLANKS;
10808
 
    while (CUR == '-') {
10809
 
        minus = 1 - minus;
10810
 
        found = 1;
10811
 
        NEXT;
10812
 
        SKIP_BLANKS;
10813
 
    }
10814
 
 
10815
 
    xmlXPathCompUnionExpr(ctxt);
10816
 
    CHECK_ERROR;
10817
 
    if (found) {
10818
 
        if (minus)
10819
 
            PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10820
 
        else
10821
 
            PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10822
 
    }
10823
 
}
10824
 
 
10825
 
/**
10826
 
 * xmlXPathCompMultiplicativeExpr:
10827
 
 * @ctxt:  the XPath Parser context
10828
 
 *
10829
 
 *  [26]   MultiplicativeExpr ::=   UnaryExpr
10830
 
 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10831
 
 *                   | MultiplicativeExpr 'div' UnaryExpr
10832
 
 *                   | MultiplicativeExpr 'mod' UnaryExpr
10833
 
 *  [34]   MultiplyOperator ::=   '*'
10834
 
 *
10835
 
 * Compile an Additive expression.
10836
 
 */
10837
 
 
10838
 
static void
10839
 
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10840
 
    xmlXPathCompUnaryExpr(ctxt);
10841
 
    CHECK_ERROR;
10842
 
    SKIP_BLANKS;
10843
 
    while ((CUR == '*') ||
10844
 
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10845
 
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10846
 
        int op = -1;
10847
 
        int op1 = ctxt->comp->last;
10848
 
 
10849
 
        if (CUR == '*') {
10850
 
            op = 0;
10851
 
            NEXT;
10852
 
        } else if (CUR == 'd') {
10853
 
            op = 1;
10854
 
            SKIP(3);
10855
 
        } else if (CUR == 'm') {
10856
 
            op = 2;
10857
 
            SKIP(3);
10858
 
        }
10859
 
        SKIP_BLANKS;
10860
 
        xmlXPathCompUnaryExpr(ctxt);
10861
 
        CHECK_ERROR;
10862
 
        PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10863
 
        SKIP_BLANKS;
10864
 
    }
10865
 
}
10866
 
 
10867
 
/**
10868
 
 * xmlXPathCompAdditiveExpr:
10869
 
 * @ctxt:  the XPath Parser context
10870
 
 *
10871
 
 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10872
 
 *                   | AdditiveExpr '+' MultiplicativeExpr
10873
 
 *                   | AdditiveExpr '-' MultiplicativeExpr
10874
 
 *
10875
 
 * Compile an Additive expression.
10876
 
 */
10877
 
 
10878
 
static void
10879
 
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10880
 
 
10881
 
    xmlXPathCompMultiplicativeExpr(ctxt);
10882
 
    CHECK_ERROR;
10883
 
    SKIP_BLANKS;
10884
 
    while ((CUR == '+') || (CUR == '-')) {
10885
 
        int plus;
10886
 
        int op1 = ctxt->comp->last;
10887
 
 
10888
 
        if (CUR == '+') plus = 1;
10889
 
        else plus = 0;
10890
 
        NEXT;
10891
 
        SKIP_BLANKS;
10892
 
        xmlXPathCompMultiplicativeExpr(ctxt);
10893
 
        CHECK_ERROR;
10894
 
        PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10895
 
        SKIP_BLANKS;
10896
 
    }
10897
 
}
10898
 
 
10899
 
/**
10900
 
 * xmlXPathCompRelationalExpr:
10901
 
 * @ctxt:  the XPath Parser context
10902
 
 *
10903
 
 *  [24]   RelationalExpr ::=   AdditiveExpr
10904
 
 *                 | RelationalExpr '<' AdditiveExpr
10905
 
 *                 | RelationalExpr '>' AdditiveExpr
10906
 
 *                 | RelationalExpr '<=' AdditiveExpr
10907
 
 *                 | RelationalExpr '>=' AdditiveExpr
10908
 
 *
10909
 
 *  A <= B > C is allowed ? Answer from James, yes with
10910
 
 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10911
 
 *  which is basically what got implemented.
10912
 
 *
10913
 
 * Compile a Relational expression, then push the result
10914
 
 * on the stack
10915
 
 */
10916
 
 
10917
 
static void
10918
 
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10919
 
    xmlXPathCompAdditiveExpr(ctxt);
10920
 
    CHECK_ERROR;
10921
 
    SKIP_BLANKS;
10922
 
    while ((CUR == '<') ||
10923
 
           (CUR == '>') ||
10924
 
           ((CUR == '<') && (NXT(1) == '=')) ||
10925
 
           ((CUR == '>') && (NXT(1) == '='))) {
10926
 
        int inf, strict;
10927
 
        int op1 = ctxt->comp->last;
10928
 
 
10929
 
        if (CUR == '<') inf = 1;
10930
 
        else inf = 0;
10931
 
        if (NXT(1) == '=') strict = 0;
10932
 
        else strict = 1;
10933
 
        NEXT;
10934
 
        if (!strict) NEXT;
10935
 
        SKIP_BLANKS;
10936
 
        xmlXPathCompAdditiveExpr(ctxt);
10937
 
        CHECK_ERROR;
10938
 
        PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10939
 
        SKIP_BLANKS;
10940
 
    }
10941
 
}
10942
 
 
10943
 
/**
10944
 
 * xmlXPathCompEqualityExpr:
10945
 
 * @ctxt:  the XPath Parser context
10946
 
 *
10947
 
 *  [23]   EqualityExpr ::=   RelationalExpr
10948
 
 *                 | EqualityExpr '=' RelationalExpr
10949
 
 *                 | EqualityExpr '!=' RelationalExpr
10950
 
 *
10951
 
 *  A != B != C is allowed ? Answer from James, yes with
10952
 
 *  (RelationalExpr = RelationalExpr) = RelationalExpr
10953
 
 *  (RelationalExpr != RelationalExpr) != RelationalExpr
10954
 
 *  which is basically what got implemented.
10955
 
 *
10956
 
 * Compile an Equality expression.
10957
 
 *
10958
 
 */
10959
 
static void
10960
 
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10961
 
    xmlXPathCompRelationalExpr(ctxt);
10962
 
    CHECK_ERROR;
10963
 
    SKIP_BLANKS;
10964
 
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10965
 
        int eq;
10966
 
        int op1 = ctxt->comp->last;
10967
 
 
10968
 
        if (CUR == '=') eq = 1;
10969
 
        else eq = 0;
10970
 
        NEXT;
10971
 
        if (!eq) NEXT;
10972
 
        SKIP_BLANKS;
10973
 
        xmlXPathCompRelationalExpr(ctxt);
10974
 
        CHECK_ERROR;
10975
 
        PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10976
 
        SKIP_BLANKS;
10977
 
    }
10978
 
}
10979
 
 
10980
 
/**
10981
 
 * xmlXPathCompAndExpr:
10982
 
 * @ctxt:  the XPath Parser context
10983
 
 *
10984
 
 *  [22]   AndExpr ::=   EqualityExpr
10985
 
 *                 | AndExpr 'and' EqualityExpr
10986
 
 *
10987
 
 * Compile an AND expression.
10988
 
 *
10989
 
 */
10990
 
static void
10991
 
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10992
 
    xmlXPathCompEqualityExpr(ctxt);
10993
 
    CHECK_ERROR;
10994
 
    SKIP_BLANKS;
10995
 
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10996
 
        int op1 = ctxt->comp->last;
10997
 
        SKIP(3);
10998
 
        SKIP_BLANKS;
10999
 
        xmlXPathCompEqualityExpr(ctxt);
11000
 
        CHECK_ERROR;
11001
 
        PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
11002
 
        SKIP_BLANKS;
11003
 
    }
11004
 
}
11005
 
 
11006
 
/**
11007
 
 * xmlXPathCompileExpr:
11008
 
 * @ctxt:  the XPath Parser context
11009
 
 *
11010
 
 *  [14]   Expr ::=   OrExpr
11011
 
 *  [21]   OrExpr ::=   AndExpr
11012
 
 *                 | OrExpr 'or' AndExpr
11013
 
 *
11014
 
 * Parse and compile an expression
11015
 
 */
11016
 
static void
11017
 
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
11018
 
    xmlXPathCompAndExpr(ctxt);
11019
 
    CHECK_ERROR;
11020
 
    SKIP_BLANKS;
11021
 
    while ((CUR == 'o') && (NXT(1) == 'r')) {
11022
 
        int op1 = ctxt->comp->last;
11023
 
        SKIP(2);
11024
 
        SKIP_BLANKS;
11025
 
        xmlXPathCompAndExpr(ctxt);
11026
 
        CHECK_ERROR;
11027
 
        PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
11028
 
        SKIP_BLANKS;
11029
 
    }
11030
 
    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
11031
 
        /* more ops could be optimized too */
11032
 
        /*
11033
 
        * This is the main place to eliminate sorting for
11034
 
        * operations which don't require a sorted node-set.
11035
 
        * E.g. count().
11036
 
        */
11037
 
        PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11038
 
    }
11039
 
}
11040
 
 
11041
 
/**
11042
 
 * xmlXPathCompPredicate:
11043
 
 * @ctxt:  the XPath Parser context
11044
 
 * @filter:  act as a filter
11045
 
 *
11046
 
 *  [8]   Predicate ::=   '[' PredicateExpr ']'
11047
 
 *  [9]   PredicateExpr ::=   Expr
11048
 
 *
11049
 
 * Compile a predicate expression
11050
 
 */
11051
 
static void
11052
 
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11053
 
    int op1 = ctxt->comp->last;
11054
 
 
11055
 
    SKIP_BLANKS;
11056
 
    if (CUR != '[') {
11057
 
        XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11058
 
    }
11059
 
    NEXT;
11060
 
    SKIP_BLANKS;
11061
 
 
11062
 
    ctxt->comp->last = -1;
11063
 
    /*
11064
 
    * This call to xmlXPathCompileExpr() will deactivate sorting
11065
 
    * of the predicate result.
11066
 
    * TODO: Sorting is still activated for filters, since I'm not
11067
 
    *  sure if needed. Normally sorting should not be needed, since
11068
 
    *  a filter can only diminish the number of items in a sequence,
11069
 
    *  but won't change its order; so if the initial sequence is sorted,
11070
 
    *  subsequent sorting is not needed.
11071
 
    */
11072
 
    if (! filter)
11073
 
        xmlXPathCompileExpr(ctxt, 0);
11074
 
    else
11075
 
        xmlXPathCompileExpr(ctxt, 1);
11076
 
    CHECK_ERROR;
11077
 
 
11078
 
    if (CUR != ']') {
11079
 
        XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11080
 
    }
11081
 
 
11082
 
    if (filter)
11083
 
        PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11084
 
    else
11085
 
        PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11086
 
 
11087
 
    NEXT;
11088
 
    SKIP_BLANKS;
11089
 
}
11090
 
 
11091
 
/**
11092
 
 * xmlXPathCompNodeTest:
11093
 
 * @ctxt:  the XPath Parser context
11094
 
 * @test:  pointer to a xmlXPathTestVal
11095
 
 * @type:  pointer to a xmlXPathTypeVal
11096
 
 * @prefix:  placeholder for a possible name prefix
11097
 
 *
11098
 
 * [7] NodeTest ::=   NameTest
11099
 
 *                  | NodeType '(' ')'
11100
 
 *                  | 'processing-instruction' '(' Literal ')'
11101
 
 *
11102
 
 * [37] NameTest ::=  '*'
11103
 
 *                  | NCName ':' '*'
11104
 
 *                  | QName
11105
 
 * [38] NodeType ::= 'comment'
11106
 
 *                 | 'text'
11107
 
 *                 | 'processing-instruction'
11108
 
 *                 | 'node'
11109
 
 *
11110
 
 * Returns the name found and updates @test, @type and @prefix appropriately
11111
 
 */
11112
 
static xmlChar *
11113
 
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11114
 
                     xmlXPathTypeVal *type, const xmlChar **prefix,
11115
 
                     xmlChar *name) {
11116
 
    int blanks;
11117
 
 
11118
 
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11119
 
        STRANGE;
11120
 
        return(NULL);
11121
 
    }
11122
 
    *type = (xmlXPathTypeVal) 0;
11123
 
    *test = (xmlXPathTestVal) 0;
11124
 
    *prefix = NULL;
11125
 
    SKIP_BLANKS;
11126
 
 
11127
 
    if ((name == NULL) && (CUR == '*')) {
11128
 
        /*
11129
 
         * All elements
11130
 
         */
11131
 
        NEXT;
11132
 
        *test = NODE_TEST_ALL;
11133
 
        return(NULL);
11134
 
    }
11135
 
 
11136
 
    if (name == NULL)
11137
 
        name = xmlXPathParseNCName(ctxt);
11138
 
    if (name == NULL) {
11139
 
        XP_ERRORNULL(XPATH_EXPR_ERROR);
11140
 
    }
11141
 
 
11142
 
    blanks = IS_BLANK_CH(CUR);
11143
 
    SKIP_BLANKS;
11144
 
    if (CUR == '(') {
11145
 
        NEXT;
11146
 
        /*
11147
 
         * NodeType or PI search
11148
 
         */
11149
 
        if (xmlStrEqual(name, BAD_CAST "comment"))
11150
 
            *type = NODE_TYPE_COMMENT;
11151
 
        else if (xmlStrEqual(name, BAD_CAST "node"))
11152
 
            *type = NODE_TYPE_NODE;
11153
 
        else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11154
 
            *type = NODE_TYPE_PI;
11155
 
        else if (xmlStrEqual(name, BAD_CAST "text"))
11156
 
            *type = NODE_TYPE_TEXT;
11157
 
        else {
11158
 
            if (name != NULL)
11159
 
                xmlFree(name);
11160
 
            XP_ERRORNULL(XPATH_EXPR_ERROR);
11161
 
        }
11162
 
 
11163
 
        *test = NODE_TEST_TYPE;
11164
 
 
11165
 
        SKIP_BLANKS;
11166
 
        if (*type == NODE_TYPE_PI) {
11167
 
            /*
11168
 
             * Specific case: search a PI by name.
11169
 
             */
11170
 
            if (name != NULL)
11171
 
                xmlFree(name);
11172
 
            name = NULL;
11173
 
            if (CUR != ')') {
11174
 
                name = xmlXPathParseLiteral(ctxt);
11175
 
                CHECK_ERROR NULL;
11176
 
                *test = NODE_TEST_PI;
11177
 
                SKIP_BLANKS;
11178
 
            }
11179
 
        }
11180
 
        if (CUR != ')') {
11181
 
            if (name != NULL)
11182
 
                xmlFree(name);
11183
 
            XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11184
 
        }
11185
 
        NEXT;
11186
 
        return(name);
11187
 
    }
11188
 
    *test = NODE_TEST_NAME;
11189
 
    if ((!blanks) && (CUR == ':')) {
11190
 
        NEXT;
11191
 
 
11192
 
        /*
11193
 
         * Since currently the parser context don't have a
11194
 
         * namespace list associated:
11195
 
         * The namespace name for this prefix can be computed
11196
 
         * only at evaluation time. The compilation is done
11197
 
         * outside of any context.
11198
 
         */
11199
 
#if 0
11200
 
        *prefix = xmlXPathNsLookup(ctxt->context, name);
11201
 
        if (name != NULL)
11202
 
            xmlFree(name);
11203
 
        if (*prefix == NULL) {
11204
 
            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11205
 
        }
11206
 
#else
11207
 
        *prefix = name;
11208
 
#endif
11209
 
 
11210
 
        if (CUR == '*') {
11211
 
            /*
11212
 
             * All elements
11213
 
             */
11214
 
            NEXT;
11215
 
            *test = NODE_TEST_ALL;
11216
 
            return(NULL);
11217
 
        }
11218
 
 
11219
 
        name = xmlXPathParseNCName(ctxt);
11220
 
        if (name == NULL) {
11221
 
            XP_ERRORNULL(XPATH_EXPR_ERROR);
11222
 
        }
11223
 
    }
11224
 
    return(name);
11225
 
}
11226
 
 
11227
 
/**
11228
 
 * xmlXPathIsAxisName:
11229
 
 * @name:  a preparsed name token
11230
 
 *
11231
 
 * [6] AxisName ::=   'ancestor'
11232
 
 *                  | 'ancestor-or-self'
11233
 
 *                  | 'attribute'
11234
 
 *                  | 'child'
11235
 
 *                  | 'descendant'
11236
 
 *                  | 'descendant-or-self'
11237
 
 *                  | 'following'
11238
 
 *                  | 'following-sibling'
11239
 
 *                  | 'namespace'
11240
 
 *                  | 'parent'
11241
 
 *                  | 'preceding'
11242
 
 *                  | 'preceding-sibling'
11243
 
 *                  | 'self'
11244
 
 *
11245
 
 * Returns the axis or 0
11246
 
 */
11247
 
static xmlXPathAxisVal
11248
 
xmlXPathIsAxisName(const xmlChar *name) {
11249
 
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11250
 
    switch (name[0]) {
11251
 
        case 'a':
11252
 
            if (xmlStrEqual(name, BAD_CAST "ancestor"))
11253
 
                ret = AXIS_ANCESTOR;
11254
 
            if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11255
 
                ret = AXIS_ANCESTOR_OR_SELF;
11256
 
            if (xmlStrEqual(name, BAD_CAST "attribute"))
11257
 
                ret = AXIS_ATTRIBUTE;
11258
 
            break;
11259
 
        case 'c':
11260
 
            if (xmlStrEqual(name, BAD_CAST "child"))
11261
 
                ret = AXIS_CHILD;
11262
 
            break;
11263
 
        case 'd':
11264
 
            if (xmlStrEqual(name, BAD_CAST "descendant"))
11265
 
                ret = AXIS_DESCENDANT;
11266
 
            if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11267
 
                ret = AXIS_DESCENDANT_OR_SELF;
11268
 
            break;
11269
 
        case 'f':
11270
 
            if (xmlStrEqual(name, BAD_CAST "following"))
11271
 
                ret = AXIS_FOLLOWING;
11272
 
            if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11273
 
                ret = AXIS_FOLLOWING_SIBLING;
11274
 
            break;
11275
 
        case 'n':
11276
 
            if (xmlStrEqual(name, BAD_CAST "namespace"))
11277
 
                ret = AXIS_NAMESPACE;
11278
 
            break;
11279
 
        case 'p':
11280
 
            if (xmlStrEqual(name, BAD_CAST "parent"))
11281
 
                ret = AXIS_PARENT;
11282
 
            if (xmlStrEqual(name, BAD_CAST "preceding"))
11283
 
                ret = AXIS_PRECEDING;
11284
 
            if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11285
 
                ret = AXIS_PRECEDING_SIBLING;
11286
 
            break;
11287
 
        case 's':
11288
 
            if (xmlStrEqual(name, BAD_CAST "self"))
11289
 
                ret = AXIS_SELF;
11290
 
            break;
11291
 
    }
11292
 
    return(ret);
11293
 
}
11294
 
 
11295
 
/**
11296
 
 * xmlXPathCompStep:
11297
 
 * @ctxt:  the XPath Parser context
11298
 
 *
11299
 
 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11300
 
 *                  | AbbreviatedStep
11301
 
 *
11302
 
 * [12] AbbreviatedStep ::=   '.' | '..'
11303
 
 *
11304
 
 * [5] AxisSpecifier ::= AxisName '::'
11305
 
 *                  | AbbreviatedAxisSpecifier
11306
 
 *
11307
 
 * [13] AbbreviatedAxisSpecifier ::= '@'?
11308
 
 *
11309
 
 * Modified for XPtr range support as:
11310
 
 *
11311
 
 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11312
 
 *                     | AbbreviatedStep
11313
 
 *                     | 'range-to' '(' Expr ')' Predicate*
11314
 
 *
11315
 
 * Compile one step in a Location Path
11316
 
 * A location step of . is short for self::node(). This is
11317
 
 * particularly useful in conjunction with //. For example, the
11318
 
 * location path .//para is short for
11319
 
 * self::node()/descendant-or-self::node()/child::para
11320
 
 * and so will select all para descendant elements of the context
11321
 
 * node.
11322
 
 * Similarly, a location step of .. is short for parent::node().
11323
 
 * For example, ../title is short for parent::node()/child::title
11324
 
 * and so will select the title children of the parent of the context
11325
 
 * node.
11326
 
 */
11327
 
static void
11328
 
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11329
 
#ifdef LIBXML_XPTR_ENABLED
11330
 
    int rangeto = 0;
11331
 
    int op2 = -1;
11332
 
#endif
11333
 
 
11334
 
    SKIP_BLANKS;
11335
 
    if ((CUR == '.') && (NXT(1) == '.')) {
11336
 
        SKIP(2);
11337
 
        SKIP_BLANKS;
11338
 
        PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11339
 
                    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11340
 
    } else if (CUR == '.') {
11341
 
        NEXT;
11342
 
        SKIP_BLANKS;
11343
 
    } else {
11344
 
        xmlChar *name = NULL;
11345
 
        const xmlChar *prefix = NULL;
11346
 
        xmlXPathTestVal test = (xmlXPathTestVal) 0;
11347
 
        xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11348
 
        xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11349
 
        int op1;
11350
 
 
11351
 
        /*
11352
 
         * The modification needed for XPointer change to the production
11353
 
         */
11354
 
#ifdef LIBXML_XPTR_ENABLED
11355
 
        if (ctxt->xptr) {
11356
 
            name = xmlXPathParseNCName(ctxt);
11357
 
            if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11358
 
                op2 = ctxt->comp->last;
11359
 
                xmlFree(name);
11360
 
                SKIP_BLANKS;
11361
 
                if (CUR != '(') {
11362
 
                    XP_ERROR(XPATH_EXPR_ERROR);
11363
 
                }
11364
 
                NEXT;
11365
 
                SKIP_BLANKS;
11366
 
 
11367
 
                xmlXPathCompileExpr(ctxt, 1);
11368
 
                /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11369
 
                CHECK_ERROR;
11370
 
 
11371
 
                SKIP_BLANKS;
11372
 
                if (CUR != ')') {
11373
 
                    XP_ERROR(XPATH_EXPR_ERROR);
11374
 
                }
11375
 
                NEXT;
11376
 
                rangeto = 1;
11377
 
                goto eval_predicates;
11378
 
            }
11379
 
        }
11380
 
#endif
11381
 
        if (CUR == '*') {
11382
 
            axis = AXIS_CHILD;
11383
 
        } else {
11384
 
            if (name == NULL)
11385
 
                name = xmlXPathParseNCName(ctxt);
11386
 
            if (name != NULL) {
11387
 
                axis = xmlXPathIsAxisName(name);
11388
 
                if (axis != 0) {
11389
 
                    SKIP_BLANKS;
11390
 
                    if ((CUR == ':') && (NXT(1) == ':')) {
11391
 
                        SKIP(2);
11392
 
                        xmlFree(name);
11393
 
                        name = NULL;
11394
 
                    } else {
11395
 
                        /* an element name can conflict with an axis one :-\ */
11396
 
                        axis = AXIS_CHILD;
11397
 
                    }
11398
 
                } else {
11399
 
                    axis = AXIS_CHILD;
11400
 
                }
11401
 
            } else if (CUR == '@') {
11402
 
                NEXT;
11403
 
                axis = AXIS_ATTRIBUTE;
11404
 
            } else {
11405
 
                axis = AXIS_CHILD;
11406
 
            }
11407
 
        }
11408
 
 
11409
 
        if (ctxt->error != XPATH_EXPRESSION_OK) {
11410
 
            xmlFree(name);
11411
 
            return;
11412
 
        }
11413
 
 
11414
 
        name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11415
 
        if (test == 0)
11416
 
            return;
11417
 
 
11418
 
        if ((prefix != NULL) && (ctxt->context != NULL) &&
11419
 
            (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11420
 
            if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11421
 
                xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11422
 
            }
11423
 
        }
11424
 
#ifdef DEBUG_STEP
11425
 
        xmlGenericError(xmlGenericErrorContext,
11426
 
                "Basis : computing new set\n");
11427
 
#endif
11428
 
 
11429
 
#ifdef DEBUG_STEP
11430
 
        xmlGenericError(xmlGenericErrorContext, "Basis : ");
11431
 
        if (ctxt->value == NULL)
11432
 
            xmlGenericError(xmlGenericErrorContext, "no value\n");
11433
 
        else if (ctxt->value->nodesetval == NULL)
11434
 
            xmlGenericError(xmlGenericErrorContext, "Empty\n");
11435
 
        else
11436
 
            xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11437
 
#endif
11438
 
 
11439
 
#ifdef LIBXML_XPTR_ENABLED
11440
 
eval_predicates:
11441
 
#endif
11442
 
        op1 = ctxt->comp->last;
11443
 
        ctxt->comp->last = -1;
11444
 
 
11445
 
        SKIP_BLANKS;
11446
 
        while (CUR == '[') {
11447
 
            xmlXPathCompPredicate(ctxt, 0);
11448
 
        }
11449
 
 
11450
 
#ifdef LIBXML_XPTR_ENABLED
11451
 
        if (rangeto) {
11452
 
            PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11453
 
        } else
11454
 
#endif
11455
 
            PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11456
 
                           test, type, (void *)prefix, (void *)name);
11457
 
 
11458
 
    }
11459
 
#ifdef DEBUG_STEP
11460
 
    xmlGenericError(xmlGenericErrorContext, "Step : ");
11461
 
    if (ctxt->value == NULL)
11462
 
        xmlGenericError(xmlGenericErrorContext, "no value\n");
11463
 
    else if (ctxt->value->nodesetval == NULL)
11464
 
        xmlGenericError(xmlGenericErrorContext, "Empty\n");
11465
 
    else
11466
 
        xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11467
 
                ctxt->value->nodesetval);
11468
 
#endif
11469
 
}
11470
 
 
11471
 
/**
11472
 
 * xmlXPathCompRelativeLocationPath:
11473
 
 * @ctxt:  the XPath Parser context
11474
 
 *
11475
 
 *  [3]   RelativeLocationPath ::=   Step
11476
 
 *                     | RelativeLocationPath '/' Step
11477
 
 *                     | AbbreviatedRelativeLocationPath
11478
 
 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11479
 
 *
11480
 
 * Compile a relative location path.
11481
 
 */
11482
 
static void
11483
 
xmlXPathCompRelativeLocationPath
11484
 
(xmlXPathParserContextPtr ctxt) {
11485
 
    SKIP_BLANKS;
11486
 
    if ((CUR == '/') && (NXT(1) == '/')) {
11487
 
        SKIP(2);
11488
 
        SKIP_BLANKS;
11489
 
        PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11490
 
                         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11491
 
    } else if (CUR == '/') {
11492
 
            NEXT;
11493
 
        SKIP_BLANKS;
11494
 
    }
11495
 
    xmlXPathCompStep(ctxt);
11496
 
    CHECK_ERROR;
11497
 
    SKIP_BLANKS;
11498
 
    while (CUR == '/') {
11499
 
        if ((CUR == '/') && (NXT(1) == '/')) {
11500
 
            SKIP(2);
11501
 
            SKIP_BLANKS;
11502
 
            PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11503
 
                             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11504
 
            xmlXPathCompStep(ctxt);
11505
 
        } else if (CUR == '/') {
11506
 
            NEXT;
11507
 
            SKIP_BLANKS;
11508
 
            xmlXPathCompStep(ctxt);
11509
 
        }
11510
 
        SKIP_BLANKS;
11511
 
    }
11512
 
}
11513
 
 
11514
 
/**
11515
 
 * xmlXPathCompLocationPath:
11516
 
 * @ctxt:  the XPath Parser context
11517
 
 *
11518
 
 *  [1]   LocationPath ::=   RelativeLocationPath
11519
 
 *                     | AbsoluteLocationPath
11520
 
 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11521
 
 *                     | AbbreviatedAbsoluteLocationPath
11522
 
 *  [10]   AbbreviatedAbsoluteLocationPath ::=
11523
 
 *                           '//' RelativeLocationPath
11524
 
 *
11525
 
 * Compile a location path
11526
 
 *
11527
 
 * // is short for /descendant-or-self::node()/. For example,
11528
 
 * //para is short for /descendant-or-self::node()/child::para and
11529
 
 * so will select any para element in the document (even a para element
11530
 
 * that is a document element will be selected by //para since the
11531
 
 * document element node is a child of the root node); div//para is
11532
 
 * short for div/descendant-or-self::node()/child::para and so will
11533
 
 * select all para descendants of div children.
11534
 
 */
11535
 
static void
11536
 
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11537
 
    SKIP_BLANKS;
11538
 
    if (CUR != '/') {
11539
 
        xmlXPathCompRelativeLocationPath(ctxt);
11540
 
    } else {
11541
 
        while (CUR == '/') {
11542
 
            if ((CUR == '/') && (NXT(1) == '/')) {
11543
 
                SKIP(2);
11544
 
                SKIP_BLANKS;
11545
 
                PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11546
 
                             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11547
 
                xmlXPathCompRelativeLocationPath(ctxt);
11548
 
            } else if (CUR == '/') {
11549
 
                NEXT;
11550
 
                SKIP_BLANKS;
11551
 
                if ((CUR != 0 ) &&
11552
 
                    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11553
 
                     (CUR == '@') || (CUR == '*')))
11554
 
                    xmlXPathCompRelativeLocationPath(ctxt);
11555
 
            }
11556
 
            CHECK_ERROR;
11557
 
        }
11558
 
    }
11559
 
}
11560
 
 
11561
 
/************************************************************************
11562
 
 *                                                                      *
11563
 
 *              XPath precompiled expression evaluation                 *
11564
 
 *                                                                      *
11565
 
 ************************************************************************/
11566
 
 
11567
 
static int
11568
 
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11569
 
 
11570
 
#ifdef DEBUG_STEP
11571
 
static void
11572
 
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11573
 
                          int nbNodes)
11574
 
{
11575
 
    xmlGenericError(xmlGenericErrorContext, "new step : ");
11576
 
    switch (op->value) {
11577
 
        case AXIS_ANCESTOR:
11578
 
            xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11579
 
            break;
11580
 
        case AXIS_ANCESTOR_OR_SELF:
11581
 
            xmlGenericError(xmlGenericErrorContext,
11582
 
                            "axis 'ancestors-or-self' ");
11583
 
            break;
11584
 
        case AXIS_ATTRIBUTE:
11585
 
            xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11586
 
            break;
11587
 
        case AXIS_CHILD:
11588
 
            xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11589
 
            break;
11590
 
        case AXIS_DESCENDANT:
11591
 
            xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11592
 
            break;
11593
 
        case AXIS_DESCENDANT_OR_SELF:
11594
 
            xmlGenericError(xmlGenericErrorContext,
11595
 
                            "axis 'descendant-or-self' ");
11596
 
            break;
11597
 
        case AXIS_FOLLOWING:
11598
 
            xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11599
 
            break;
11600
 
        case AXIS_FOLLOWING_SIBLING:
11601
 
            xmlGenericError(xmlGenericErrorContext,
11602
 
                            "axis 'following-siblings' ");
11603
 
            break;
11604
 
        case AXIS_NAMESPACE:
11605
 
            xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11606
 
            break;
11607
 
        case AXIS_PARENT:
11608
 
            xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11609
 
            break;
11610
 
        case AXIS_PRECEDING:
11611
 
            xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11612
 
            break;
11613
 
        case AXIS_PRECEDING_SIBLING:
11614
 
            xmlGenericError(xmlGenericErrorContext,
11615
 
                            "axis 'preceding-sibling' ");
11616
 
            break;
11617
 
        case AXIS_SELF:
11618
 
            xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11619
 
            break;
11620
 
    }
11621
 
    xmlGenericError(xmlGenericErrorContext,
11622
 
        " context contains %d nodes\n", nbNodes);
11623
 
    switch (op->value2) {
11624
 
        case NODE_TEST_NONE:
11625
 
            xmlGenericError(xmlGenericErrorContext,
11626
 
                            "           searching for none !!!\n");
11627
 
            break;
11628
 
        case NODE_TEST_TYPE:
11629
 
            xmlGenericError(xmlGenericErrorContext,
11630
 
                            "           searching for type %d\n", op->value3);
11631
 
            break;
11632
 
        case NODE_TEST_PI:
11633
 
            xmlGenericError(xmlGenericErrorContext,
11634
 
                            "           searching for PI !!!\n");
11635
 
            break;
11636
 
        case NODE_TEST_ALL:
11637
 
            xmlGenericError(xmlGenericErrorContext,
11638
 
                            "           searching for *\n");
11639
 
            break;
11640
 
        case NODE_TEST_NS:
11641
 
            xmlGenericError(xmlGenericErrorContext,
11642
 
                            "           searching for namespace %s\n",
11643
 
                            op->value5);
11644
 
            break;
11645
 
        case NODE_TEST_NAME:
11646
 
            xmlGenericError(xmlGenericErrorContext,
11647
 
                            "           searching for name %s\n", op->value5);
11648
 
            if (op->value4)
11649
 
                xmlGenericError(xmlGenericErrorContext,
11650
 
                                "           with namespace %s\n", op->value4);
11651
 
            break;
11652
 
    }
11653
 
    xmlGenericError(xmlGenericErrorContext, "Testing : ");
11654
 
}
11655
 
#endif /* DEBUG_STEP */
11656
 
 
11657
 
static int
11658
 
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11659
 
                            xmlXPathStepOpPtr op,
11660
 
                            xmlNodeSetPtr set,
11661
 
                            int contextSize,
11662
 
                            int hasNsNodes)
11663
 
{
11664
 
    if (op->ch1 != -1) {
11665
 
        xmlXPathCompExprPtr comp = ctxt->comp;
11666
 
        /*
11667
 
        * Process inner predicates first.
11668
 
        */
11669
 
        if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11670
 
            /*
11671
 
            * TODO: raise an internal error.
11672
 
            */
11673
 
        }
11674
 
        contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11675
 
            &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11676
 
        CHECK_ERROR0;
11677
 
        if (contextSize <= 0)
11678
 
            return(0);
11679
 
    }
11680
 
    if (op->ch2 != -1) {
11681
 
        xmlXPathContextPtr xpctxt = ctxt->context;
11682
 
        xmlNodePtr contextNode, oldContextNode;
11683
 
        xmlDocPtr oldContextDoc;
11684
 
        int i, res, contextPos = 0, newContextSize;
11685
 
        xmlXPathStepOpPtr exprOp;
11686
 
        xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11687
 
 
11688
 
#ifdef LIBXML_XPTR_ENABLED
11689
 
        /*
11690
 
        * URGENT TODO: Check the following:
11691
 
        *  We don't expect location sets if evaluating prediates, right?
11692
 
        *  Only filters should expect location sets, right?
11693
 
        */
11694
 
#endif
11695
 
        /*
11696
 
        * SPEC XPath 1.0:
11697
 
        *  "For each node in the node-set to be filtered, the
11698
 
        *  PredicateExpr is evaluated with that node as the
11699
 
        *  context node, with the number of nodes in the
11700
 
        *  node-set as the context size, and with the proximity
11701
 
        *  position of the node in the node-set with respect to
11702
 
        *  the axis as the context position;"
11703
 
        * @oldset is the node-set" to be filtered.
11704
 
        *
11705
 
        * SPEC XPath 1.0:
11706
 
        *  "only predicates change the context position and
11707
 
        *  context size (see [2.4 Predicates])."
11708
 
        * Example:
11709
 
        *   node-set  context pos
11710
 
        *    nA         1
11711
 
        *    nB         2
11712
 
        *    nC         3
11713
 
        *   After applying predicate [position() > 1] :
11714
 
        *   node-set  context pos
11715
 
        *    nB         1
11716
 
        *    nC         2
11717
 
        */
11718
 
        oldContextNode = xpctxt->node;
11719
 
        oldContextDoc = xpctxt->doc;
11720
 
        /*
11721
 
        * Get the expression of this predicate.
11722
 
        */
11723
 
        exprOp = &ctxt->comp->steps[op->ch2];
11724
 
        newContextSize = 0;
11725
 
        for (i = 0; i < set->nodeNr; i++) {
11726
 
            if (set->nodeTab[i] == NULL)
11727
 
                continue;
11728
 
 
11729
 
            contextNode = set->nodeTab[i];
11730
 
            xpctxt->node = contextNode;
11731
 
            xpctxt->contextSize = contextSize;
11732
 
            xpctxt->proximityPosition = ++contextPos;
11733
 
 
11734
 
            /*
11735
 
            * Also set the xpath document in case things like
11736
 
            * key() are evaluated in the predicate.
11737
 
            */
11738
 
            if ((contextNode->type != XML_NAMESPACE_DECL) &&
11739
 
                (contextNode->doc != NULL))
11740
 
                xpctxt->doc = contextNode->doc;
11741
 
            /*
11742
 
            * Evaluate the predicate expression with 1 context node
11743
 
            * at a time; this node is packaged into a node set; this
11744
 
            * node set is handed over to the evaluation mechanism.
11745
 
            */
11746
 
            if (contextObj == NULL)
11747
 
                contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11748
 
            else {
11749
 
                if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11750
 
                    contextNode) < 0) {
11751
 
                    ctxt->error = XPATH_MEMORY_ERROR;
11752
 
                    goto evaluation_exit;
11753
 
                }
11754
 
            }
11755
 
 
11756
 
            valuePush(ctxt, contextObj);
11757
 
 
11758
 
            res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11759
 
 
11760
 
            if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11761
 
                xmlXPathNodeSetClear(set, hasNsNodes);
11762
 
                newContextSize = 0;
11763
 
                goto evaluation_exit;
11764
 
            }
11765
 
 
11766
 
            if (res != 0) {
11767
 
                newContextSize++;
11768
 
            } else {
11769
 
                /*
11770
 
                * Remove the entry from the initial node set.
11771
 
                */
11772
 
                set->nodeTab[i] = NULL;
11773
 
                if (contextNode->type == XML_NAMESPACE_DECL)
11774
 
                    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11775
 
            }
11776
 
            if (ctxt->value == contextObj) {
11777
 
                /*
11778
 
                * Don't free the temporary XPath object holding the
11779
 
                * context node, in order to avoid massive recreation
11780
 
                * inside this loop.
11781
 
                */
11782
 
                valuePop(ctxt);
11783
 
                xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11784
 
            } else {
11785
 
                /*
11786
 
                * TODO: The object was lost in the evaluation machinery.
11787
 
                *  Can this happen? Maybe in internal-error cases.
11788
 
                */
11789
 
                contextObj = NULL;
11790
 
            }
11791
 
        }
11792
 
 
11793
 
        if (contextObj != NULL) {
11794
 
            if (ctxt->value == contextObj)
11795
 
                valuePop(ctxt);
11796
 
            xmlXPathReleaseObject(xpctxt, contextObj);
11797
 
        }
11798
 
evaluation_exit:
11799
 
        if (exprRes != NULL)
11800
 
            xmlXPathReleaseObject(ctxt->context, exprRes);
11801
 
        /*
11802
 
        * Reset/invalidate the context.
11803
 
        */
11804
 
        xpctxt->node = oldContextNode;
11805
 
        xpctxt->doc = oldContextDoc;
11806
 
        xpctxt->contextSize = -1;
11807
 
        xpctxt->proximityPosition = -1;
11808
 
        return(newContextSize);
11809
 
    }
11810
 
    return(contextSize);
11811
 
}
11812
 
 
11813
 
static int
11814
 
xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11815
 
                                      xmlXPathStepOpPtr op,
11816
 
                                      xmlNodeSetPtr set,
11817
 
                                      int contextSize,
11818
 
                                      int minPos,
11819
 
                                      int maxPos,
11820
 
                                      int hasNsNodes)
11821
 
{
11822
 
    if (op->ch1 != -1) {
11823
 
        xmlXPathCompExprPtr comp = ctxt->comp;
11824
 
        if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11825
 
            /*
11826
 
            * TODO: raise an internal error.
11827
 
            */
11828
 
        }
11829
 
        contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11830
 
            &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11831
 
        CHECK_ERROR0;
11832
 
        if (contextSize <= 0)
11833
 
            return(0);
11834
 
    }
11835
 
    /*
11836
 
    * Check if the node set contains a sufficient number of nodes for
11837
 
    * the requested range.
11838
 
    */
11839
 
    if (contextSize < minPos) {
11840
 
        xmlXPathNodeSetClear(set, hasNsNodes);
11841
 
        return(0);
11842
 
    }
11843
 
    if (op->ch2 == -1) {
11844
 
        /*
11845
 
        * TODO: Can this ever happen?
11846
 
        */
11847
 
        return (contextSize);
11848
 
    } else {
11849
 
        xmlDocPtr oldContextDoc;
11850
 
        int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11851
 
        xmlXPathStepOpPtr exprOp;
11852
 
        xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11853
 
        xmlNodePtr oldContextNode, contextNode = NULL;
11854
 
        xmlXPathContextPtr xpctxt = ctxt->context;
11855
 
        int frame;
11856
 
 
11857
 
#ifdef LIBXML_XPTR_ENABLED
11858
 
            /*
11859
 
            * URGENT TODO: Check the following:
11860
 
            *  We don't expect location sets if evaluating prediates, right?
11861
 
            *  Only filters should expect location sets, right?
11862
 
        */
11863
 
#endif /* LIBXML_XPTR_ENABLED */
11864
 
 
11865
 
        /*
11866
 
        * Save old context.
11867
 
        */
11868
 
        oldContextNode = xpctxt->node;
11869
 
        oldContextDoc = xpctxt->doc;
11870
 
        /*
11871
 
        * Get the expression of this predicate.
11872
 
        */
11873
 
        exprOp = &ctxt->comp->steps[op->ch2];
11874
 
        for (i = 0; i < set->nodeNr; i++) {
11875
 
            xmlXPathObjectPtr tmp;
11876
 
 
11877
 
            if (set->nodeTab[i] == NULL)
11878
 
                continue;
11879
 
 
11880
 
            contextNode = set->nodeTab[i];
11881
 
            xpctxt->node = contextNode;
11882
 
            xpctxt->contextSize = contextSize;
11883
 
            xpctxt->proximityPosition = ++contextPos;
11884
 
 
11885
 
            /*
11886
 
            * Initialize the new set.
11887
 
            * Also set the xpath document in case things like
11888
 
            * key() evaluation are attempted on the predicate
11889
 
            */
11890
 
            if ((contextNode->type != XML_NAMESPACE_DECL) &&
11891
 
                (contextNode->doc != NULL))
11892
 
                xpctxt->doc = contextNode->doc;
11893
 
            /*
11894
 
            * Evaluate the predicate expression with 1 context node
11895
 
            * at a time; this node is packaged into a node set; this
11896
 
            * node set is handed over to the evaluation mechanism.
11897
 
            */
11898
 
            if (contextObj == NULL)
11899
 
                contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11900
 
            else {
11901
 
                if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11902
 
                    contextNode) < 0) {
11903
 
                    ctxt->error = XPATH_MEMORY_ERROR;
11904
 
                    goto evaluation_exit;
11905
 
                }
11906
 
            }
11907
 
 
11908
 
            frame = xmlXPathSetFrame(ctxt);
11909
 
            valuePush(ctxt, contextObj);
11910
 
            res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11911
 
            tmp = valuePop(ctxt);
11912
 
            xmlXPathPopFrame(ctxt, frame);
11913
 
 
11914
 
            if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11915
 
                while (tmp != contextObj) {
11916
 
                    /*
11917
 
                     * Free up the result
11918
 
                     * then pop off contextObj, which will be freed later
11919
 
                     */
11920
 
                    xmlXPathReleaseObject(xpctxt, tmp);
11921
 
                    tmp = valuePop(ctxt);
11922
 
                }
11923
 
                goto evaluation_error;
11924
 
            }
11925
 
            /* push the result back onto the stack */
11926
 
            valuePush(ctxt, tmp);
11927
 
 
11928
 
            if (res)
11929
 
                pos++;
11930
 
 
11931
 
            if (res && (pos >= minPos) && (pos <= maxPos)) {
11932
 
                /*
11933
 
                * Fits in the requested range.
11934
 
                */
11935
 
                newContextSize++;
11936
 
                if (minPos == maxPos) {
11937
 
                    /*
11938
 
                    * Only 1 node was requested.
11939
 
                    */
11940
 
                    if (contextNode->type == XML_NAMESPACE_DECL) {
11941
 
                        /*
11942
 
                        * As always: take care of those nasty
11943
 
                        * namespace nodes.
11944
 
                        */
11945
 
                        set->nodeTab[i] = NULL;
11946
 
                    }
11947
 
                    xmlXPathNodeSetClear(set, hasNsNodes);
11948
 
                    set->nodeNr = 1;
11949
 
                    set->nodeTab[0] = contextNode;
11950
 
                    goto evaluation_exit;
11951
 
                }
11952
 
                if (pos == maxPos) {
11953
 
                    /*
11954
 
                    * We are done.
11955
 
                    */
11956
 
                    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11957
 
                    goto evaluation_exit;
11958
 
                }
11959
 
            } else {
11960
 
                /*
11961
 
                * Remove the entry from the initial node set.
11962
 
                */
11963
 
                set->nodeTab[i] = NULL;
11964
 
                if (contextNode->type == XML_NAMESPACE_DECL)
11965
 
                    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11966
 
            }
11967
 
            if (exprRes != NULL) {
11968
 
                xmlXPathReleaseObject(ctxt->context, exprRes);
11969
 
                exprRes = NULL;
11970
 
            }
11971
 
            if (ctxt->value == contextObj) {
11972
 
                /*
11973
 
                * Don't free the temporary XPath object holding the
11974
 
                * context node, in order to avoid massive recreation
11975
 
                * inside this loop.
11976
 
                */
11977
 
                valuePop(ctxt);
11978
 
                xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11979
 
            } else {
11980
 
                /*
11981
 
                * The object was lost in the evaluation machinery.
11982
 
                * Can this happen? Maybe in case of internal-errors.
11983
 
                */
11984
 
                contextObj = NULL;
11985
 
            }
11986
 
        }
11987
 
        goto evaluation_exit;
11988
 
 
11989
 
evaluation_error:
11990
 
        xmlXPathNodeSetClear(set, hasNsNodes);
11991
 
        newContextSize = 0;
11992
 
 
11993
 
evaluation_exit:
11994
 
        if (contextObj != NULL) {
11995
 
            if (ctxt->value == contextObj)
11996
 
                valuePop(ctxt);
11997
 
            xmlXPathReleaseObject(xpctxt, contextObj);
11998
 
        }
11999
 
        if (exprRes != NULL)
12000
 
            xmlXPathReleaseObject(ctxt->context, exprRes);
12001
 
        /*
12002
 
        * Reset/invalidate the context.
12003
 
        */
12004
 
        xpctxt->node = oldContextNode;
12005
 
        xpctxt->doc = oldContextDoc;
12006
 
        xpctxt->contextSize = -1;
12007
 
        xpctxt->proximityPosition = -1;
12008
 
        return(newContextSize);
12009
 
    }
12010
 
    return(contextSize);
12011
 
}
12012
 
 
12013
 
static int
12014
 
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
12015
 
                            xmlXPathStepOpPtr op,
12016
 
                            int *maxPos)
12017
 
{
12018
 
 
12019
 
    xmlXPathStepOpPtr exprOp;
12020
 
 
12021
 
    /*
12022
 
    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12023
 
    */
12024
 
 
12025
 
    /*
12026
 
    * If not -1, then ch1 will point to:
12027
 
    * 1) For predicates (XPATH_OP_PREDICATE):
12028
 
    *    - an inner predicate operator
12029
 
    * 2) For filters (XPATH_OP_FILTER):
12030
 
    *    - an inner filter operater OR
12031
 
    *    - an expression selecting the node set.
12032
 
    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
12033
 
    */
12034
 
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12035
 
        return(0);
12036
 
 
12037
 
    if (op->ch2 != -1) {
12038
 
        exprOp = &ctxt->comp->steps[op->ch2];
12039
 
    } else
12040
 
        return(0);
12041
 
 
12042
 
    if ((exprOp != NULL) &&
12043
 
        (exprOp->op == XPATH_OP_VALUE) &&
12044
 
        (exprOp->value4 != NULL) &&
12045
 
        (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12046
 
    {
12047
 
        /*
12048
 
        * We have a "[n]" predicate here.
12049
 
        * TODO: Unfortunately this simplistic test here is not
12050
 
        * able to detect a position() predicate in compound
12051
 
        * expressions like "[@attr = 'a" and position() = 1],
12052
 
        * and even not the usage of position() in
12053
 
        * "[position() = 1]"; thus - obviously - a position-range,
12054
 
        * like it "[position() < 5]", is also not detected.
12055
 
        * Maybe we could rewrite the AST to ease the optimization.
12056
 
        */
12057
 
        *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
12058
 
 
12059
 
        if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
12060
 
            (float) *maxPos)
12061
 
        {
12062
 
            return(1);
12063
 
        }
12064
 
    }
12065
 
    return(0);
12066
 
}
12067
 
 
12068
 
static int
12069
 
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12070
 
                           xmlXPathStepOpPtr op,
12071
 
                           xmlNodePtr * first, xmlNodePtr * last,
12072
 
                           int toBool)
12073
 
{
12074
 
 
12075
 
#define XP_TEST_HIT \
12076
 
    if (hasAxisRange != 0) { \
12077
 
        if (++pos == maxPos) { \
12078
 
            if (addNode(seq, cur) < 0) \
12079
 
                ctxt->error = XPATH_MEMORY_ERROR; \
12080
 
            goto axis_range_end; } \
12081
 
    } else { \
12082
 
        if (addNode(seq, cur) < 0) \
12083
 
            ctxt->error = XPATH_MEMORY_ERROR; \
12084
 
        if (breakOnFirstHit) goto first_hit; }
12085
 
 
12086
 
#define XP_TEST_HIT_NS \
12087
 
    if (hasAxisRange != 0) { \
12088
 
        if (++pos == maxPos) { \
12089
 
            hasNsNodes = 1; \
12090
 
            if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12091
 
                ctxt->error = XPATH_MEMORY_ERROR; \
12092
 
        goto axis_range_end; } \
12093
 
    } else { \
12094
 
        hasNsNodes = 1; \
12095
 
        if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12096
 
            ctxt->error = XPATH_MEMORY_ERROR; \
12097
 
        if (breakOnFirstHit) goto first_hit; }
12098
 
 
12099
 
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12100
 
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12101
 
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12102
 
    const xmlChar *prefix = op->value4;
12103
 
    const xmlChar *name = op->value5;
12104
 
    const xmlChar *URI = NULL;
12105
 
 
12106
 
#ifdef DEBUG_STEP
12107
 
    int nbMatches = 0, prevMatches = 0;
12108
 
#endif
12109
 
    int total = 0, hasNsNodes = 0;
12110
 
    /* The popped object holding the context nodes */
12111
 
    xmlXPathObjectPtr obj;
12112
 
    /* The set of context nodes for the node tests */
12113
 
    xmlNodeSetPtr contextSeq;
12114
 
    int contextIdx;
12115
 
    xmlNodePtr contextNode;
12116
 
    /* The final resulting node set wrt to all context nodes */
12117
 
    xmlNodeSetPtr outSeq;
12118
 
    /*
12119
 
    * The temporary resulting node set wrt 1 context node.
12120
 
    * Used to feed predicate evaluation.
12121
 
    */
12122
 
    xmlNodeSetPtr seq;
12123
 
    xmlNodePtr cur;
12124
 
    /* First predicate operator */
12125
 
    xmlXPathStepOpPtr predOp;
12126
 
    int maxPos; /* The requested position() (when a "[n]" predicate) */
12127
 
    int hasPredicateRange, hasAxisRange, pos, size, newSize;
12128
 
    int breakOnFirstHit;
12129
 
 
12130
 
    xmlXPathTraversalFunction next = NULL;
12131
 
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12132
 
    xmlXPathNodeSetMergeFunction mergeAndClear;
12133
 
    xmlNodePtr oldContextNode;
12134
 
    xmlXPathContextPtr xpctxt = ctxt->context;
12135
 
 
12136
 
 
12137
 
    CHECK_TYPE0(XPATH_NODESET);
12138
 
    obj = valuePop(ctxt);
12139
 
    /*
12140
 
    * Setup namespaces.
12141
 
    */
12142
 
    if (prefix != NULL) {
12143
 
        URI = xmlXPathNsLookup(xpctxt, prefix);
12144
 
        if (URI == NULL) {
12145
 
            xmlXPathReleaseObject(xpctxt, obj);
12146
 
            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12147
 
        }
12148
 
    }
12149
 
    /*
12150
 
    * Setup axis.
12151
 
    *
12152
 
    * MAYBE FUTURE TODO: merging optimizations:
12153
 
    * - If the nodes to be traversed wrt to the initial nodes and
12154
 
    *   the current axis cannot overlap, then we could avoid searching
12155
 
    *   for duplicates during the merge.
12156
 
    *   But the question is how/when to evaluate if they cannot overlap.
12157
 
    *   Example: if we know that for two initial nodes, the one is
12158
 
    *   not in the ancestor-or-self axis of the other, then we could safely
12159
 
    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12160
 
    *   the descendant-or-self axis.
12161
 
    */
12162
 
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
12163
 
    switch (axis) {
12164
 
        case AXIS_ANCESTOR:
12165
 
            first = NULL;
12166
 
            next = xmlXPathNextAncestor;
12167
 
            break;
12168
 
        case AXIS_ANCESTOR_OR_SELF:
12169
 
            first = NULL;
12170
 
            next = xmlXPathNextAncestorOrSelf;
12171
 
            break;
12172
 
        case AXIS_ATTRIBUTE:
12173
 
            first = NULL;
12174
 
            last = NULL;
12175
 
            next = xmlXPathNextAttribute;
12176
 
            mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12177
 
            break;
12178
 
        case AXIS_CHILD:
12179
 
            last = NULL;
12180
 
            if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12181
 
                (type == NODE_TYPE_NODE))
12182
 
            {
12183
 
                /*
12184
 
                * Optimization if an element node type is 'element'.
12185
 
                */
12186
 
                next = xmlXPathNextChildElement;
12187
 
            } else
12188
 
                next = xmlXPathNextChild;
12189
 
            mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12190
 
            break;
12191
 
        case AXIS_DESCENDANT:
12192
 
            last = NULL;
12193
 
            next = xmlXPathNextDescendant;
12194
 
            break;
12195
 
        case AXIS_DESCENDANT_OR_SELF:
12196
 
            last = NULL;
12197
 
            next = xmlXPathNextDescendantOrSelf;
12198
 
            break;
12199
 
        case AXIS_FOLLOWING:
12200
 
            last = NULL;
12201
 
            next = xmlXPathNextFollowing;
12202
 
            break;
12203
 
        case AXIS_FOLLOWING_SIBLING:
12204
 
            last = NULL;
12205
 
            next = xmlXPathNextFollowingSibling;
12206
 
            break;
12207
 
        case AXIS_NAMESPACE:
12208
 
            first = NULL;
12209
 
            last = NULL;
12210
 
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12211
 
            mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12212
 
            break;
12213
 
        case AXIS_PARENT:
12214
 
            first = NULL;
12215
 
            next = xmlXPathNextParent;
12216
 
            break;
12217
 
        case AXIS_PRECEDING:
12218
 
            first = NULL;
12219
 
            next = xmlXPathNextPrecedingInternal;
12220
 
            break;
12221
 
        case AXIS_PRECEDING_SIBLING:
12222
 
            first = NULL;
12223
 
            next = xmlXPathNextPrecedingSibling;
12224
 
            break;
12225
 
        case AXIS_SELF:
12226
 
            first = NULL;
12227
 
            last = NULL;
12228
 
            next = xmlXPathNextSelf;
12229
 
            mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12230
 
            break;
12231
 
    }
12232
 
 
12233
 
#ifdef DEBUG_STEP
12234
 
    xmlXPathDebugDumpStepAxis(op,
12235
 
        (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12236
 
#endif
12237
 
 
12238
 
    if (next == NULL) {
12239
 
        xmlXPathReleaseObject(xpctxt, obj);
12240
 
        return(0);
12241
 
    }
12242
 
    contextSeq = obj->nodesetval;
12243
 
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12244
 
        xmlXPathReleaseObject(xpctxt, obj);
12245
 
        valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12246
 
        return(0);
12247
 
    }
12248
 
    /*
12249
 
    * Predicate optimization ---------------------------------------------
12250
 
    * If this step has a last predicate, which contains a position(),
12251
 
    * then we'll optimize (although not exactly "position()", but only
12252
 
    * the  short-hand form, i.e., "[n]".
12253
 
    *
12254
 
    * Example - expression "/foo[parent::bar][1]":
12255
 
    *
12256
 
    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12257
 
    *   ROOT                               -- op->ch1
12258
 
    *   PREDICATE                          -- op->ch2 (predOp)
12259
 
    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12260
 
    *       SORT
12261
 
    *         COLLECT  'parent' 'name' 'node' bar
12262
 
    *           NODE
12263
 
    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12264
 
    *
12265
 
    */
12266
 
    maxPos = 0;
12267
 
    predOp = NULL;
12268
 
    hasPredicateRange = 0;
12269
 
    hasAxisRange = 0;
12270
 
    if (op->ch2 != -1) {
12271
 
        /*
12272
 
        * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12273
 
        */
12274
 
        predOp = &ctxt->comp->steps[op->ch2];
12275
 
        if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12276
 
            if (predOp->ch1 != -1) {
12277
 
                /*
12278
 
                * Use the next inner predicate operator.
12279
 
                */
12280
 
                predOp = &ctxt->comp->steps[predOp->ch1];
12281
 
                hasPredicateRange = 1;
12282
 
            } else {
12283
 
                /*
12284
 
                * There's no other predicate than the [n] predicate.
12285
 
                */
12286
 
                predOp = NULL;
12287
 
                hasAxisRange = 1;
12288
 
            }
12289
 
        }
12290
 
    }
12291
 
    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12292
 
    /*
12293
 
    * Axis traversal -----------------------------------------------------
12294
 
    */
12295
 
    /*
12296
 
     * 2.3 Node Tests
12297
 
     *  - For the attribute axis, the principal node type is attribute.
12298
 
     *  - For the namespace axis, the principal node type is namespace.
12299
 
     *  - For other axes, the principal node type is element.
12300
 
     *
12301
 
     * A node test * is true for any node of the
12302
 
     * principal node type. For example, child::* will
12303
 
     * select all element children of the context node
12304
 
     */
12305
 
    oldContextNode = xpctxt->node;
12306
 
    addNode = xmlXPathNodeSetAddUnique;
12307
 
    outSeq = NULL;
12308
 
    seq = NULL;
12309
 
    contextNode = NULL;
12310
 
    contextIdx = 0;
12311
 
 
12312
 
 
12313
 
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12314
 
           (ctxt->error == XPATH_EXPRESSION_OK)) {
12315
 
        xpctxt->node = contextSeq->nodeTab[contextIdx++];
12316
 
 
12317
 
        if (seq == NULL) {
12318
 
            seq = xmlXPathNodeSetCreate(NULL);
12319
 
            if (seq == NULL) {
12320
 
                total = 0;
12321
 
                goto error;
12322
 
            }
12323
 
        }
12324
 
        /*
12325
 
        * Traverse the axis and test the nodes.
12326
 
        */
12327
 
        pos = 0;
12328
 
        cur = NULL;
12329
 
        hasNsNodes = 0;
12330
 
        do {
12331
 
            cur = next(ctxt, cur);
12332
 
            if (cur == NULL)
12333
 
                break;
12334
 
 
12335
 
            /*
12336
 
            * QUESTION TODO: What does the "first" and "last" stuff do?
12337
 
            */
12338
 
            if ((first != NULL) && (*first != NULL)) {
12339
 
                if (*first == cur)
12340
 
                    break;
12341
 
                if (((total % 256) == 0) &&
12342
 
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12343
 
                    (xmlXPathCmpNodesExt(*first, cur) >= 0))
12344
 
#else
12345
 
                    (xmlXPathCmpNodes(*first, cur) >= 0))
12346
 
#endif
12347
 
                {
12348
 
                    break;
12349
 
                }
12350
 
            }
12351
 
            if ((last != NULL) && (*last != NULL)) {
12352
 
                if (*last == cur)
12353
 
                    break;
12354
 
                if (((total % 256) == 0) &&
12355
 
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12356
 
                    (xmlXPathCmpNodesExt(cur, *last) >= 0))
12357
 
#else
12358
 
                    (xmlXPathCmpNodes(cur, *last) >= 0))
12359
 
#endif
12360
 
                {
12361
 
                    break;
12362
 
                }
12363
 
            }
12364
 
 
12365
 
            total++;
12366
 
 
12367
 
#ifdef DEBUG_STEP
12368
 
            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12369
 
#endif
12370
 
 
12371
 
            switch (test) {
12372
 
                case NODE_TEST_NONE:
12373
 
                    total = 0;
12374
 
                    STRANGE
12375
 
                    goto error;
12376
 
                case NODE_TEST_TYPE:
12377
 
                    /*
12378
 
                    * TODO: Don't we need to use
12379
 
                    *  xmlXPathNodeSetAddNs() for namespace nodes here?
12380
 
                    *  Surprisingly, some c14n tests fail, if we do this.
12381
 
                    */
12382
 
                    if (type == NODE_TYPE_NODE) {
12383
 
                        switch (cur->type) {
12384
 
                            case XML_DOCUMENT_NODE:
12385
 
                            case XML_HTML_DOCUMENT_NODE:
12386
 
#ifdef LIBXML_DOCB_ENABLED
12387
 
                            case XML_DOCB_DOCUMENT_NODE:
12388
 
#endif
12389
 
                            case XML_ELEMENT_NODE:
12390
 
                            case XML_ATTRIBUTE_NODE:
12391
 
                            case XML_PI_NODE:
12392
 
                            case XML_COMMENT_NODE:
12393
 
                            case XML_CDATA_SECTION_NODE:
12394
 
                            case XML_TEXT_NODE:
12395
 
                            case XML_NAMESPACE_DECL:
12396
 
                                XP_TEST_HIT
12397
 
                                break;
12398
 
                            default:
12399
 
                                break;
12400
 
                        }
12401
 
                    } else if (cur->type == type) {
12402
 
                        if (cur->type == XML_NAMESPACE_DECL)
12403
 
                            XP_TEST_HIT_NS
12404
 
                        else
12405
 
                            XP_TEST_HIT
12406
 
                    } else if ((type == NODE_TYPE_TEXT) &&
12407
 
                         (cur->type == XML_CDATA_SECTION_NODE))
12408
 
                    {
12409
 
                        XP_TEST_HIT
12410
 
                    }
12411
 
                    break;
12412
 
                case NODE_TEST_PI:
12413
 
                    if ((cur->type == XML_PI_NODE) &&
12414
 
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
12415
 
                    {
12416
 
                        XP_TEST_HIT
12417
 
                    }
12418
 
                    break;
12419
 
                case NODE_TEST_ALL:
12420
 
                    if (axis == AXIS_ATTRIBUTE) {
12421
 
                        if (cur->type == XML_ATTRIBUTE_NODE)
12422
 
                        {
12423
 
                            XP_TEST_HIT
12424
 
                        }
12425
 
                    } else if (axis == AXIS_NAMESPACE) {
12426
 
                        if (cur->type == XML_NAMESPACE_DECL)
12427
 
                        {
12428
 
                            XP_TEST_HIT_NS
12429
 
                        }
12430
 
                    } else {
12431
 
                        if (cur->type == XML_ELEMENT_NODE) {
12432
 
                            if (prefix == NULL)
12433
 
                            {
12434
 
                                XP_TEST_HIT
12435
 
 
12436
 
                            } else if ((cur->ns != NULL) &&
12437
 
                                (xmlStrEqual(URI, cur->ns->href)))
12438
 
                            {
12439
 
                                XP_TEST_HIT
12440
 
                            }
12441
 
                        }
12442
 
                    }
12443
 
                    break;
12444
 
                case NODE_TEST_NS:{
12445
 
                        TODO;
12446
 
                        break;
12447
 
                    }
12448
 
                case NODE_TEST_NAME:
12449
 
                    if (axis == AXIS_ATTRIBUTE) {
12450
 
                        if (cur->type != XML_ATTRIBUTE_NODE)
12451
 
                            break;
12452
 
                    } else if (axis == AXIS_NAMESPACE) {
12453
 
                        if (cur->type != XML_NAMESPACE_DECL)
12454
 
                            break;
12455
 
                    } else {
12456
 
                        if (cur->type != XML_ELEMENT_NODE)
12457
 
                            break;
12458
 
                    }
12459
 
                    switch (cur->type) {
12460
 
                        case XML_ELEMENT_NODE:
12461
 
                            if (xmlStrEqual(name, cur->name)) {
12462
 
                                if (prefix == NULL) {
12463
 
                                    if (cur->ns == NULL)
12464
 
                                    {
12465
 
                                        XP_TEST_HIT
12466
 
                                    }
12467
 
                                } else {
12468
 
                                    if ((cur->ns != NULL) &&
12469
 
                                        (xmlStrEqual(URI, cur->ns->href)))
12470
 
                                    {
12471
 
                                        XP_TEST_HIT
12472
 
                                    }
12473
 
                                }
12474
 
                            }
12475
 
                            break;
12476
 
                        case XML_ATTRIBUTE_NODE:{
12477
 
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
12478
 
 
12479
 
                                if (xmlStrEqual(name, attr->name)) {
12480
 
                                    if (prefix == NULL) {
12481
 
                                        if ((attr->ns == NULL) ||
12482
 
                                            (attr->ns->prefix == NULL))
12483
 
                                        {
12484
 
                                            XP_TEST_HIT
12485
 
                                        }
12486
 
                                    } else {
12487
 
                                        if ((attr->ns != NULL) &&
12488
 
                                            (xmlStrEqual(URI,
12489
 
                                              attr->ns->href)))
12490
 
                                        {
12491
 
                                            XP_TEST_HIT
12492
 
                                        }
12493
 
                                    }
12494
 
                                }
12495
 
                                break;
12496
 
                            }
12497
 
                        case XML_NAMESPACE_DECL:
12498
 
                            if (cur->type == XML_NAMESPACE_DECL) {
12499
 
                                xmlNsPtr ns = (xmlNsPtr) cur;
12500
 
 
12501
 
                                if ((ns->prefix != NULL) && (name != NULL)
12502
 
                                    && (xmlStrEqual(ns->prefix, name)))
12503
 
                                {
12504
 
                                    XP_TEST_HIT_NS
12505
 
                                }
12506
 
                            }
12507
 
                            break;
12508
 
                        default:
12509
 
                            break;
12510
 
                    }
12511
 
                    break;
12512
 
            } /* switch(test) */
12513
 
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12514
 
 
12515
 
        goto apply_predicates;
12516
 
 
12517
 
axis_range_end: /* ----------------------------------------------------- */
12518
 
        /*
12519
 
        * We have a "/foo[n]", and position() = n was reached.
12520
 
        * Note that we can have as well "/foo/::parent::foo[1]", so
12521
 
        * a duplicate-aware merge is still needed.
12522
 
        * Merge with the result.
12523
 
        */
12524
 
        if (outSeq == NULL) {
12525
 
            outSeq = seq;
12526
 
            seq = NULL;
12527
 
        } else
12528
 
            outSeq = mergeAndClear(outSeq, seq, 0);
12529
 
        /*
12530
 
        * Break if only a true/false result was requested.
12531
 
        */
12532
 
        if (toBool)
12533
 
            break;
12534
 
        continue;
12535
 
 
12536
 
first_hit: /* ---------------------------------------------------------- */
12537
 
        /*
12538
 
        * Break if only a true/false result was requested and
12539
 
        * no predicates existed and a node test succeeded.
12540
 
        */
12541
 
        if (outSeq == NULL) {
12542
 
            outSeq = seq;
12543
 
            seq = NULL;
12544
 
        } else
12545
 
            outSeq = mergeAndClear(outSeq, seq, 0);
12546
 
        break;
12547
 
 
12548
 
#ifdef DEBUG_STEP
12549
 
        if (seq != NULL)
12550
 
            nbMatches += seq->nodeNr;
12551
 
#endif
12552
 
 
12553
 
apply_predicates: /* --------------------------------------------------- */
12554
 
        if (ctxt->error != XPATH_EXPRESSION_OK)
12555
 
            goto error;
12556
 
 
12557
 
        /*
12558
 
        * Apply predicates.
12559
 
        */
12560
 
        if ((predOp != NULL) && (seq->nodeNr > 0)) {
12561
 
            /*
12562
 
            * E.g. when we have a "/foo[some expression][n]".
12563
 
            */
12564
 
            /*
12565
 
            * QUESTION TODO: The old predicate evaluation took into
12566
 
            *  account location-sets.
12567
 
            *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12568
 
            *  Do we expect such a set here?
12569
 
            *  All what I learned now from the evaluation semantics
12570
 
            *  does not indicate that a location-set will be processed
12571
 
            *  here, so this looks OK.
12572
 
            */
12573
 
            /*
12574
 
            * Iterate over all predicates, starting with the outermost
12575
 
            * predicate.
12576
 
            * TODO: Problem: we cannot execute the inner predicates first
12577
 
            *  since we cannot go back *up* the operator tree!
12578
 
            *  Options we have:
12579
 
            *  1) Use of recursive functions (like is it currently done
12580
 
            *     via xmlXPathCompOpEval())
12581
 
            *  2) Add a predicate evaluation information stack to the
12582
 
            *     context struct
12583
 
            *  3) Change the way the operators are linked; we need a
12584
 
            *     "parent" field on xmlXPathStepOp
12585
 
            *
12586
 
            * For the moment, I'll try to solve this with a recursive
12587
 
            * function: xmlXPathCompOpEvalPredicate().
12588
 
            */
12589
 
            size = seq->nodeNr;
12590
 
            if (hasPredicateRange != 0)
12591
 
                newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12592
 
                    predOp, seq, size, maxPos, maxPos, hasNsNodes);
12593
 
            else
12594
 
                newSize = xmlXPathCompOpEvalPredicate(ctxt,
12595
 
                    predOp, seq, size, hasNsNodes);
12596
 
 
12597
 
            if (ctxt->error != XPATH_EXPRESSION_OK) {
12598
 
                total = 0;
12599
 
                goto error;
12600
 
            }
12601
 
            /*
12602
 
            * Add the filtered set of nodes to the result node set.
12603
 
            */
12604
 
            if (newSize == 0) {
12605
 
                /*
12606
 
                * The predicates filtered all nodes out.
12607
 
                */
12608
 
                xmlXPathNodeSetClear(seq, hasNsNodes);
12609
 
            } else if (seq->nodeNr > 0) {
12610
 
                /*
12611
 
                * Add to result set.
12612
 
                */
12613
 
                if (outSeq == NULL) {
12614
 
                    if (size != newSize) {
12615
 
                        /*
12616
 
                        * We need to merge and clear here, since
12617
 
                        * the sequence will contained NULLed entries.
12618
 
                        */
12619
 
                        outSeq = mergeAndClear(NULL, seq, 1);
12620
 
                    } else {
12621
 
                        outSeq = seq;
12622
 
                        seq = NULL;
12623
 
                    }
12624
 
                } else
12625
 
                    outSeq = mergeAndClear(outSeq, seq,
12626
 
                        (size != newSize) ? 1: 0);
12627
 
                /*
12628
 
                * Break if only a true/false result was requested.
12629
 
                */
12630
 
                if (toBool)
12631
 
                    break;
12632
 
            }
12633
 
        } else if (seq->nodeNr > 0) {
12634
 
            /*
12635
 
            * Add to result set.
12636
 
            */
12637
 
            if (outSeq == NULL) {
12638
 
                outSeq = seq;
12639
 
                seq = NULL;
12640
 
            } else {
12641
 
                outSeq = mergeAndClear(outSeq, seq, 0);
12642
 
            }
12643
 
        }
12644
 
    }
12645
 
 
12646
 
error:
12647
 
    if ((obj->boolval) && (obj->user != NULL)) {
12648
 
        /*
12649
 
        * QUESTION TODO: What does this do and why?
12650
 
        * TODO: Do we have to do this also for the "error"
12651
 
        * cleanup further down?
12652
 
        */
12653
 
        ctxt->value->boolval = 1;
12654
 
        ctxt->value->user = obj->user;
12655
 
        obj->user = NULL;
12656
 
        obj->boolval = 0;
12657
 
    }
12658
 
    xmlXPathReleaseObject(xpctxt, obj);
12659
 
 
12660
 
    /*
12661
 
    * Ensure we return at least an emtpy set.
12662
 
    */
12663
 
    if (outSeq == NULL) {
12664
 
        if ((seq != NULL) && (seq->nodeNr == 0))
12665
 
            outSeq = seq;
12666
 
        else
12667
 
            outSeq = xmlXPathNodeSetCreate(NULL);
12668
 
        /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12669
 
    }
12670
 
    if ((seq != NULL) && (seq != outSeq)) {
12671
 
         xmlXPathFreeNodeSet(seq);
12672
 
    }
12673
 
    /*
12674
 
    * Hand over the result. Better to push the set also in
12675
 
    * case of errors.
12676
 
    */
12677
 
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12678
 
    /*
12679
 
    * Reset the context node.
12680
 
    */
12681
 
    xpctxt->node = oldContextNode;
12682
 
 
12683
 
#ifdef DEBUG_STEP
12684
 
    xmlGenericError(xmlGenericErrorContext,
12685
 
        "\nExamined %d nodes, found %d nodes at that step\n",
12686
 
        total, nbMatches);
12687
 
#endif
12688
 
 
12689
 
    return(total);
12690
 
}
12691
 
 
12692
 
static int
12693
 
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12694
 
                              xmlXPathStepOpPtr op, xmlNodePtr * first);
12695
 
 
12696
 
/**
12697
 
 * xmlXPathCompOpEvalFirst:
12698
 
 * @ctxt:  the XPath parser context with the compiled expression
12699
 
 * @op:  an XPath compiled operation
12700
 
 * @first:  the first elem found so far
12701
 
 *
12702
 
 * Evaluate the Precompiled XPath operation searching only the first
12703
 
 * element in document order
12704
 
 *
12705
 
 * Returns the number of examined objects.
12706
 
 */
12707
 
static int
12708
 
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12709
 
                        xmlXPathStepOpPtr op, xmlNodePtr * first)
12710
 
{
12711
 
    int total = 0, cur;
12712
 
    xmlXPathCompExprPtr comp;
12713
 
    xmlXPathObjectPtr arg1, arg2;
12714
 
 
12715
 
    CHECK_ERROR0;
12716
 
    comp = ctxt->comp;
12717
 
    switch (op->op) {
12718
 
        case XPATH_OP_END:
12719
 
            return (0);
12720
 
        case XPATH_OP_UNION:
12721
 
            total =
12722
 
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12723
 
                                        first);
12724
 
            CHECK_ERROR0;
12725
 
            if ((ctxt->value != NULL)
12726
 
                && (ctxt->value->type == XPATH_NODESET)
12727
 
                && (ctxt->value->nodesetval != NULL)
12728
 
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12729
 
                /*
12730
 
                 * limit tree traversing to first node in the result
12731
 
                 */
12732
 
                /*
12733
 
                * OPTIMIZE TODO: This implicitely sorts
12734
 
                *  the result, even if not needed. E.g. if the argument
12735
 
                *  of the count() function, no sorting is needed.
12736
 
                * OPTIMIZE TODO: How do we know if the node-list wasn't
12737
 
                *  aready sorted?
12738
 
                */
12739
 
                if (ctxt->value->nodesetval->nodeNr > 1)
12740
 
                    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12741
 
                *first = ctxt->value->nodesetval->nodeTab[0];
12742
 
            }
12743
 
            cur =
12744
 
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12745
 
                                        first);
12746
 
            CHECK_ERROR0;
12747
 
            CHECK_TYPE0(XPATH_NODESET);
12748
 
            arg2 = valuePop(ctxt);
12749
 
 
12750
 
            CHECK_TYPE0(XPATH_NODESET);
12751
 
            arg1 = valuePop(ctxt);
12752
 
 
12753
 
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12754
 
                                                    arg2->nodesetval);
12755
 
            valuePush(ctxt, arg1);
12756
 
            xmlXPathReleaseObject(ctxt->context, arg2);
12757
 
            /* optimizer */
12758
 
            if (total > cur)
12759
 
                xmlXPathCompSwap(op);
12760
 
            return (total + cur);
12761
 
        case XPATH_OP_ROOT:
12762
 
            xmlXPathRoot(ctxt);
12763
 
            return (0);
12764
 
        case XPATH_OP_NODE:
12765
 
            if (op->ch1 != -1)
12766
 
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12767
 
            CHECK_ERROR0;
12768
 
            if (op->ch2 != -1)
12769
 
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12770
 
            CHECK_ERROR0;
12771
 
            valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12772
 
                ctxt->context->node));
12773
 
            return (total);
12774
 
        case XPATH_OP_RESET:
12775
 
            if (op->ch1 != -1)
12776
 
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12777
 
            CHECK_ERROR0;
12778
 
            if (op->ch2 != -1)
12779
 
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12780
 
            CHECK_ERROR0;
12781
 
            ctxt->context->node = NULL;
12782
 
            return (total);
12783
 
        case XPATH_OP_COLLECT:{
12784
 
                if (op->ch1 == -1)
12785
 
                    return (total);
12786
 
 
12787
 
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12788
 
                CHECK_ERROR0;
12789
 
 
12790
 
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12791
 
                return (total);
12792
 
            }
12793
 
        case XPATH_OP_VALUE:
12794
 
            valuePush(ctxt,
12795
 
                      xmlXPathCacheObjectCopy(ctxt->context,
12796
 
                        (xmlXPathObjectPtr) op->value4));
12797
 
            return (0);
12798
 
        case XPATH_OP_SORT:
12799
 
            if (op->ch1 != -1)
12800
 
                total +=
12801
 
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12802
 
                                            first);
12803
 
            CHECK_ERROR0;
12804
 
            if ((ctxt->value != NULL)
12805
 
                && (ctxt->value->type == XPATH_NODESET)
12806
 
                && (ctxt->value->nodesetval != NULL)
12807
 
                && (ctxt->value->nodesetval->nodeNr > 1))
12808
 
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12809
 
            return (total);
12810
 
#ifdef XP_OPTIMIZED_FILTER_FIRST
12811
 
        case XPATH_OP_FILTER:
12812
 
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12813
 
            return (total);
12814
 
#endif
12815
 
        default:
12816
 
            return (xmlXPathCompOpEval(ctxt, op));
12817
 
    }
12818
 
}
12819
 
 
12820
 
/**
12821
 
 * xmlXPathCompOpEvalLast:
12822
 
 * @ctxt:  the XPath parser context with the compiled expression
12823
 
 * @op:  an XPath compiled operation
12824
 
 * @last:  the last elem found so far
12825
 
 *
12826
 
 * Evaluate the Precompiled XPath operation searching only the last
12827
 
 * element in document order
12828
 
 *
12829
 
 * Returns the number of nodes traversed
12830
 
 */
12831
 
static int
12832
 
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12833
 
                       xmlNodePtr * last)
12834
 
{
12835
 
    int total = 0, cur;
12836
 
    xmlXPathCompExprPtr comp;
12837
 
    xmlXPathObjectPtr arg1, arg2;
12838
 
    xmlNodePtr bak;
12839
 
    xmlDocPtr bakd;
12840
 
    int pp;
12841
 
    int cs;
12842
 
 
12843
 
    CHECK_ERROR0;
12844
 
    comp = ctxt->comp;
12845
 
    switch (op->op) {
12846
 
        case XPATH_OP_END:
12847
 
            return (0);
12848
 
        case XPATH_OP_UNION:
12849
 
            bakd = ctxt->context->doc;
12850
 
            bak = ctxt->context->node;
12851
 
            pp = ctxt->context->proximityPosition;
12852
 
            cs = ctxt->context->contextSize;
12853
 
            total =
12854
 
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12855
 
            CHECK_ERROR0;
12856
 
            if ((ctxt->value != NULL)
12857
 
                && (ctxt->value->type == XPATH_NODESET)
12858
 
                && (ctxt->value->nodesetval != NULL)
12859
 
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12860
 
                /*
12861
 
                 * limit tree traversing to first node in the result
12862
 
                 */
12863
 
                if (ctxt->value->nodesetval->nodeNr > 1)
12864
 
                    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12865
 
                *last =
12866
 
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
12867
 
                                                     nodesetval->nodeNr -
12868
 
                                                     1];
12869
 
            }
12870
 
            ctxt->context->doc = bakd;
12871
 
            ctxt->context->node = bak;
12872
 
            ctxt->context->proximityPosition = pp;
12873
 
            ctxt->context->contextSize = cs;
12874
 
            cur =
12875
 
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12876
 
            CHECK_ERROR0;
12877
 
            if ((ctxt->value != NULL)
12878
 
                && (ctxt->value->type == XPATH_NODESET)
12879
 
                && (ctxt->value->nodesetval != NULL)
12880
 
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12881
 
            }
12882
 
            CHECK_TYPE0(XPATH_NODESET);
12883
 
            arg2 = valuePop(ctxt);
12884
 
 
12885
 
            CHECK_TYPE0(XPATH_NODESET);
12886
 
            arg1 = valuePop(ctxt);
12887
 
 
12888
 
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12889
 
                                                    arg2->nodesetval);
12890
 
            valuePush(ctxt, arg1);
12891
 
            xmlXPathReleaseObject(ctxt->context, arg2);
12892
 
            /* optimizer */
12893
 
            if (total > cur)
12894
 
                xmlXPathCompSwap(op);
12895
 
            return (total + cur);
12896
 
        case XPATH_OP_ROOT:
12897
 
            xmlXPathRoot(ctxt);
12898
 
            return (0);
12899
 
        case XPATH_OP_NODE:
12900
 
            if (op->ch1 != -1)
12901
 
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12902
 
            CHECK_ERROR0;
12903
 
            if (op->ch2 != -1)
12904
 
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12905
 
            CHECK_ERROR0;
12906
 
            valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12907
 
                ctxt->context->node));
12908
 
            return (total);
12909
 
        case XPATH_OP_RESET:
12910
 
            if (op->ch1 != -1)
12911
 
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12912
 
            CHECK_ERROR0;
12913
 
            if (op->ch2 != -1)
12914
 
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12915
 
            CHECK_ERROR0;
12916
 
            ctxt->context->node = NULL;
12917
 
            return (total);
12918
 
        case XPATH_OP_COLLECT:{
12919
 
                if (op->ch1 == -1)
12920
 
                    return (0);
12921
 
 
12922
 
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12923
 
                CHECK_ERROR0;
12924
 
 
12925
 
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12926
 
                return (total);
12927
 
            }
12928
 
        case XPATH_OP_VALUE:
12929
 
            valuePush(ctxt,
12930
 
                      xmlXPathCacheObjectCopy(ctxt->context,
12931
 
                        (xmlXPathObjectPtr) op->value4));
12932
 
            return (0);
12933
 
        case XPATH_OP_SORT:
12934
 
            if (op->ch1 != -1)
12935
 
                total +=
12936
 
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12937
 
                                           last);
12938
 
            CHECK_ERROR0;
12939
 
            if ((ctxt->value != NULL)
12940
 
                && (ctxt->value->type == XPATH_NODESET)
12941
 
                && (ctxt->value->nodesetval != NULL)
12942
 
                && (ctxt->value->nodesetval->nodeNr > 1))
12943
 
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12944
 
            return (total);
12945
 
        default:
12946
 
            return (xmlXPathCompOpEval(ctxt, op));
12947
 
    }
12948
 
}
12949
 
 
12950
 
#ifdef XP_OPTIMIZED_FILTER_FIRST
12951
 
static int
12952
 
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12953
 
                              xmlXPathStepOpPtr op, xmlNodePtr * first)
12954
 
{
12955
 
    int total = 0;
12956
 
    xmlXPathCompExprPtr comp;
12957
 
    xmlXPathObjectPtr res;
12958
 
    xmlXPathObjectPtr obj;
12959
 
    xmlNodeSetPtr oldset;
12960
 
    xmlNodePtr oldnode;
12961
 
    xmlDocPtr oldDoc;
12962
 
    int i;
12963
 
 
12964
 
    CHECK_ERROR0;
12965
 
    comp = ctxt->comp;
12966
 
    /*
12967
 
    * Optimization for ()[last()] selection i.e. the last elem
12968
 
    */
12969
 
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
12970
 
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12971
 
        (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12972
 
        int f = comp->steps[op->ch2].ch1;
12973
 
 
12974
 
        if ((f != -1) &&
12975
 
            (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12976
 
            (comp->steps[f].value5 == NULL) &&
12977
 
            (comp->steps[f].value == 0) &&
12978
 
            (comp->steps[f].value4 != NULL) &&
12979
 
            (xmlStrEqual
12980
 
            (comp->steps[f].value4, BAD_CAST "last"))) {
12981
 
            xmlNodePtr last = NULL;
12982
 
 
12983
 
            total +=
12984
 
                xmlXPathCompOpEvalLast(ctxt,
12985
 
                    &comp->steps[op->ch1],
12986
 
                    &last);
12987
 
            CHECK_ERROR0;
12988
 
            /*
12989
 
            * The nodeset should be in document order,
12990
 
            * Keep only the last value
12991
 
            */
12992
 
            if ((ctxt->value != NULL) &&
12993
 
                (ctxt->value->type == XPATH_NODESET) &&
12994
 
                (ctxt->value->nodesetval != NULL) &&
12995
 
                (ctxt->value->nodesetval->nodeTab != NULL) &&
12996
 
                (ctxt->value->nodesetval->nodeNr > 1)) {
12997
 
                ctxt->value->nodesetval->nodeTab[0] =
12998
 
                    ctxt->value->nodesetval->nodeTab[ctxt->
12999
 
                    value->
13000
 
                    nodesetval->
13001
 
                    nodeNr -
13002
 
                    1];
13003
 
                ctxt->value->nodesetval->nodeNr = 1;
13004
 
                *first = *(ctxt->value->nodesetval->nodeTab);
13005
 
            }
13006
 
            return (total);
13007
 
        }
13008
 
    }
13009
 
 
13010
 
    if (op->ch1 != -1)
13011
 
        total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13012
 
    CHECK_ERROR0;
13013
 
    if (op->ch2 == -1)
13014
 
        return (total);
13015
 
    if (ctxt->value == NULL)
13016
 
        return (total);
13017
 
 
13018
 
#ifdef LIBXML_XPTR_ENABLED
13019
 
    oldnode = ctxt->context->node;
13020
 
    /*
13021
 
    * Hum are we filtering the result of an XPointer expression
13022
 
    */
13023
 
    if (ctxt->value->type == XPATH_LOCATIONSET) {
13024
 
        xmlXPathObjectPtr tmp = NULL;
13025
 
        xmlLocationSetPtr newlocset = NULL;
13026
 
        xmlLocationSetPtr oldlocset;
13027
 
 
13028
 
        /*
13029
 
        * Extract the old locset, and then evaluate the result of the
13030
 
        * expression for all the element in the locset. use it to grow
13031
 
        * up a new locset.
13032
 
        */
13033
 
        CHECK_TYPE0(XPATH_LOCATIONSET);
13034
 
        obj = valuePop(ctxt);
13035
 
        oldlocset = obj->user;
13036
 
        ctxt->context->node = NULL;
13037
 
 
13038
 
        if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13039
 
            ctxt->context->contextSize = 0;
13040
 
            ctxt->context->proximityPosition = 0;
13041
 
            if (op->ch2 != -1)
13042
 
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13043
 
            res = valuePop(ctxt);
13044
 
            if (res != NULL) {
13045
 
                xmlXPathReleaseObject(ctxt->context, res);
13046
 
            }
13047
 
            valuePush(ctxt, obj);
13048
 
            CHECK_ERROR0;
13049
 
            return (total);
13050
 
        }
13051
 
        newlocset = xmlXPtrLocationSetCreate(NULL);
13052
 
 
13053
 
        for (i = 0; i < oldlocset->locNr; i++) {
13054
 
            /*
13055
 
            * Run the evaluation with a node list made of a
13056
 
            * single item in the nodelocset.
13057
 
            */
13058
 
            ctxt->context->node = oldlocset->locTab[i]->user;
13059
 
            ctxt->context->contextSize = oldlocset->locNr;
13060
 
            ctxt->context->proximityPosition = i + 1;
13061
 
            if (tmp == NULL) {
13062
 
                tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13063
 
                    ctxt->context->node);
13064
 
            } else {
13065
 
                if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13066
 
                                             ctxt->context->node) < 0) {
13067
 
                    ctxt->error = XPATH_MEMORY_ERROR;
13068
 
                }
13069
 
            }
13070
 
            valuePush(ctxt, tmp);
13071
 
            if (op->ch2 != -1)
13072
 
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13073
 
            if (ctxt->error != XPATH_EXPRESSION_OK) {
13074
 
                xmlXPathFreeObject(obj);
13075
 
                return(0);
13076
 
            }
13077
 
            /*
13078
 
            * The result of the evaluation need to be tested to
13079
 
            * decided whether the filter succeeded or not
13080
 
            */
13081
 
            res = valuePop(ctxt);
13082
 
            if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13083
 
                xmlXPtrLocationSetAdd(newlocset,
13084
 
                    xmlXPathCacheObjectCopy(ctxt->context,
13085
 
                        oldlocset->locTab[i]));
13086
 
            }
13087
 
            /*
13088
 
            * Cleanup
13089
 
            */
13090
 
            if (res != NULL) {
13091
 
                xmlXPathReleaseObject(ctxt->context, res);
13092
 
            }
13093
 
            if (ctxt->value == tmp) {
13094
 
                valuePop(ctxt);
13095
 
                xmlXPathNodeSetClear(tmp->nodesetval, 1);
13096
 
                /*
13097
 
                * REVISIT TODO: Don't create a temporary nodeset
13098
 
                * for everly iteration.
13099
 
                */
13100
 
                /* OLD: xmlXPathFreeObject(res); */
13101
 
            } else
13102
 
                tmp = NULL;
13103
 
            ctxt->context->node = NULL;
13104
 
            /*
13105
 
            * Only put the first node in the result, then leave.
13106
 
            */
13107
 
            if (newlocset->locNr > 0) {
13108
 
                *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13109
 
                break;
13110
 
            }
13111
 
        }
13112
 
        if (tmp != NULL) {
13113
 
            xmlXPathReleaseObject(ctxt->context, tmp);
13114
 
        }
13115
 
        /*
13116
 
        * The result is used as the new evaluation locset.
13117
 
        */
13118
 
        xmlXPathReleaseObject(ctxt->context, obj);
13119
 
        ctxt->context->node = NULL;
13120
 
        ctxt->context->contextSize = -1;
13121
 
        ctxt->context->proximityPosition = -1;
13122
 
        valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13123
 
        ctxt->context->node = oldnode;
13124
 
        return (total);
13125
 
    }
13126
 
#endif /* LIBXML_XPTR_ENABLED */
13127
 
 
13128
 
    /*
13129
 
    * Extract the old set, and then evaluate the result of the
13130
 
    * expression for all the element in the set. use it to grow
13131
 
    * up a new set.
13132
 
    */
13133
 
    CHECK_TYPE0(XPATH_NODESET);
13134
 
    obj = valuePop(ctxt);
13135
 
    oldset = obj->nodesetval;
13136
 
 
13137
 
    oldnode = ctxt->context->node;
13138
 
    oldDoc = ctxt->context->doc;
13139
 
    ctxt->context->node = NULL;
13140
 
 
13141
 
    if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13142
 
        ctxt->context->contextSize = 0;
13143
 
        ctxt->context->proximityPosition = 0;
13144
 
        /* QUESTION TODO: Why was this code commented out?
13145
 
            if (op->ch2 != -1)
13146
 
                total +=
13147
 
                    xmlXPathCompOpEval(ctxt,
13148
 
                        &comp->steps[op->ch2]);
13149
 
            CHECK_ERROR0;
13150
 
            res = valuePop(ctxt);
13151
 
            if (res != NULL)
13152
 
                xmlXPathFreeObject(res);
13153
 
        */
13154
 
        valuePush(ctxt, obj);
13155
 
        ctxt->context->node = oldnode;
13156
 
        CHECK_ERROR0;
13157
 
    } else {
13158
 
        xmlNodeSetPtr newset;
13159
 
        xmlXPathObjectPtr tmp = NULL;
13160
 
        /*
13161
 
        * Initialize the new set.
13162
 
        * Also set the xpath document in case things like
13163
 
        * key() evaluation are attempted on the predicate
13164
 
        */
13165
 
        newset = xmlXPathNodeSetCreate(NULL);
13166
 
        /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13167
 
 
13168
 
        for (i = 0; i < oldset->nodeNr; i++) {
13169
 
            /*
13170
 
            * Run the evaluation with a node list made of
13171
 
            * a single item in the nodeset.
13172
 
            */
13173
 
            ctxt->context->node = oldset->nodeTab[i];
13174
 
            if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13175
 
                (oldset->nodeTab[i]->doc != NULL))
13176
 
                ctxt->context->doc = oldset->nodeTab[i]->doc;
13177
 
            if (tmp == NULL) {
13178
 
                tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13179
 
                    ctxt->context->node);
13180
 
            } else {
13181
 
                if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13182
 
                                             ctxt->context->node) < 0) {
13183
 
                    ctxt->error = XPATH_MEMORY_ERROR;
13184
 
                }
13185
 
            }
13186
 
            valuePush(ctxt, tmp);
13187
 
            ctxt->context->contextSize = oldset->nodeNr;
13188
 
            ctxt->context->proximityPosition = i + 1;
13189
 
            if (op->ch2 != -1)
13190
 
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13191
 
            if (ctxt->error != XPATH_EXPRESSION_OK) {
13192
 
                xmlXPathFreeNodeSet(newset);
13193
 
                xmlXPathFreeObject(obj);
13194
 
                return(0);
13195
 
            }
13196
 
            /*
13197
 
            * The result of the evaluation needs to be tested to
13198
 
            * decide whether the filter succeeded or not
13199
 
            */
13200
 
            res = valuePop(ctxt);
13201
 
            if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13202
 
                if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13203
 
                    ctxt->error = XPATH_MEMORY_ERROR;
13204
 
            }
13205
 
            /*
13206
 
            * Cleanup
13207
 
            */
13208
 
            if (res != NULL) {
13209
 
                xmlXPathReleaseObject(ctxt->context, res);
13210
 
            }
13211
 
            if (ctxt->value == tmp) {
13212
 
                valuePop(ctxt);
13213
 
                /*
13214
 
                * Don't free the temporary nodeset
13215
 
                * in order to avoid massive recreation inside this
13216
 
                * loop.
13217
 
                */
13218
 
                xmlXPathNodeSetClear(tmp->nodesetval, 1);
13219
 
            } else
13220
 
                tmp = NULL;
13221
 
            ctxt->context->node = NULL;
13222
 
            /*
13223
 
            * Only put the first node in the result, then leave.
13224
 
            */
13225
 
            if (newset->nodeNr > 0) {
13226
 
                *first = *(newset->nodeTab);
13227
 
                break;
13228
 
            }
13229
 
        }
13230
 
        if (tmp != NULL) {
13231
 
            xmlXPathReleaseObject(ctxt->context, tmp);
13232
 
        }
13233
 
        /*
13234
 
        * The result is used as the new evaluation set.
13235
 
        */
13236
 
        xmlXPathReleaseObject(ctxt->context, obj);
13237
 
        ctxt->context->node = NULL;
13238
 
        ctxt->context->contextSize = -1;
13239
 
        ctxt->context->proximityPosition = -1;
13240
 
        /* may want to move this past the '}' later */
13241
 
        ctxt->context->doc = oldDoc;
13242
 
        valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13243
 
    }
13244
 
    ctxt->context->node = oldnode;
13245
 
    return(total);
13246
 
}
13247
 
#endif /* XP_OPTIMIZED_FILTER_FIRST */
13248
 
 
13249
 
/**
13250
 
 * xmlXPathCompOpEval:
13251
 
 * @ctxt:  the XPath parser context with the compiled expression
13252
 
 * @op:  an XPath compiled operation
13253
 
 *
13254
 
 * Evaluate the Precompiled XPath operation
13255
 
 * Returns the number of nodes traversed
13256
 
 */
13257
 
static int
13258
 
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13259
 
{
13260
 
    int total = 0;
13261
 
    int equal, ret;
13262
 
    xmlXPathCompExprPtr comp;
13263
 
    xmlXPathObjectPtr arg1, arg2;
13264
 
    xmlNodePtr bak;
13265
 
    xmlDocPtr bakd;
13266
 
    int pp;
13267
 
    int cs;
13268
 
 
13269
 
    CHECK_ERROR0;
13270
 
    comp = ctxt->comp;
13271
 
    switch (op->op) {
13272
 
        case XPATH_OP_END:
13273
 
            return (0);
13274
 
        case XPATH_OP_AND:
13275
 
            bakd = ctxt->context->doc;
13276
 
            bak = ctxt->context->node;
13277
 
            pp = ctxt->context->proximityPosition;
13278
 
            cs = ctxt->context->contextSize;
13279
 
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13280
 
            CHECK_ERROR0;
13281
 
            xmlXPathBooleanFunction(ctxt, 1);
13282
 
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13283
 
                return (total);
13284
 
            arg2 = valuePop(ctxt);
13285
 
            ctxt->context->doc = bakd;
13286
 
            ctxt->context->node = bak;
13287
 
            ctxt->context->proximityPosition = pp;
13288
 
            ctxt->context->contextSize = cs;
13289
 
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13290
 
            if (ctxt->error) {
13291
 
                xmlXPathFreeObject(arg2);
13292
 
                return(0);
13293
 
            }
13294
 
            xmlXPathBooleanFunction(ctxt, 1);
13295
 
            arg1 = valuePop(ctxt);
13296
 
            arg1->boolval &= arg2->boolval;
13297
 
            valuePush(ctxt, arg1);
13298
 
            xmlXPathReleaseObject(ctxt->context, arg2);
13299
 
            return (total);
13300
 
        case XPATH_OP_OR:
13301
 
            bakd = ctxt->context->doc;
13302
 
            bak = ctxt->context->node;
13303
 
            pp = ctxt->context->proximityPosition;
13304
 
            cs = ctxt->context->contextSize;
13305
 
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13306
 
            CHECK_ERROR0;
13307
 
            xmlXPathBooleanFunction(ctxt, 1);
13308
 
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13309
 
                return (total);
13310
 
            arg2 = valuePop(ctxt);
13311
 
            ctxt->context->doc = bakd;
13312
 
            ctxt->context->node = bak;
13313
 
            ctxt->context->proximityPosition = pp;
13314
 
            ctxt->context->contextSize = cs;
13315
 
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13316
 
            if (ctxt->error) {
13317
 
                xmlXPathFreeObject(arg2);
13318
 
                return(0);
13319
 
            }
13320
 
            xmlXPathBooleanFunction(ctxt, 1);
13321
 
            arg1 = valuePop(ctxt);
13322
 
            arg1->boolval |= arg2->boolval;
13323
 
            valuePush(ctxt, arg1);
13324
 
            xmlXPathReleaseObject(ctxt->context, arg2);
13325
 
            return (total);
13326
 
        case XPATH_OP_EQUAL:
13327
 
            bakd = ctxt->context->doc;
13328
 
            bak = ctxt->context->node;
13329
 
            pp = ctxt->context->proximityPosition;
13330
 
            cs = ctxt->context->contextSize;
13331
 
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13332
 
            CHECK_ERROR0;
13333
 
            ctxt->context->doc = bakd;
13334
 
            ctxt->context->node = bak;
13335
 
            ctxt->context->proximityPosition = pp;
13336
 
            ctxt->context->contextSize = cs;
13337
 
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13338
 
            CHECK_ERROR0;
13339
 
            if (op->value)
13340
 
                equal = xmlXPathEqualValues(ctxt);
13341
 
            else
13342
 
                equal = xmlXPathNotEqualValues(ctxt);
13343
 
            valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13344
 
            return (total);
13345
 
        case XPATH_OP_CMP:
13346
 
            bakd = ctxt->context->doc;
13347
 
            bak = ctxt->context->node;
13348
 
            pp = ctxt->context->proximityPosition;
13349
 
            cs = ctxt->context->contextSize;
13350
 
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13351
 
            CHECK_ERROR0;
13352
 
            ctxt->context->doc = bakd;
13353
 
            ctxt->context->node = bak;
13354
 
            ctxt->context->proximityPosition = pp;
13355
 
            ctxt->context->contextSize = cs;
13356
 
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13357
 
            CHECK_ERROR0;
13358
 
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13359
 
            valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13360
 
            return (total);
13361
 
        case XPATH_OP_PLUS:
13362
 
            bakd = ctxt->context->doc;
13363
 
            bak = ctxt->context->node;
13364
 
            pp = ctxt->context->proximityPosition;
13365
 
            cs = ctxt->context->contextSize;
13366
 
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13367
 
            CHECK_ERROR0;
13368
 
            if (op->ch2 != -1) {
13369
 
                ctxt->context->doc = bakd;
13370
 
                ctxt->context->node = bak;
13371
 
                ctxt->context->proximityPosition = pp;
13372
 
                ctxt->context->contextSize = cs;
13373
 
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13374
 
            }
13375
 
            CHECK_ERROR0;
13376
 
            if (op->value == 0)
13377
 
                xmlXPathSubValues(ctxt);
13378
 
            else if (op->value == 1)
13379
 
                xmlXPathAddValues(ctxt);
13380
 
            else if (op->value == 2)
13381
 
                xmlXPathValueFlipSign(ctxt);
13382
 
            else if (op->value == 3) {
13383
 
                CAST_TO_NUMBER;
13384
 
                CHECK_TYPE0(XPATH_NUMBER);
13385
 
            }
13386
 
            return (total);
13387
 
        case XPATH_OP_MULT:
13388
 
            bakd = ctxt->context->doc;
13389
 
            bak = ctxt->context->node;
13390
 
            pp = ctxt->context->proximityPosition;
13391
 
            cs = ctxt->context->contextSize;
13392
 
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13393
 
            CHECK_ERROR0;
13394
 
            ctxt->context->doc = bakd;
13395
 
            ctxt->context->node = bak;
13396
 
            ctxt->context->proximityPosition = pp;
13397
 
            ctxt->context->contextSize = cs;
13398
 
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13399
 
            CHECK_ERROR0;
13400
 
            if (op->value == 0)
13401
 
                xmlXPathMultValues(ctxt);
13402
 
            else if (op->value == 1)
13403
 
                xmlXPathDivValues(ctxt);
13404
 
            else if (op->value == 2)
13405
 
                xmlXPathModValues(ctxt);
13406
 
            return (total);
13407
 
        case XPATH_OP_UNION:
13408
 
            bakd = ctxt->context->doc;
13409
 
            bak = ctxt->context->node;
13410
 
            pp = ctxt->context->proximityPosition;
13411
 
            cs = ctxt->context->contextSize;
13412
 
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13413
 
            CHECK_ERROR0;
13414
 
            ctxt->context->doc = bakd;
13415
 
            ctxt->context->node = bak;
13416
 
            ctxt->context->proximityPosition = pp;
13417
 
            ctxt->context->contextSize = cs;
13418
 
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13419
 
            CHECK_ERROR0;
13420
 
            CHECK_TYPE0(XPATH_NODESET);
13421
 
            arg2 = valuePop(ctxt);
13422
 
 
13423
 
            CHECK_TYPE0(XPATH_NODESET);
13424
 
            arg1 = valuePop(ctxt);
13425
 
 
13426
 
            if ((arg1->nodesetval == NULL) ||
13427
 
                ((arg2->nodesetval != NULL) &&
13428
 
                 (arg2->nodesetval->nodeNr != 0)))
13429
 
            {
13430
 
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13431
 
                                                        arg2->nodesetval);
13432
 
            }
13433
 
 
13434
 
            valuePush(ctxt, arg1);
13435
 
            xmlXPathReleaseObject(ctxt->context, arg2);
13436
 
            return (total);
13437
 
        case XPATH_OP_ROOT:
13438
 
            xmlXPathRoot(ctxt);
13439
 
            return (total);
13440
 
        case XPATH_OP_NODE:
13441
 
            if (op->ch1 != -1)
13442
 
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13443
 
            CHECK_ERROR0;
13444
 
            if (op->ch2 != -1)
13445
 
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13446
 
            CHECK_ERROR0;
13447
 
            valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13448
 
                ctxt->context->node));
13449
 
            return (total);
13450
 
        case XPATH_OP_RESET:
13451
 
            if (op->ch1 != -1)
13452
 
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13453
 
            CHECK_ERROR0;
13454
 
            if (op->ch2 != -1)
13455
 
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13456
 
            CHECK_ERROR0;
13457
 
            ctxt->context->node = NULL;
13458
 
            return (total);
13459
 
        case XPATH_OP_COLLECT:{
13460
 
                if (op->ch1 == -1)
13461
 
                    return (total);
13462
 
 
13463
 
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13464
 
                CHECK_ERROR0;
13465
 
 
13466
 
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13467
 
                return (total);
13468
 
            }
13469
 
        case XPATH_OP_VALUE:
13470
 
            valuePush(ctxt,
13471
 
                      xmlXPathCacheObjectCopy(ctxt->context,
13472
 
                        (xmlXPathObjectPtr) op->value4));
13473
 
            return (total);
13474
 
        case XPATH_OP_VARIABLE:{
13475
 
                xmlXPathObjectPtr val;
13476
 
 
13477
 
                if (op->ch1 != -1)
13478
 
                    total +=
13479
 
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13480
 
                if (op->value5 == NULL) {
13481
 
                    val = xmlXPathVariableLookup(ctxt->context, op->value4);
13482
 
                    if (val == NULL) {
13483
 
                        ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13484
 
                        return(0);
13485
 
                    }
13486
 
                    valuePush(ctxt, val);
13487
 
                } else {
13488
 
                    const xmlChar *URI;
13489
 
 
13490
 
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
13491
 
                    if (URI == NULL) {
13492
 
                        xmlGenericError(xmlGenericErrorContext,
13493
 
            "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13494
 
                                    (char *) op->value4, (char *)op->value5);
13495
 
                        ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13496
 
                        return (total);
13497
 
                    }
13498
 
                    val = xmlXPathVariableLookupNS(ctxt->context,
13499
 
                                                       op->value4, URI);
13500
 
                    if (val == NULL) {
13501
 
                        ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13502
 
                        return(0);
13503
 
                    }
13504
 
                    valuePush(ctxt, val);
13505
 
                }
13506
 
                return (total);
13507
 
            }
13508
 
        case XPATH_OP_FUNCTION:{
13509
 
                xmlXPathFunction func;
13510
 
                const xmlChar *oldFunc, *oldFuncURI;
13511
 
                int i;
13512
 
                int frame;
13513
 
 
13514
 
                frame = xmlXPathSetFrame(ctxt);
13515
 
                if (op->ch1 != -1)
13516
 
                    total +=
13517
 
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13518
 
                if (ctxt->valueNr < op->value) {
13519
 
                    xmlGenericError(xmlGenericErrorContext,
13520
 
                            "xmlXPathCompOpEval: parameter error\n");
13521
 
                    ctxt->error = XPATH_INVALID_OPERAND;
13522
 
                    xmlXPathPopFrame(ctxt, frame);
13523
 
                    return (total);
13524
 
                }
13525
 
                for (i = 0; i < op->value; i++) {
13526
 
                    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13527
 
                        xmlGenericError(xmlGenericErrorContext,
13528
 
                                "xmlXPathCompOpEval: parameter error\n");
13529
 
                        ctxt->error = XPATH_INVALID_OPERAND;
13530
 
                        xmlXPathPopFrame(ctxt, frame);
13531
 
                        return (total);
13532
 
                    }
13533
 
                }
13534
 
                if (op->cache != NULL)
13535
 
                    XML_CAST_FPTR(func) = op->cache;
13536
 
                else {
13537
 
                    const xmlChar *URI = NULL;
13538
 
 
13539
 
                    if (op->value5 == NULL)
13540
 
                        func =
13541
 
                            xmlXPathFunctionLookup(ctxt->context,
13542
 
                                                   op->value4);
13543
 
                    else {
13544
 
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
13545
 
                        if (URI == NULL) {
13546
 
                            xmlGenericError(xmlGenericErrorContext,
13547
 
            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13548
 
                                    (char *)op->value4, (char *)op->value5);
13549
 
                            xmlXPathPopFrame(ctxt, frame);
13550
 
                            ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13551
 
                            return (total);
13552
 
                        }
13553
 
                        func = xmlXPathFunctionLookupNS(ctxt->context,
13554
 
                                                        op->value4, URI);
13555
 
                    }
13556
 
                    if (func == NULL) {
13557
 
                        xmlGenericError(xmlGenericErrorContext,
13558
 
                                "xmlXPathCompOpEval: function %s not found\n",
13559
 
                                        (char *)op->value4);
13560
 
                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13561
 
                    }
13562
 
                    op->cache = XML_CAST_FPTR(func);
13563
 
                    op->cacheURI = (void *) URI;
13564
 
                }
13565
 
                oldFunc = ctxt->context->function;
13566
 
                oldFuncURI = ctxt->context->functionURI;
13567
 
                ctxt->context->function = op->value4;
13568
 
                ctxt->context->functionURI = op->cacheURI;
13569
 
                func(ctxt, op->value);
13570
 
                ctxt->context->function = oldFunc;
13571
 
                ctxt->context->functionURI = oldFuncURI;
13572
 
                xmlXPathPopFrame(ctxt, frame);
13573
 
                return (total);
13574
 
            }
13575
 
        case XPATH_OP_ARG:
13576
 
            bakd = ctxt->context->doc;
13577
 
            bak = ctxt->context->node;
13578
 
            pp = ctxt->context->proximityPosition;
13579
 
            cs = ctxt->context->contextSize;
13580
 
            if (op->ch1 != -1)
13581
 
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13582
 
            ctxt->context->contextSize = cs;
13583
 
            ctxt->context->proximityPosition = pp;
13584
 
            ctxt->context->node = bak;
13585
 
            ctxt->context->doc = bakd;
13586
 
            CHECK_ERROR0;
13587
 
            if (op->ch2 != -1) {
13588
 
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13589
 
                ctxt->context->doc = bakd;
13590
 
                ctxt->context->node = bak;
13591
 
                CHECK_ERROR0;
13592
 
            }
13593
 
            return (total);
13594
 
        case XPATH_OP_PREDICATE:
13595
 
        case XPATH_OP_FILTER:{
13596
 
                xmlXPathObjectPtr res;
13597
 
                xmlXPathObjectPtr obj, tmp;
13598
 
                xmlNodeSetPtr newset = NULL;
13599
 
                xmlNodeSetPtr oldset;
13600
 
                xmlNodePtr oldnode;
13601
 
                xmlDocPtr oldDoc;
13602
 
                int i;
13603
 
 
13604
 
                /*
13605
 
                 * Optimization for ()[1] selection i.e. the first elem
13606
 
                 */
13607
 
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13608
 
#ifdef XP_OPTIMIZED_FILTER_FIRST
13609
 
                    /*
13610
 
                    * FILTER TODO: Can we assume that the inner processing
13611
 
                    *  will result in an ordered list if we have an
13612
 
                    *  XPATH_OP_FILTER?
13613
 
                    *  What about an additional field or flag on
13614
 
                    *  xmlXPathObject like @sorted ? This way we wouln'd need
13615
 
                    *  to assume anything, so it would be more robust and
13616
 
                    *  easier to optimize.
13617
 
                    */
13618
 
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13619
 
                     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13620
 
#else
13621
 
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13622
 
#endif
13623
 
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13624
 
                    xmlXPathObjectPtr val;
13625
 
 
13626
 
                    val = comp->steps[op->ch2].value4;
13627
 
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13628
 
                        (val->floatval == 1.0)) {
13629
 
                        xmlNodePtr first = NULL;
13630
 
 
13631
 
                        total +=
13632
 
                            xmlXPathCompOpEvalFirst(ctxt,
13633
 
                                                    &comp->steps[op->ch1],
13634
 
                                                    &first);
13635
 
                        CHECK_ERROR0;
13636
 
                        /*
13637
 
                         * The nodeset should be in document order,
13638
 
                         * Keep only the first value
13639
 
                         */
13640
 
                        if ((ctxt->value != NULL) &&
13641
 
                            (ctxt->value->type == XPATH_NODESET) &&
13642
 
                            (ctxt->value->nodesetval != NULL) &&
13643
 
                            (ctxt->value->nodesetval->nodeNr > 1))
13644
 
                            ctxt->value->nodesetval->nodeNr = 1;
13645
 
                        return (total);
13646
 
                    }
13647
 
                }
13648
 
                /*
13649
 
                 * Optimization for ()[last()] selection i.e. the last elem
13650
 
                 */
13651
 
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13652
 
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13653
 
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13654
 
                    int f = comp->steps[op->ch2].ch1;
13655
 
 
13656
 
                    if ((f != -1) &&
13657
 
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13658
 
                        (comp->steps[f].value5 == NULL) &&
13659
 
                        (comp->steps[f].value == 0) &&
13660
 
                        (comp->steps[f].value4 != NULL) &&
13661
 
                        (xmlStrEqual
13662
 
                         (comp->steps[f].value4, BAD_CAST "last"))) {
13663
 
                        xmlNodePtr last = NULL;
13664
 
 
13665
 
                        total +=
13666
 
                            xmlXPathCompOpEvalLast(ctxt,
13667
 
                                                   &comp->steps[op->ch1],
13668
 
                                                   &last);
13669
 
                        CHECK_ERROR0;
13670
 
                        /*
13671
 
                         * The nodeset should be in document order,
13672
 
                         * Keep only the last value
13673
 
                         */
13674
 
                        if ((ctxt->value != NULL) &&
13675
 
                            (ctxt->value->type == XPATH_NODESET) &&
13676
 
                            (ctxt->value->nodesetval != NULL) &&
13677
 
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
13678
 
                            (ctxt->value->nodesetval->nodeNr > 1)) {
13679
 
                            ctxt->value->nodesetval->nodeTab[0] =
13680
 
                                ctxt->value->nodesetval->nodeTab[ctxt->
13681
 
                                                                 value->
13682
 
                                                                 nodesetval->
13683
 
                                                                 nodeNr -
13684
 
                                                                 1];
13685
 
                            ctxt->value->nodesetval->nodeNr = 1;
13686
 
                        }
13687
 
                        return (total);
13688
 
                    }
13689
 
                }
13690
 
                /*
13691
 
                * Process inner predicates first.
13692
 
                * Example "index[parent::book][1]":
13693
 
                * ...
13694
 
                *   PREDICATE   <-- we are here "[1]"
13695
 
                *     PREDICATE <-- process "[parent::book]" first
13696
 
                *       SORT
13697
 
                *         COLLECT  'parent' 'name' 'node' book
13698
 
                *           NODE
13699
 
                *     ELEM Object is a number : 1
13700
 
                */
13701
 
                if (op->ch1 != -1)
13702
 
                    total +=
13703
 
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13704
 
                CHECK_ERROR0;
13705
 
                if (op->ch2 == -1)
13706
 
                    return (total);
13707
 
                if (ctxt->value == NULL)
13708
 
                    return (total);
13709
 
 
13710
 
                oldnode = ctxt->context->node;
13711
 
 
13712
 
#ifdef LIBXML_XPTR_ENABLED
13713
 
                /*
13714
 
                 * Hum are we filtering the result of an XPointer expression
13715
 
                 */
13716
 
                if (ctxt->value->type == XPATH_LOCATIONSET) {
13717
 
                    xmlLocationSetPtr newlocset = NULL;
13718
 
                    xmlLocationSetPtr oldlocset;
13719
 
 
13720
 
                    /*
13721
 
                     * Extract the old locset, and then evaluate the result of the
13722
 
                     * expression for all the element in the locset. use it to grow
13723
 
                     * up a new locset.
13724
 
                     */
13725
 
                    CHECK_TYPE0(XPATH_LOCATIONSET);
13726
 
                    obj = valuePop(ctxt);
13727
 
                    oldlocset = obj->user;
13728
 
                    ctxt->context->node = NULL;
13729
 
 
13730
 
                    if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13731
 
                        ctxt->context->contextSize = 0;
13732
 
                        ctxt->context->proximityPosition = 0;
13733
 
                        if (op->ch2 != -1)
13734
 
                            total +=
13735
 
                                xmlXPathCompOpEval(ctxt,
13736
 
                                                   &comp->steps[op->ch2]);
13737
 
                        res = valuePop(ctxt);
13738
 
                        if (res != NULL) {
13739
 
                            xmlXPathReleaseObject(ctxt->context, res);
13740
 
                        }
13741
 
                        valuePush(ctxt, obj);
13742
 
                        CHECK_ERROR0;
13743
 
                        return (total);
13744
 
                    }
13745
 
                    newlocset = xmlXPtrLocationSetCreate(NULL);
13746
 
 
13747
 
                    for (i = 0; i < oldlocset->locNr; i++) {
13748
 
                        /*
13749
 
                         * Run the evaluation with a node list made of a
13750
 
                         * single item in the nodelocset.
13751
 
                         */
13752
 
                        ctxt->context->node = oldlocset->locTab[i]->user;
13753
 
                        ctxt->context->contextSize = oldlocset->locNr;
13754
 
                        ctxt->context->proximityPosition = i + 1;
13755
 
                        tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13756
 
                            ctxt->context->node);
13757
 
                        valuePush(ctxt, tmp);
13758
 
 
13759
 
                        if (op->ch2 != -1)
13760
 
                            total +=
13761
 
                                xmlXPathCompOpEval(ctxt,
13762
 
                                                   &comp->steps[op->ch2]);
13763
 
                        if (ctxt->error != XPATH_EXPRESSION_OK) {
13764
 
                            xmlXPathFreeObject(obj);
13765
 
                            return(0);
13766
 
                        }
13767
 
 
13768
 
                        /*
13769
 
                         * The result of the evaluation need to be tested to
13770
 
                         * decided whether the filter succeeded or not
13771
 
                         */
13772
 
                        res = valuePop(ctxt);
13773
 
                        if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13774
 
                            xmlXPtrLocationSetAdd(newlocset,
13775
 
                                                  xmlXPathObjectCopy
13776
 
                                                  (oldlocset->locTab[i]));
13777
 
                        }
13778
 
 
13779
 
                        /*
13780
 
                         * Cleanup
13781
 
                         */
13782
 
                        if (res != NULL) {
13783
 
                            xmlXPathReleaseObject(ctxt->context, res);
13784
 
                        }
13785
 
                        if (ctxt->value == tmp) {
13786
 
                            res = valuePop(ctxt);
13787
 
                            xmlXPathReleaseObject(ctxt->context, res);
13788
 
                        }
13789
 
 
13790
 
                        ctxt->context->node = NULL;
13791
 
                    }
13792
 
 
13793
 
                    /*
13794
 
                     * The result is used as the new evaluation locset.
13795
 
                     */
13796
 
                    xmlXPathReleaseObject(ctxt->context, obj);
13797
 
                    ctxt->context->node = NULL;
13798
 
                    ctxt->context->contextSize = -1;
13799
 
                    ctxt->context->proximityPosition = -1;
13800
 
                    valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13801
 
                    ctxt->context->node = oldnode;
13802
 
                    return (total);
13803
 
                }
13804
 
#endif /* LIBXML_XPTR_ENABLED */
13805
 
 
13806
 
                /*
13807
 
                 * Extract the old set, and then evaluate the result of the
13808
 
                 * expression for all the element in the set. use it to grow
13809
 
                 * up a new set.
13810
 
                 */
13811
 
                CHECK_TYPE0(XPATH_NODESET);
13812
 
                obj = valuePop(ctxt);
13813
 
                oldset = obj->nodesetval;
13814
 
 
13815
 
                oldnode = ctxt->context->node;
13816
 
                oldDoc = ctxt->context->doc;
13817
 
                ctxt->context->node = NULL;
13818
 
 
13819
 
                if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13820
 
                    ctxt->context->contextSize = 0;
13821
 
                    ctxt->context->proximityPosition = 0;
13822
 
/*
13823
 
                    if (op->ch2 != -1)
13824
 
                        total +=
13825
 
                            xmlXPathCompOpEval(ctxt,
13826
 
                                               &comp->steps[op->ch2]);
13827
 
                    CHECK_ERROR0;
13828
 
                    res = valuePop(ctxt);
13829
 
                    if (res != NULL)
13830
 
                        xmlXPathFreeObject(res);
13831
 
*/
13832
 
                    valuePush(ctxt, obj);
13833
 
                    ctxt->context->node = oldnode;
13834
 
                    CHECK_ERROR0;
13835
 
                } else {
13836
 
                    tmp = NULL;
13837
 
                    /*
13838
 
                     * Initialize the new set.
13839
 
                     * Also set the xpath document in case things like
13840
 
                     * key() evaluation are attempted on the predicate
13841
 
                     */
13842
 
                    newset = xmlXPathNodeSetCreate(NULL);
13843
 
                    /*
13844
 
                    * SPEC XPath 1.0:
13845
 
                    *  "For each node in the node-set to be filtered, the
13846
 
                    *  PredicateExpr is evaluated with that node as the
13847
 
                    *  context node, with the number of nodes in the
13848
 
                    *  node-set as the context size, and with the proximity
13849
 
                    *  position of the node in the node-set with respect to
13850
 
                    *  the axis as the context position;"
13851
 
                    * @oldset is the node-set" to be filtered.
13852
 
                    *
13853
 
                    * SPEC XPath 1.0:
13854
 
                    *  "only predicates change the context position and
13855
 
                    *  context size (see [2.4 Predicates])."
13856
 
                    * Example:
13857
 
                    *   node-set  context pos
13858
 
                    *    nA         1
13859
 
                    *    nB         2
13860
 
                    *    nC         3
13861
 
                    *   After applying predicate [position() > 1] :
13862
 
                    *   node-set  context pos
13863
 
                    *    nB         1
13864
 
                    *    nC         2
13865
 
                    *
13866
 
                    * removed the first node in the node-set, then
13867
 
                    * the context position of the
13868
 
                    */
13869
 
                    for (i = 0; i < oldset->nodeNr; i++) {
13870
 
                        /*
13871
 
                         * Run the evaluation with a node list made of
13872
 
                         * a single item in the nodeset.
13873
 
                         */
13874
 
                        ctxt->context->node = oldset->nodeTab[i];
13875
 
                        if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13876
 
                            (oldset->nodeTab[i]->doc != NULL))
13877
 
                            ctxt->context->doc = oldset->nodeTab[i]->doc;
13878
 
                        if (tmp == NULL) {
13879
 
                            tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13880
 
                                ctxt->context->node);
13881
 
                        } else {
13882
 
                            if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13883
 
                                               ctxt->context->node) < 0) {
13884
 
                                ctxt->error = XPATH_MEMORY_ERROR;
13885
 
                            }
13886
 
                        }
13887
 
                        valuePush(ctxt, tmp);
13888
 
                        ctxt->context->contextSize = oldset->nodeNr;
13889
 
                        ctxt->context->proximityPosition = i + 1;
13890
 
                        /*
13891
 
                        * Evaluate the predicate against the context node.
13892
 
                        * Can/should we optimize position() predicates
13893
 
                        * here (e.g. "[1]")?
13894
 
                        */
13895
 
                        if (op->ch2 != -1)
13896
 
                            total +=
13897
 
                                xmlXPathCompOpEval(ctxt,
13898
 
                                                   &comp->steps[op->ch2]);
13899
 
                        if (ctxt->error != XPATH_EXPRESSION_OK) {
13900
 
                            xmlXPathFreeNodeSet(newset);
13901
 
                            xmlXPathFreeObject(obj);
13902
 
                            return(0);
13903
 
                        }
13904
 
 
13905
 
                        /*
13906
 
                         * The result of the evaluation needs to be tested to
13907
 
                         * decide whether the filter succeeded or not
13908
 
                         */
13909
 
                        /*
13910
 
                        * OPTIMIZE TODO: Can we use
13911
 
                        * xmlXPathNodeSetAdd*Unique()* instead?
13912
 
                        */
13913
 
                        res = valuePop(ctxt);
13914
 
                        if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13915
 
                            if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
13916
 
                                < 0)
13917
 
                                ctxt->error = XPATH_MEMORY_ERROR;
13918
 
                        }
13919
 
 
13920
 
                        /*
13921
 
                         * Cleanup
13922
 
                         */
13923
 
                        if (res != NULL) {
13924
 
                            xmlXPathReleaseObject(ctxt->context, res);
13925
 
                        }
13926
 
                        if (ctxt->value == tmp) {
13927
 
                            valuePop(ctxt);
13928
 
                            xmlXPathNodeSetClear(tmp->nodesetval, 1);
13929
 
                            /*
13930
 
                            * Don't free the temporary nodeset
13931
 
                            * in order to avoid massive recreation inside this
13932
 
                            * loop.
13933
 
                            */
13934
 
                        } else
13935
 
                            tmp = NULL;
13936
 
                        ctxt->context->node = NULL;
13937
 
                    }
13938
 
                    if (tmp != NULL)
13939
 
                        xmlXPathReleaseObject(ctxt->context, tmp);
13940
 
                    /*
13941
 
                     * The result is used as the new evaluation set.
13942
 
                     */
13943
 
                    xmlXPathReleaseObject(ctxt->context, obj);
13944
 
                    ctxt->context->node = NULL;
13945
 
                    ctxt->context->contextSize = -1;
13946
 
                    ctxt->context->proximityPosition = -1;
13947
 
                    /* may want to move this past the '}' later */
13948
 
                    ctxt->context->doc = oldDoc;
13949
 
                    valuePush(ctxt,
13950
 
                        xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13951
 
                }
13952
 
                ctxt->context->node = oldnode;
13953
 
                return (total);
13954
 
            }
13955
 
        case XPATH_OP_SORT:
13956
 
            if (op->ch1 != -1)
13957
 
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13958
 
            CHECK_ERROR0;
13959
 
            if ((ctxt->value != NULL) &&
13960
 
                (ctxt->value->type == XPATH_NODESET) &&
13961
 
                (ctxt->value->nodesetval != NULL) &&
13962
 
                (ctxt->value->nodesetval->nodeNr > 1))
13963
 
            {
13964
 
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
13965
 
            }
13966
 
            return (total);
13967
 
#ifdef LIBXML_XPTR_ENABLED
13968
 
        case XPATH_OP_RANGETO:{
13969
 
                xmlXPathObjectPtr range;
13970
 
                xmlXPathObjectPtr res, obj;
13971
 
                xmlXPathObjectPtr tmp;
13972
 
                xmlLocationSetPtr newlocset = NULL;
13973
 
                    xmlLocationSetPtr oldlocset;
13974
 
                xmlNodeSetPtr oldset;
13975
 
                int i, j;
13976
 
 
13977
 
                if (op->ch1 != -1)
13978
 
                    total +=
13979
 
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13980
 
                if (op->ch2 == -1)
13981
 
                    return (total);
13982
 
 
13983
 
                if (ctxt->value->type == XPATH_LOCATIONSET) {
13984
 
                    /*
13985
 
                     * Extract the old locset, and then evaluate the result of the
13986
 
                     * expression for all the element in the locset. use it to grow
13987
 
                     * up a new locset.
13988
 
                     */
13989
 
                    CHECK_TYPE0(XPATH_LOCATIONSET);
13990
 
                    obj = valuePop(ctxt);
13991
 
                    oldlocset = obj->user;
13992
 
 
13993
 
                    if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13994
 
                        ctxt->context->node = NULL;
13995
 
                        ctxt->context->contextSize = 0;
13996
 
                        ctxt->context->proximityPosition = 0;
13997
 
                        total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13998
 
                        res = valuePop(ctxt);
13999
 
                        if (res != NULL) {
14000
 
                            xmlXPathReleaseObject(ctxt->context, res);
14001
 
                        }
14002
 
                        valuePush(ctxt, obj);
14003
 
                        CHECK_ERROR0;
14004
 
                        return (total);
14005
 
                    }
14006
 
                    newlocset = xmlXPtrLocationSetCreate(NULL);
14007
 
 
14008
 
                    for (i = 0; i < oldlocset->locNr; i++) {
14009
 
                        /*
14010
 
                         * Run the evaluation with a node list made of a
14011
 
                         * single item in the nodelocset.
14012
 
                         */
14013
 
                        ctxt->context->node = oldlocset->locTab[i]->user;
14014
 
                        ctxt->context->contextSize = oldlocset->locNr;
14015
 
                        ctxt->context->proximityPosition = i + 1;
14016
 
                        tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14017
 
                            ctxt->context->node);
14018
 
                        valuePush(ctxt, tmp);
14019
 
 
14020
 
                        if (op->ch2 != -1)
14021
 
                            total +=
14022
 
                                xmlXPathCompOpEval(ctxt,
14023
 
                                                   &comp->steps[op->ch2]);
14024
 
                        if (ctxt->error != XPATH_EXPRESSION_OK) {
14025
 
                            xmlXPathFreeObject(obj);
14026
 
                            return(0);
14027
 
                        }
14028
 
 
14029
 
                        res = valuePop(ctxt);
14030
 
                        if (res->type == XPATH_LOCATIONSET) {
14031
 
                            xmlLocationSetPtr rloc =
14032
 
                                (xmlLocationSetPtr)res->user;
14033
 
                            for (j=0; j<rloc->locNr; j++) {
14034
 
                                range = xmlXPtrNewRange(
14035
 
                                  oldlocset->locTab[i]->user,
14036
 
                                  oldlocset->locTab[i]->index,
14037
 
                                  rloc->locTab[j]->user2,
14038
 
                                  rloc->locTab[j]->index2);
14039
 
                                if (range != NULL) {
14040
 
                                    xmlXPtrLocationSetAdd(newlocset, range);
14041
 
                                }
14042
 
                            }
14043
 
                        } else {
14044
 
                            range = xmlXPtrNewRangeNodeObject(
14045
 
                                (xmlNodePtr)oldlocset->locTab[i]->user, res);
14046
 
                            if (range != NULL) {
14047
 
                                xmlXPtrLocationSetAdd(newlocset,range);
14048
 
                            }
14049
 
                        }
14050
 
 
14051
 
                        /*
14052
 
                         * Cleanup
14053
 
                         */
14054
 
                        if (res != NULL) {
14055
 
                            xmlXPathReleaseObject(ctxt->context, res);
14056
 
                        }
14057
 
                        if (ctxt->value == tmp) {
14058
 
                            res = valuePop(ctxt);
14059
 
                            xmlXPathReleaseObject(ctxt->context, res);
14060
 
                        }
14061
 
 
14062
 
                        ctxt->context->node = NULL;
14063
 
                    }
14064
 
                } else {        /* Not a location set */
14065
 
                    CHECK_TYPE0(XPATH_NODESET);
14066
 
                    obj = valuePop(ctxt);
14067
 
                    oldset = obj->nodesetval;
14068
 
                    ctxt->context->node = NULL;
14069
 
 
14070
 
                    newlocset = xmlXPtrLocationSetCreate(NULL);
14071
 
 
14072
 
                    if (oldset != NULL) {
14073
 
                        for (i = 0; i < oldset->nodeNr; i++) {
14074
 
                            /*
14075
 
                             * Run the evaluation with a node list made of a single item
14076
 
                             * in the nodeset.
14077
 
                             */
14078
 
                            ctxt->context->node = oldset->nodeTab[i];
14079
 
                            /*
14080
 
                            * OPTIMIZE TODO: Avoid recreation for every iteration.
14081
 
                            */
14082
 
                            tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14083
 
                                ctxt->context->node);
14084
 
                            valuePush(ctxt, tmp);
14085
 
 
14086
 
                            if (op->ch2 != -1)
14087
 
                                total +=
14088
 
                                    xmlXPathCompOpEval(ctxt,
14089
 
                                                   &comp->steps[op->ch2]);
14090
 
                            if (ctxt->error != XPATH_EXPRESSION_OK) {
14091
 
                                xmlXPathFreeObject(obj);
14092
 
                                return(0);
14093
 
                            }
14094
 
 
14095
 
                            res = valuePop(ctxt);
14096
 
                            range =
14097
 
                                xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14098
 
                                                      res);
14099
 
                            if (range != NULL) {
14100
 
                                xmlXPtrLocationSetAdd(newlocset, range);
14101
 
                            }
14102
 
 
14103
 
                            /*
14104
 
                             * Cleanup
14105
 
                             */
14106
 
                            if (res != NULL) {
14107
 
                                xmlXPathReleaseObject(ctxt->context, res);
14108
 
                            }
14109
 
                            if (ctxt->value == tmp) {
14110
 
                                res = valuePop(ctxt);
14111
 
                                xmlXPathReleaseObject(ctxt->context, res);
14112
 
                            }
14113
 
 
14114
 
                            ctxt->context->node = NULL;
14115
 
                        }
14116
 
                    }
14117
 
                }
14118
 
 
14119
 
                /*
14120
 
                 * The result is used as the new evaluation set.
14121
 
                 */
14122
 
                xmlXPathReleaseObject(ctxt->context, obj);
14123
 
                ctxt->context->node = NULL;
14124
 
                ctxt->context->contextSize = -1;
14125
 
                ctxt->context->proximityPosition = -1;
14126
 
                valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
14127
 
                return (total);
14128
 
            }
14129
 
#endif /* LIBXML_XPTR_ENABLED */
14130
 
    }
14131
 
    xmlGenericError(xmlGenericErrorContext,
14132
 
                    "XPath: unknown precompiled operation %d\n", op->op);
14133
 
    ctxt->error = XPATH_INVALID_OPERAND;
14134
 
    return (total);
14135
 
}
14136
 
 
14137
 
/**
14138
 
 * xmlXPathCompOpEvalToBoolean:
14139
 
 * @ctxt:  the XPath parser context
14140
 
 *
14141
 
 * Evaluates if the expression evaluates to true.
14142
 
 *
14143
 
 * Returns 1 if true, 0 if false and -1 on API or internal errors.
14144
 
 */
14145
 
static int
14146
 
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
14147
 
                            xmlXPathStepOpPtr op,
14148
 
                            int isPredicate)
14149
 
{
14150
 
    xmlXPathObjectPtr resObj = NULL;
14151
 
 
14152
 
start:
14153
 
    /* comp = ctxt->comp; */
14154
 
    switch (op->op) {
14155
 
        case XPATH_OP_END:
14156
 
            return (0);
14157
 
        case XPATH_OP_VALUE:
14158
 
            resObj = (xmlXPathObjectPtr) op->value4;
14159
 
            if (isPredicate)
14160
 
                return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14161
 
            return(xmlXPathCastToBoolean(resObj));
14162
 
        case XPATH_OP_SORT:
14163
 
            /*
14164
 
            * We don't need sorting for boolean results. Skip this one.
14165
 
            */
14166
 
            if (op->ch1 != -1) {
14167
 
                op = &ctxt->comp->steps[op->ch1];
14168
 
                goto start;
14169
 
            }
14170
 
            return(0);
14171
 
        case XPATH_OP_COLLECT:
14172
 
            if (op->ch1 == -1)
14173
 
                return(0);
14174
 
 
14175
 
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14176
 
            if (ctxt->error != XPATH_EXPRESSION_OK)
14177
 
                return(-1);
14178
 
 
14179
 
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14180
 
            if (ctxt->error != XPATH_EXPRESSION_OK)
14181
 
                return(-1);
14182
 
 
14183
 
            resObj = valuePop(ctxt);
14184
 
            if (resObj == NULL)
14185
 
                return(-1);
14186
 
            break;
14187
 
        default:
14188
 
            /*
14189
 
            * Fallback to call xmlXPathCompOpEval().
14190
 
            */
14191
 
            xmlXPathCompOpEval(ctxt, op);
14192
 
            if (ctxt->error != XPATH_EXPRESSION_OK)
14193
 
                return(-1);
14194
 
 
14195
 
            resObj = valuePop(ctxt);
14196
 
            if (resObj == NULL)
14197
 
                return(-1);
14198
 
            break;
14199
 
    }
14200
 
 
14201
 
    if (resObj) {
14202
 
        int res;
14203
 
 
14204
 
        if (resObj->type == XPATH_BOOLEAN) {
14205
 
            res = resObj->boolval;
14206
 
        } else if (isPredicate) {
14207
 
            /*
14208
 
            * For predicates a result of type "number" is handled
14209
 
            * differently:
14210
 
            * SPEC XPath 1.0:
14211
 
            * "If the result is a number, the result will be converted
14212
 
            *  to true if the number is equal to the context position
14213
 
            *  and will be converted to false otherwise;"
14214
 
            */
14215
 
            res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14216
 
        } else {
14217
 
            res = xmlXPathCastToBoolean(resObj);
14218
 
        }
14219
 
        xmlXPathReleaseObject(ctxt->context, resObj);
14220
 
        return(res);
14221
 
    }
14222
 
 
14223
 
    return(0);
14224
 
}
14225
 
 
14226
 
#ifdef XPATH_STREAMING
14227
 
/**
14228
 
 * xmlXPathRunStreamEval:
14229
 
 * @ctxt:  the XPath parser context with the compiled expression
14230
 
 *
14231
 
 * Evaluate the Precompiled Streamable XPath expression in the given context.
14232
 
 */
14233
 
static int
14234
 
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14235
 
                      xmlXPathObjectPtr *resultSeq, int toBool)
14236
 
{
14237
 
    int max_depth, min_depth;
14238
 
    int from_root;
14239
 
    int ret, depth;
14240
 
    int eval_all_nodes;
14241
 
    xmlNodePtr cur = NULL, limit = NULL;
14242
 
    xmlStreamCtxtPtr patstream = NULL;
14243
 
 
14244
 
    int nb_nodes = 0;
14245
 
 
14246
 
    if ((ctxt == NULL) || (comp == NULL))
14247
 
        return(-1);
14248
 
    max_depth = xmlPatternMaxDepth(comp);
14249
 
    if (max_depth == -1)
14250
 
        return(-1);
14251
 
    if (max_depth == -2)
14252
 
        max_depth = 10000;
14253
 
    min_depth = xmlPatternMinDepth(comp);
14254
 
    if (min_depth == -1)
14255
 
        return(-1);
14256
 
    from_root = xmlPatternFromRoot(comp);
14257
 
    if (from_root < 0)
14258
 
        return(-1);
14259
 
#if 0
14260
 
    printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14261
 
#endif
14262
 
 
14263
 
    if (! toBool) {
14264
 
        if (resultSeq == NULL)
14265
 
            return(-1);
14266
 
        *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14267
 
        if (*resultSeq == NULL)
14268
 
            return(-1);
14269
 
    }
14270
 
 
14271
 
    /*
14272
 
     * handle the special cases of "/" amd "." being matched
14273
 
     */
14274
 
    if (min_depth == 0) {
14275
 
        if (from_root) {
14276
 
            /* Select "/" */
14277
 
            if (toBool)
14278
 
                return(1);
14279
 
            xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14280
 
                                     (xmlNodePtr) ctxt->doc);
14281
 
        } else {
14282
 
            /* Select "self::node()" */
14283
 
            if (toBool)
14284
 
                return(1);
14285
 
            xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14286
 
        }
14287
 
    }
14288
 
    if (max_depth == 0) {
14289
 
        return(0);
14290
 
    }
14291
 
 
14292
 
    if (from_root) {
14293
 
        cur = (xmlNodePtr)ctxt->doc;
14294
 
    } else if (ctxt->node != NULL) {
14295
 
        switch (ctxt->node->type) {
14296
 
            case XML_ELEMENT_NODE:
14297
 
            case XML_DOCUMENT_NODE:
14298
 
            case XML_DOCUMENT_FRAG_NODE:
14299
 
            case XML_HTML_DOCUMENT_NODE:
14300
 
#ifdef LIBXML_DOCB_ENABLED
14301
 
            case XML_DOCB_DOCUMENT_NODE:
14302
 
#endif
14303
 
                cur = ctxt->node;
14304
 
                break;
14305
 
            case XML_ATTRIBUTE_NODE:
14306
 
            case XML_TEXT_NODE:
14307
 
            case XML_CDATA_SECTION_NODE:
14308
 
            case XML_ENTITY_REF_NODE:
14309
 
            case XML_ENTITY_NODE:
14310
 
            case XML_PI_NODE:
14311
 
            case XML_COMMENT_NODE:
14312
 
            case XML_NOTATION_NODE:
14313
 
            case XML_DTD_NODE:
14314
 
            case XML_DOCUMENT_TYPE_NODE:
14315
 
            case XML_ELEMENT_DECL:
14316
 
            case XML_ATTRIBUTE_DECL:
14317
 
            case XML_ENTITY_DECL:
14318
 
            case XML_NAMESPACE_DECL:
14319
 
            case XML_XINCLUDE_START:
14320
 
            case XML_XINCLUDE_END:
14321
 
                break;
14322
 
        }
14323
 
        limit = cur;
14324
 
    }
14325
 
    if (cur == NULL) {
14326
 
        return(0);
14327
 
    }
14328
 
 
14329
 
    patstream = xmlPatternGetStreamCtxt(comp);
14330
 
    if (patstream == NULL) {
14331
 
        /*
14332
 
        * QUESTION TODO: Is this an error?
14333
 
        */
14334
 
        return(0);
14335
 
    }
14336
 
 
14337
 
    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14338
 
 
14339
 
    if (from_root) {
14340
 
        ret = xmlStreamPush(patstream, NULL, NULL);
14341
 
        if (ret < 0) {
14342
 
        } else if (ret == 1) {
14343
 
            if (toBool)
14344
 
                goto return_1;
14345
 
            xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14346
 
        }
14347
 
    }
14348
 
    depth = 0;
14349
 
    goto scan_children;
14350
 
next_node:
14351
 
    do {
14352
 
        nb_nodes++;
14353
 
 
14354
 
        switch (cur->type) {
14355
 
            case XML_ELEMENT_NODE:
14356
 
            case XML_TEXT_NODE:
14357
 
            case XML_CDATA_SECTION_NODE:
14358
 
            case XML_COMMENT_NODE:
14359
 
            case XML_PI_NODE:
14360
 
                if (cur->type == XML_ELEMENT_NODE) {
14361
 
                    ret = xmlStreamPush(patstream, cur->name,
14362
 
                                (cur->ns ? cur->ns->href : NULL));
14363
 
                } else if (eval_all_nodes)
14364
 
                    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14365
 
                else
14366
 
                    break;
14367
 
 
14368
 
                if (ret < 0) {
14369
 
                    /* NOP. */
14370
 
                } else if (ret == 1) {
14371
 
                    if (toBool)
14372
 
                        goto return_1;
14373
 
                    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
14374
 
                        < 0) {
14375
 
                        ctxt->lastError.domain = XML_FROM_XPATH;
14376
 
                        ctxt->lastError.code = XML_ERR_NO_MEMORY;
14377
 
                    }
14378
 
                }
14379
 
                if ((cur->children == NULL) || (depth >= max_depth)) {
14380
 
                    ret = xmlStreamPop(patstream);
14381
 
                    while (cur->next != NULL) {
14382
 
                        cur = cur->next;
14383
 
                        if ((cur->type != XML_ENTITY_DECL) &&
14384
 
                            (cur->type != XML_DTD_NODE))
14385
 
                            goto next_node;
14386
 
                    }
14387
 
                }
14388
 
            default:
14389
 
                break;
14390
 
        }
14391
 
 
14392
 
scan_children:
14393
 
        if (cur->type == XML_NAMESPACE_DECL) break;
14394
 
        if ((cur->children != NULL) && (depth < max_depth)) {
14395
 
            /*
14396
 
             * Do not descend on entities declarations
14397
 
             */
14398
 
            if (cur->children->type != XML_ENTITY_DECL) {
14399
 
                cur = cur->children;
14400
 
                depth++;
14401
 
                /*
14402
 
                 * Skip DTDs
14403
 
                 */
14404
 
                if (cur->type != XML_DTD_NODE)
14405
 
                    continue;
14406
 
            }
14407
 
        }
14408
 
 
14409
 
        if (cur == limit)
14410
 
            break;
14411
 
 
14412
 
        while (cur->next != NULL) {
14413
 
            cur = cur->next;
14414
 
            if ((cur->type != XML_ENTITY_DECL) &&
14415
 
                (cur->type != XML_DTD_NODE))
14416
 
                goto next_node;
14417
 
        }
14418
 
 
14419
 
        do {
14420
 
            cur = cur->parent;
14421
 
            depth--;
14422
 
            if ((cur == NULL) || (cur == limit))
14423
 
                goto done;
14424
 
            if (cur->type == XML_ELEMENT_NODE) {
14425
 
                ret = xmlStreamPop(patstream);
14426
 
            } else if ((eval_all_nodes) &&
14427
 
                ((cur->type == XML_TEXT_NODE) ||
14428
 
                 (cur->type == XML_CDATA_SECTION_NODE) ||
14429
 
                 (cur->type == XML_COMMENT_NODE) ||
14430
 
                 (cur->type == XML_PI_NODE)))
14431
 
            {
14432
 
                ret = xmlStreamPop(patstream);
14433
 
            }
14434
 
            if (cur->next != NULL) {
14435
 
                cur = cur->next;
14436
 
                break;
14437
 
            }
14438
 
        } while (cur != NULL);
14439
 
 
14440
 
    } while ((cur != NULL) && (depth >= 0));
14441
 
 
14442
 
done:
14443
 
 
14444
 
#if 0
14445
 
    printf("stream eval: checked %d nodes selected %d\n",
14446
 
           nb_nodes, retObj->nodesetval->nodeNr);
14447
 
#endif
14448
 
 
14449
 
    if (patstream)
14450
 
        xmlFreeStreamCtxt(patstream);
14451
 
    return(0);
14452
 
 
14453
 
return_1:
14454
 
    if (patstream)
14455
 
        xmlFreeStreamCtxt(patstream);
14456
 
    return(1);
14457
 
}
14458
 
#endif /* XPATH_STREAMING */
14459
 
 
14460
 
/**
14461
 
 * xmlXPathRunEval:
14462
 
 * @ctxt:  the XPath parser context with the compiled expression
14463
 
 * @toBool:  evaluate to a boolean result
14464
 
 *
14465
 
 * Evaluate the Precompiled XPath expression in the given context.
14466
 
 */
14467
 
static int
14468
 
xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14469
 
{
14470
 
    xmlXPathCompExprPtr comp;
14471
 
 
14472
 
    if ((ctxt == NULL) || (ctxt->comp == NULL))
14473
 
        return(-1);
14474
 
 
14475
 
    if (ctxt->valueTab == NULL) {
14476
 
        /* Allocate the value stack */
14477
 
        ctxt->valueTab = (xmlXPathObjectPtr *)
14478
 
                         xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14479
 
        if (ctxt->valueTab == NULL) {
14480
 
            xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14481
 
            xmlFree(ctxt);
14482
 
        }
14483
 
        ctxt->valueNr = 0;
14484
 
        ctxt->valueMax = 10;
14485
 
        ctxt->value = NULL;
14486
 
        ctxt->valueFrame = 0;
14487
 
    }
14488
 
#ifdef XPATH_STREAMING
14489
 
    if (ctxt->comp->stream) {
14490
 
        int res;
14491
 
 
14492
 
        if (toBool) {
14493
 
            /*
14494
 
            * Evaluation to boolean result.
14495
 
            */
14496
 
            res = xmlXPathRunStreamEval(ctxt->context,
14497
 
                ctxt->comp->stream, NULL, 1);
14498
 
            if (res != -1)
14499
 
                return(res);
14500
 
        } else {
14501
 
            xmlXPathObjectPtr resObj = NULL;
14502
 
 
14503
 
            /*
14504
 
            * Evaluation to a sequence.
14505
 
            */
14506
 
            res = xmlXPathRunStreamEval(ctxt->context,
14507
 
                ctxt->comp->stream, &resObj, 0);
14508
 
 
14509
 
            if ((res != -1) && (resObj != NULL)) {
14510
 
                valuePush(ctxt, resObj);
14511
 
                return(0);
14512
 
            }
14513
 
            if (resObj != NULL)
14514
 
                xmlXPathReleaseObject(ctxt->context, resObj);
14515
 
        }
14516
 
        /*
14517
 
        * QUESTION TODO: This falls back to normal XPath evaluation
14518
 
        * if res == -1. Is this intended?
14519
 
        */
14520
 
    }
14521
 
#endif
14522
 
    comp = ctxt->comp;
14523
 
    if (comp->last < 0) {
14524
 
        xmlGenericError(xmlGenericErrorContext,
14525
 
            "xmlXPathRunEval: last is less than zero\n");
14526
 
        return(-1);
14527
 
    }
14528
 
    if (toBool)
14529
 
        return(xmlXPathCompOpEvalToBoolean(ctxt,
14530
 
            &comp->steps[comp->last], 0));
14531
 
    else
14532
 
        xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14533
 
 
14534
 
    return(0);
14535
 
}
14536
 
 
14537
 
/************************************************************************
14538
 
 *                                                                      *
14539
 
 *                      Public interfaces                               *
14540
 
 *                                                                      *
14541
 
 ************************************************************************/
14542
 
 
14543
 
/**
14544
 
 * xmlXPathEvalPredicate:
14545
 
 * @ctxt:  the XPath context
14546
 
 * @res:  the Predicate Expression evaluation result
14547
 
 *
14548
 
 * Evaluate a predicate result for the current node.
14549
 
 * A PredicateExpr is evaluated by evaluating the Expr and converting
14550
 
 * the result to a boolean. If the result is a number, the result will
14551
 
 * be converted to true if the number is equal to the position of the
14552
 
 * context node in the context node list (as returned by the position
14553
 
 * function) and will be converted to false otherwise; if the result
14554
 
 * is not a number, then the result will be converted as if by a call
14555
 
 * to the boolean function.
14556
 
 *
14557
 
 * Returns 1 if predicate is true, 0 otherwise
14558
 
 */
14559
 
int
14560
 
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14561
 
    if ((ctxt == NULL) || (res == NULL)) return(0);
14562
 
    switch (res->type) {
14563
 
        case XPATH_BOOLEAN:
14564
 
            return(res->boolval);
14565
 
        case XPATH_NUMBER:
14566
 
            return(res->floatval == ctxt->proximityPosition);
14567
 
        case XPATH_NODESET:
14568
 
        case XPATH_XSLT_TREE:
14569
 
            if (res->nodesetval == NULL)
14570
 
                return(0);
14571
 
            return(res->nodesetval->nodeNr != 0);
14572
 
        case XPATH_STRING:
14573
 
            return((res->stringval != NULL) &&
14574
 
                   (xmlStrlen(res->stringval) != 0));
14575
 
        default:
14576
 
            STRANGE
14577
 
    }
14578
 
    return(0);
14579
 
}
14580
 
 
14581
 
/**
14582
 
 * xmlXPathEvaluatePredicateResult:
14583
 
 * @ctxt:  the XPath Parser context
14584
 
 * @res:  the Predicate Expression evaluation result
14585
 
 *
14586
 
 * Evaluate a predicate result for the current node.
14587
 
 * A PredicateExpr is evaluated by evaluating the Expr and converting
14588
 
 * the result to a boolean. If the result is a number, the result will
14589
 
 * be converted to true if the number is equal to the position of the
14590
 
 * context node in the context node list (as returned by the position
14591
 
 * function) and will be converted to false otherwise; if the result
14592
 
 * is not a number, then the result will be converted as if by a call
14593
 
 * to the boolean function.
14594
 
 *
14595
 
 * Returns 1 if predicate is true, 0 otherwise
14596
 
 */
14597
 
int
14598
 
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14599
 
                                xmlXPathObjectPtr res) {
14600
 
    if ((ctxt == NULL) || (res == NULL)) return(0);
14601
 
    switch (res->type) {
14602
 
        case XPATH_BOOLEAN:
14603
 
            return(res->boolval);
14604
 
        case XPATH_NUMBER:
14605
 
#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14606
 
            return((res->floatval == ctxt->context->proximityPosition) &&
14607
 
                   (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14608
 
#else
14609
 
            return(res->floatval == ctxt->context->proximityPosition);
14610
 
#endif
14611
 
        case XPATH_NODESET:
14612
 
        case XPATH_XSLT_TREE:
14613
 
            if (res->nodesetval == NULL)
14614
 
                return(0);
14615
 
            return(res->nodesetval->nodeNr != 0);
14616
 
        case XPATH_STRING:
14617
 
            return((res->stringval != NULL) && (res->stringval[0] != 0));
14618
 
#ifdef LIBXML_XPTR_ENABLED
14619
 
        case XPATH_LOCATIONSET:{
14620
 
            xmlLocationSetPtr ptr = res->user;
14621
 
            if (ptr == NULL)
14622
 
                return(0);
14623
 
            return (ptr->locNr != 0);
14624
 
            }
14625
 
#endif
14626
 
        default:
14627
 
            STRANGE
14628
 
    }
14629
 
    return(0);
14630
 
}
14631
 
 
14632
 
#ifdef XPATH_STREAMING
14633
 
/**
14634
 
 * xmlXPathTryStreamCompile:
14635
 
 * @ctxt: an XPath context
14636
 
 * @str:  the XPath expression
14637
 
 *
14638
 
 * Try to compile the XPath expression as a streamable subset.
14639
 
 *
14640
 
 * Returns the compiled expression or NULL if failed to compile.
14641
 
 */
14642
 
static xmlXPathCompExprPtr
14643
 
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14644
 
    /*
14645
 
     * Optimization: use streaming patterns when the XPath expression can
14646
 
     * be compiled to a stream lookup
14647
 
     */
14648
 
    xmlPatternPtr stream;
14649
 
    xmlXPathCompExprPtr comp;
14650
 
    xmlDictPtr dict = NULL;
14651
 
    const xmlChar **namespaces = NULL;
14652
 
    xmlNsPtr ns;
14653
 
    int i, j;
14654
 
 
14655
 
    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14656
 
        (!xmlStrchr(str, '@'))) {
14657
 
        const xmlChar *tmp;
14658
 
 
14659
 
        /*
14660
 
         * We don't try to handle expressions using the verbose axis
14661
 
         * specifiers ("::"), just the simplied form at this point.
14662
 
         * Additionally, if there is no list of namespaces available and
14663
 
         *  there's a ":" in the expression, indicating a prefixed QName,
14664
 
         *  then we won't try to compile either. xmlPatterncompile() needs
14665
 
         *  to have a list of namespaces at compilation time in order to
14666
 
         *  compile prefixed name tests.
14667
 
         */
14668
 
        tmp = xmlStrchr(str, ':');
14669
 
        if ((tmp != NULL) &&
14670
 
            ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14671
 
            return(NULL);
14672
 
 
14673
 
        if (ctxt != NULL) {
14674
 
            dict = ctxt->dict;
14675
 
            if (ctxt->nsNr > 0) {
14676
 
                namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14677
 
                if (namespaces == NULL) {
14678
 
                    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14679
 
                    return(NULL);
14680
 
                }
14681
 
                for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14682
 
                    ns = ctxt->namespaces[j];
14683
 
                    namespaces[i++] = ns->href;
14684
 
                    namespaces[i++] = ns->prefix;
14685
 
                }
14686
 
                namespaces[i++] = NULL;
14687
 
                namespaces[i] = NULL;
14688
 
            }
14689
 
        }
14690
 
 
14691
 
        stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14692
 
                        &namespaces[0]);
14693
 
        if (namespaces != NULL) {
14694
 
            xmlFree((xmlChar **)namespaces);
14695
 
        }
14696
 
        if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14697
 
            comp = xmlXPathNewCompExpr();
14698
 
            if (comp == NULL) {
14699
 
                xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14700
 
                return(NULL);
14701
 
            }
14702
 
            comp->stream = stream;
14703
 
            comp->dict = dict;
14704
 
            if (comp->dict)
14705
 
                xmlDictReference(comp->dict);
14706
 
            return(comp);
14707
 
        }
14708
 
        xmlFreePattern(stream);
14709
 
    }
14710
 
    return(NULL);
14711
 
}
14712
 
#endif /* XPATH_STREAMING */
14713
 
 
14714
 
static void
14715
 
xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14716
 
{
14717
 
    /*
14718
 
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14719
 
    * internal representation.
14720
 
    */
14721
 
 
14722
 
    if ((op->ch1 != -1) &&
14723
 
        (op->op == XPATH_OP_COLLECT /* 11 */))
14724
 
    {
14725
 
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14726
 
 
14727
 
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14728
 
            ((xmlXPathAxisVal) prevop->value ==
14729
 
                AXIS_DESCENDANT_OR_SELF) &&
14730
 
            (prevop->ch2 == -1) &&
14731
 
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14732
 
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14733
 
        {
14734
 
            /*
14735
 
            * This is a "descendant-or-self::node()" without predicates.
14736
 
            * Try to eliminate it.
14737
 
            */
14738
 
 
14739
 
            switch ((xmlXPathAxisVal) op->value) {
14740
 
                case AXIS_CHILD:
14741
 
                case AXIS_DESCENDANT:
14742
 
                    /*
14743
 
                    * Convert "descendant-or-self::node()/child::" or
14744
 
                    * "descendant-or-self::node()/descendant::" to
14745
 
                    * "descendant::"
14746
 
                    */
14747
 
                    op->ch1   = prevop->ch1;
14748
 
                    op->value = AXIS_DESCENDANT;
14749
 
                    break;
14750
 
                case AXIS_SELF:
14751
 
                case AXIS_DESCENDANT_OR_SELF:
14752
 
                    /*
14753
 
                    * Convert "descendant-or-self::node()/self::" or
14754
 
                    * "descendant-or-self::node()/descendant-or-self::" to
14755
 
                    * to "descendant-or-self::"
14756
 
                    */
14757
 
                    op->ch1   = prevop->ch1;
14758
 
                    op->value = AXIS_DESCENDANT_OR_SELF;
14759
 
                    break;
14760
 
                default:
14761
 
                    break;
14762
 
            }
14763
 
        }
14764
 
    }
14765
 
 
14766
 
    /* Recurse */
14767
 
    if (op->ch1 != -1)
14768
 
        xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
14769
 
    if (op->ch2 != -1)
14770
 
        xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
14771
 
}
14772
 
 
14773
 
/**
14774
 
 * xmlXPathCtxtCompile:
14775
 
 * @ctxt: an XPath context
14776
 
 * @str:  the XPath expression
14777
 
 *
14778
 
 * Compile an XPath expression
14779
 
 *
14780
 
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14781
 
 *         the caller has to free the object.
14782
 
 */
14783
 
xmlXPathCompExprPtr
14784
 
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14785
 
    xmlXPathParserContextPtr pctxt;
14786
 
    xmlXPathCompExprPtr comp;
14787
 
 
14788
 
#ifdef XPATH_STREAMING
14789
 
    comp = xmlXPathTryStreamCompile(ctxt, str);
14790
 
    if (comp != NULL)
14791
 
        return(comp);
14792
 
#endif
14793
 
 
14794
 
    xmlXPathInit();
14795
 
 
14796
 
    pctxt = xmlXPathNewParserContext(str, ctxt);
14797
 
    if (pctxt == NULL)
14798
 
        return NULL;
14799
 
    xmlXPathCompileExpr(pctxt, 1);
14800
 
 
14801
 
    if( pctxt->error != XPATH_EXPRESSION_OK )
14802
 
    {
14803
 
        xmlXPathFreeParserContext(pctxt);
14804
 
        return(NULL);
14805
 
    }
14806
 
 
14807
 
    if (*pctxt->cur != 0) {
14808
 
        /*
14809
 
         * aleksey: in some cases this line prints *second* error message
14810
 
         * (see bug #78858) and probably this should be fixed.
14811
 
         * However, we are not sure that all error messages are printed
14812
 
         * out in other places. It's not critical so we leave it as-is for now
14813
 
         */
14814
 
        xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14815
 
        comp = NULL;
14816
 
    } else {
14817
 
        comp = pctxt->comp;
14818
 
        pctxt->comp = NULL;
14819
 
    }
14820
 
    xmlXPathFreeParserContext(pctxt);
14821
 
 
14822
 
    if (comp != NULL) {
14823
 
        comp->expr = xmlStrdup(str);
14824
 
#ifdef DEBUG_EVAL_COUNTS
14825
 
        comp->string = xmlStrdup(str);
14826
 
        comp->nb = 0;
14827
 
#endif
14828
 
        if ((comp->nbStep > 1) && (comp->last >= 0)) {
14829
 
            xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
14830
 
        }
14831
 
    }
14832
 
    return(comp);
14833
 
}
14834
 
 
14835
 
/**
14836
 
 * xmlXPathCompile:
14837
 
 * @str:  the XPath expression
14838
 
 *
14839
 
 * Compile an XPath expression
14840
 
 *
14841
 
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14842
 
 *         the caller has to free the object.
14843
 
 */
14844
 
xmlXPathCompExprPtr
14845
 
xmlXPathCompile(const xmlChar *str) {
14846
 
    return(xmlXPathCtxtCompile(NULL, str));
14847
 
}
14848
 
 
14849
 
/**
14850
 
 * xmlXPathCompiledEvalInternal:
14851
 
 * @comp:  the compiled XPath expression
14852
 
 * @ctxt:  the XPath context
14853
 
 * @resObj: the resulting XPath object or NULL
14854
 
 * @toBool: 1 if only a boolean result is requested
14855
 
 *
14856
 
 * Evaluate the Precompiled XPath expression in the given context.
14857
 
 * The caller has to free @resObj.
14858
 
 *
14859
 
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14860
 
 *         the caller has to free the object.
14861
 
 */
14862
 
static int
14863
 
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14864
 
                             xmlXPathContextPtr ctxt,
14865
 
                             xmlXPathObjectPtr *resObj,
14866
 
                             int toBool)
14867
 
{
14868
 
    xmlXPathParserContextPtr pctxt;
14869
 
#ifndef LIBXML_THREAD_ENABLED
14870
 
    static int reentance = 0;
14871
 
#endif
14872
 
    int res;
14873
 
 
14874
 
    CHECK_CTXT_NEG(ctxt)
14875
 
 
14876
 
    if (comp == NULL)
14877
 
        return(-1);
14878
 
    xmlXPathInit();
14879
 
 
14880
 
#ifndef LIBXML_THREAD_ENABLED
14881
 
    reentance++;
14882
 
    if (reentance > 1)
14883
 
        xmlXPathDisableOptimizer = 1;
14884
 
#endif
14885
 
 
14886
 
#ifdef DEBUG_EVAL_COUNTS
14887
 
    comp->nb++;
14888
 
    if ((comp->string != NULL) && (comp->nb > 100)) {
14889
 
        fprintf(stderr, "100 x %s\n", comp->string);
14890
 
        comp->nb = 0;
14891
 
    }
14892
 
#endif
14893
 
    pctxt = xmlXPathCompParserContext(comp, ctxt);
14894
 
    res = xmlXPathRunEval(pctxt, toBool);
14895
 
 
14896
 
    if (resObj) {
14897
 
        if (pctxt->value == NULL) {
14898
 
            xmlGenericError(xmlGenericErrorContext,
14899
 
                "xmlXPathCompiledEval: evaluation failed\n");
14900
 
            *resObj = NULL;
14901
 
        } else {
14902
 
            *resObj = valuePop(pctxt);
14903
 
        }
14904
 
    }
14905
 
 
14906
 
    /*
14907
 
    * Pop all remaining objects from the stack.
14908
 
    */
14909
 
    if (pctxt->valueNr > 0) {
14910
 
        xmlXPathObjectPtr tmp;
14911
 
        int stack = 0;
14912
 
 
14913
 
        do {
14914
 
            tmp = valuePop(pctxt);
14915
 
            if (tmp != NULL) {
14916
 
                stack++;
14917
 
                xmlXPathReleaseObject(ctxt, tmp);
14918
 
            }
14919
 
        } while (tmp != NULL);
14920
 
        if ((stack != 0) &&
14921
 
            ((toBool) || ((resObj) && (*resObj))))
14922
 
        {
14923
 
            xmlGenericError(xmlGenericErrorContext,
14924
 
                "xmlXPathCompiledEval: %d objects left on the stack.\n",
14925
 
                stack);
14926
 
        }
14927
 
    }
14928
 
 
14929
 
    if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14930
 
        xmlXPathFreeObject(*resObj);
14931
 
        *resObj = NULL;
14932
 
    }
14933
 
    pctxt->comp = NULL;
14934
 
    xmlXPathFreeParserContext(pctxt);
14935
 
#ifndef LIBXML_THREAD_ENABLED
14936
 
    reentance--;
14937
 
#endif
14938
 
 
14939
 
    return(res);
14940
 
}
14941
 
 
14942
 
/**
14943
 
 * xmlXPathCompiledEval:
14944
 
 * @comp:  the compiled XPath expression
14945
 
 * @ctx:  the XPath context
14946
 
 *
14947
 
 * Evaluate the Precompiled XPath expression in the given context.
14948
 
 *
14949
 
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14950
 
 *         the caller has to free the object.
14951
 
 */
14952
 
xmlXPathObjectPtr
14953
 
xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14954
 
{
14955
 
    xmlXPathObjectPtr res = NULL;
14956
 
 
14957
 
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14958
 
    return(res);
14959
 
}
14960
 
 
14961
 
/**
14962
 
 * xmlXPathCompiledEvalToBoolean:
14963
 
 * @comp:  the compiled XPath expression
14964
 
 * @ctxt:  the XPath context
14965
 
 *
14966
 
 * Applies the XPath boolean() function on the result of the given
14967
 
 * compiled expression.
14968
 
 *
14969
 
 * Returns 1 if the expression evaluated to true, 0 if to false and
14970
 
 *         -1 in API and internal errors.
14971
 
 */
14972
 
int
14973
 
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14974
 
                              xmlXPathContextPtr ctxt)
14975
 
{
14976
 
    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14977
 
}
14978
 
 
14979
 
/**
14980
 
 * xmlXPathEvalExpr:
14981
 
 * @ctxt:  the XPath Parser context
14982
 
 *
14983
 
 * Parse and evaluate an XPath expression in the given context,
14984
 
 * then push the result on the context stack
14985
 
 */
14986
 
void
14987
 
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14988
 
#ifdef XPATH_STREAMING
14989
 
    xmlXPathCompExprPtr comp;
14990
 
#endif
14991
 
 
14992
 
    if (ctxt == NULL) return;
14993
 
 
14994
 
#ifdef XPATH_STREAMING
14995
 
    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14996
 
    if (comp != NULL) {
14997
 
        if (ctxt->comp != NULL)
14998
 
            xmlXPathFreeCompExpr(ctxt->comp);
14999
 
        ctxt->comp = comp;
15000
 
        if (ctxt->cur != NULL)
15001
 
            while (*ctxt->cur != 0) ctxt->cur++;
15002
 
    } else
15003
 
#endif
15004
 
    {
15005
 
        xmlXPathCompileExpr(ctxt, 1);
15006
 
        if ((ctxt->error == XPATH_EXPRESSION_OK) &&
15007
 
            (ctxt->comp != NULL) &&
15008
 
            (ctxt->comp->nbStep > 1) &&
15009
 
            (ctxt->comp->last >= 0))
15010
 
        {
15011
 
            xmlXPathOptimizeExpression(ctxt->comp,
15012
 
                &ctxt->comp->steps[ctxt->comp->last]);
15013
 
        }
15014
 
    }
15015
 
    CHECK_ERROR;
15016
 
    xmlXPathRunEval(ctxt, 0);
15017
 
}
15018
 
 
15019
 
/**
15020
 
 * xmlXPathEval:
15021
 
 * @str:  the XPath expression
15022
 
 * @ctx:  the XPath context
15023
 
 *
15024
 
 * Evaluate the XPath Location Path in the given context.
15025
 
 *
15026
 
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15027
 
 *         the caller has to free the object.
15028
 
 */
15029
 
xmlXPathObjectPtr
15030
 
xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
15031
 
    xmlXPathParserContextPtr ctxt;
15032
 
    xmlXPathObjectPtr res, tmp, init = NULL;
15033
 
    int stack = 0;
15034
 
 
15035
 
    CHECK_CTXT(ctx)
15036
 
 
15037
 
    xmlXPathInit();
15038
 
 
15039
 
    ctxt = xmlXPathNewParserContext(str, ctx);
15040
 
    if (ctxt == NULL)
15041
 
        return NULL;
15042
 
    xmlXPathEvalExpr(ctxt);
15043
 
 
15044
 
    if (ctxt->value == NULL) {
15045
 
        xmlGenericError(xmlGenericErrorContext,
15046
 
                "xmlXPathEval: evaluation failed\n");
15047
 
        res = NULL;
15048
 
    } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
15049
 
#ifdef XPATH_STREAMING
15050
 
            && (ctxt->comp->stream == NULL)
15051
 
#endif
15052
 
              ) {
15053
 
        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15054
 
        res = NULL;
15055
 
    } else {
15056
 
        res = valuePop(ctxt);
15057
 
    }
15058
 
 
15059
 
    do {
15060
 
        tmp = valuePop(ctxt);
15061
 
        if (tmp != NULL) {
15062
 
            if (tmp != init)
15063
 
                stack++;
15064
 
            xmlXPathReleaseObject(ctx, tmp);
15065
 
        }
15066
 
    } while (tmp != NULL);
15067
 
    if ((stack != 0) && (res != NULL)) {
15068
 
        xmlGenericError(xmlGenericErrorContext,
15069
 
                "xmlXPathEval: %d object left on the stack\n",
15070
 
                stack);
15071
 
    }
15072
 
    if (ctxt->error != XPATH_EXPRESSION_OK) {
15073
 
        xmlXPathFreeObject(res);
15074
 
        res = NULL;
15075
 
    }
15076
 
 
15077
 
    xmlXPathFreeParserContext(ctxt);
15078
 
    return(res);
15079
 
}
15080
 
 
15081
 
/**
15082
 
 * xmlXPathSetContextNode:
15083
 
 * @node: the node to to use as the context node
15084
 
 * @ctx:  the XPath context
15085
 
 *
15086
 
 * Sets 'node' as the context node. The node must be in the same
15087
 
 * document as that associated with the context.
15088
 
 *
15089
 
 * Returns -1 in case of error or 0 if successful
15090
 
 */
15091
 
int
15092
 
xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
15093
 
    if ((node == NULL) || (ctx == NULL))
15094
 
        return(-1);
15095
 
 
15096
 
    if (node->doc == ctx->doc) {
15097
 
        ctx->node = node;
15098
 
        return(0);
15099
 
    }
15100
 
    return(-1);
15101
 
}
15102
 
 
15103
 
/**
15104
 
 * xmlXPathNodeEval:
15105
 
 * @node: the node to to use as the context node
15106
 
 * @str:  the XPath expression
15107
 
 * @ctx:  the XPath context
15108
 
 *
15109
 
 * Evaluate the XPath Location Path in the given context. The node 'node'
15110
 
 * is set as the context node. The context node is not restored.
15111
 
 *
15112
 
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15113
 
 *         the caller has to free the object.
15114
 
 */
15115
 
xmlXPathObjectPtr
15116
 
xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
15117
 
    if (str == NULL)
15118
 
        return(NULL);
15119
 
    if (xmlXPathSetContextNode(node, ctx) < 0)
15120
 
        return(NULL);
15121
 
    return(xmlXPathEval(str, ctx));
15122
 
}
15123
 
 
15124
 
/**
15125
 
 * xmlXPathEvalExpression:
15126
 
 * @str:  the XPath expression
15127
 
 * @ctxt:  the XPath context
15128
 
 *
15129
 
 * Evaluate the XPath expression in the given context.
15130
 
 *
15131
 
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15132
 
 *         the caller has to free the object.
15133
 
 */
15134
 
xmlXPathObjectPtr
15135
 
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15136
 
    xmlXPathParserContextPtr pctxt;
15137
 
    xmlXPathObjectPtr res, tmp;
15138
 
    int stack = 0;
15139
 
 
15140
 
    CHECK_CTXT(ctxt)
15141
 
 
15142
 
    xmlXPathInit();
15143
 
 
15144
 
    pctxt = xmlXPathNewParserContext(str, ctxt);
15145
 
    if (pctxt == NULL)
15146
 
        return NULL;
15147
 
    xmlXPathEvalExpr(pctxt);
15148
 
 
15149
 
    if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
15150
 
        xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15151
 
        res = NULL;
15152
 
    } else {
15153
 
        res = valuePop(pctxt);
15154
 
    }
15155
 
    do {
15156
 
        tmp = valuePop(pctxt);
15157
 
        if (tmp != NULL) {
15158
 
            xmlXPathReleaseObject(ctxt, tmp);
15159
 
            stack++;
15160
 
        }
15161
 
    } while (tmp != NULL);
15162
 
    if ((stack != 0) && (res != NULL)) {
15163
 
        xmlGenericError(xmlGenericErrorContext,
15164
 
                "xmlXPathEvalExpression: %d object left on the stack\n",
15165
 
                stack);
15166
 
    }
15167
 
    xmlXPathFreeParserContext(pctxt);
15168
 
    return(res);
15169
 
}
15170
 
 
15171
 
/************************************************************************
15172
 
 *                                                                      *
15173
 
 *      Extra functions not pertaining to the XPath spec                *
15174
 
 *                                                                      *
15175
 
 ************************************************************************/
15176
 
/**
15177
 
 * xmlXPathEscapeUriFunction:
15178
 
 * @ctxt:  the XPath Parser context
15179
 
 * @nargs:  the number of arguments
15180
 
 *
15181
 
 * Implement the escape-uri() XPath function
15182
 
 *    string escape-uri(string $str, bool $escape-reserved)
15183
 
 *
15184
 
 * This function applies the URI escaping rules defined in section 2 of [RFC
15185
 
 * 2396] to the string supplied as $uri-part, which typically represents all
15186
 
 * or part of a URI. The effect of the function is to replace any special
15187
 
 * character in the string by an escape sequence of the form %xx%yy...,
15188
 
 * where xxyy... is the hexadecimal representation of the octets used to
15189
 
 * represent the character in UTF-8.
15190
 
 *
15191
 
 * The set of characters that are escaped depends on the setting of the
15192
 
 * boolean argument $escape-reserved.
15193
 
 *
15194
 
 * If $escape-reserved is true, all characters are escaped other than lower
15195
 
 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15196
 
 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15197
 
 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15198
 
 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15199
 
 * A-F).
15200
 
 *
15201
 
 * If $escape-reserved is false, the behavior differs in that characters
15202
 
 * referred to in [RFC 2396] as reserved characters are not escaped. These
15203
 
 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15204
 
 *
15205
 
 * [RFC 2396] does not define whether escaped URIs should use lower case or
15206
 
 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15207
 
 * compared using string comparison functions, this function must always use
15208
 
 * the upper-case letters A-F.
15209
 
 *
15210
 
 * Generally, $escape-reserved should be set to true when escaping a string
15211
 
 * that is to form a single part of a URI, and to false when escaping an
15212
 
 * entire URI or URI reference.
15213
 
 *
15214
 
 * In the case of non-ascii characters, the string is encoded according to
15215
 
 * utf-8 and then converted according to RFC 2396.
15216
 
 *
15217
 
 * Examples
15218
 
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15219
 
 *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15220
 
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15221
 
 *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15222
 
 *
15223
 
 */
15224
 
static void
15225
 
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15226
 
    xmlXPathObjectPtr str;
15227
 
    int escape_reserved;
15228
 
    xmlBufPtr target;
15229
 
    xmlChar *cptr;
15230
 
    xmlChar escape[4];
15231
 
 
15232
 
    CHECK_ARITY(2);
15233
 
 
15234
 
    escape_reserved = xmlXPathPopBoolean(ctxt);
15235
 
 
15236
 
    CAST_TO_STRING;
15237
 
    str = valuePop(ctxt);
15238
 
 
15239
 
    target = xmlBufCreate();
15240
 
 
15241
 
    escape[0] = '%';
15242
 
    escape[3] = 0;
15243
 
 
15244
 
    if (target) {
15245
 
        for (cptr = str->stringval; *cptr; cptr++) {
15246
 
            if ((*cptr >= 'A' && *cptr <= 'Z') ||
15247
 
                (*cptr >= 'a' && *cptr <= 'z') ||
15248
 
                (*cptr >= '0' && *cptr <= '9') ||
15249
 
                *cptr == '-' || *cptr == '_' || *cptr == '.' ||
15250
 
                *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15251
 
                *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15252
 
                (*cptr == '%' &&
15253
 
                 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15254
 
                  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15255
 
                  (cptr[1] >= '0' && cptr[1] <= '9')) &&
15256
 
                 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15257
 
                  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15258
 
                  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15259
 
                (!escape_reserved &&
15260
 
                 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15261
 
                  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15262
 
                  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15263
 
                  *cptr == ','))) {
15264
 
                xmlBufAdd(target, cptr, 1);
15265
 
            } else {
15266
 
                if ((*cptr >> 4) < 10)
15267
 
                    escape[1] = '0' + (*cptr >> 4);
15268
 
                else
15269
 
                    escape[1] = 'A' - 10 + (*cptr >> 4);
15270
 
                if ((*cptr & 0xF) < 10)
15271
 
                    escape[2] = '0' + (*cptr & 0xF);
15272
 
                else
15273
 
                    escape[2] = 'A' - 10 + (*cptr & 0xF);
15274
 
 
15275
 
                xmlBufAdd(target, &escape[0], 3);
15276
 
            }
15277
 
        }
15278
 
    }
15279
 
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15280
 
        xmlBufContent(target)));
15281
 
    xmlBufFree(target);
15282
 
    xmlXPathReleaseObject(ctxt->context, str);
15283
 
}
15284
 
 
15285
 
/**
15286
 
 * xmlXPathRegisterAllFunctions:
15287
 
 * @ctxt:  the XPath context
15288
 
 *
15289
 
 * Registers all default XPath functions in this context
15290
 
 */
15291
 
void
15292
 
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15293
 
{
15294
 
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15295
 
                         xmlXPathBooleanFunction);
15296
 
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15297
 
                         xmlXPathCeilingFunction);
15298
 
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15299
 
                         xmlXPathCountFunction);
15300
 
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15301
 
                         xmlXPathConcatFunction);
15302
 
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15303
 
                         xmlXPathContainsFunction);
15304
 
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15305
 
                         xmlXPathIdFunction);
15306
 
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15307
 
                         xmlXPathFalseFunction);
15308
 
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15309
 
                         xmlXPathFloorFunction);
15310
 
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15311
 
                         xmlXPathLastFunction);
15312
 
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15313
 
                         xmlXPathLangFunction);
15314
 
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15315
 
                         xmlXPathLocalNameFunction);
15316
 
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15317
 
                         xmlXPathNotFunction);
15318
 
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15319
 
                         xmlXPathNameFunction);
15320
 
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15321
 
                         xmlXPathNamespaceURIFunction);
15322
 
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15323
 
                         xmlXPathNormalizeFunction);
15324
 
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15325
 
                         xmlXPathNumberFunction);
15326
 
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15327
 
                         xmlXPathPositionFunction);
15328
 
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15329
 
                         xmlXPathRoundFunction);
15330
 
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15331
 
                         xmlXPathStringFunction);
15332
 
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15333
 
                         xmlXPathStringLengthFunction);
15334
 
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15335
 
                         xmlXPathStartsWithFunction);
15336
 
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15337
 
                         xmlXPathSubstringFunction);
15338
 
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15339
 
                         xmlXPathSubstringBeforeFunction);
15340
 
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15341
 
                         xmlXPathSubstringAfterFunction);
15342
 
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15343
 
                         xmlXPathSumFunction);
15344
 
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15345
 
                         xmlXPathTrueFunction);
15346
 
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15347
 
                         xmlXPathTranslateFunction);
15348
 
 
15349
 
    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15350
 
         (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15351
 
                         xmlXPathEscapeUriFunction);
15352
 
}
15353
 
 
15354
 
#endif /* LIBXML_XPATH_ENABLED */
15355
 
#define bottom_xpath
15356
 
#include "elfgcchack.h"