~inkscape.dev/inkscape-devlibs/trunk

« back to all changes in this revision

Viewing changes to python/Lib/site-packages/lxml/includes/libxslt/xsltutils.c

  • Committer: Eduard Braun
  • Date: 2016-10-22 16:54:41 UTC
  • Revision ID: eduard.braun2@gmx.de-20161022165441-gfp6agtut9nh4p22
Update Python to version 2.7.12

Included modules:
  coverage 4.2
  lxml 3.6.4
  numpy 1.11.2
  scour 0.35
  six 1.10.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * xsltutils.c: Utilities for the XSL Transformation 1.0 engine
3
 
 *
4
 
 * Reference:
5
 
 *   http://www.w3.org/TR/1999/REC-xslt-19991116
6
 
 *
7
 
 * See Copyright for the status of this software.
8
 
 *
9
 
 * daniel@veillard.com
10
 
 */
11
 
 
12
 
#define IN_LIBXSLT
13
 
#include "libxslt.h"
14
 
 
15
 
#ifndef XSLT_NEED_TRIO
16
 
#include <stdio.h>
17
 
#else
18
 
#include <trio.h>
19
 
#endif
20
 
 
21
 
#include <string.h>
22
 
#include <time.h>
23
 
#ifdef HAVE_SYS_TIME_H
24
 
#include <sys/time.h>
25
 
#endif
26
 
#ifdef HAVE_UNISTD_H
27
 
#include <unistd.h>
28
 
#endif
29
 
#ifdef HAVE_STDLIB_H
30
 
#include <stdlib.h>
31
 
#endif
32
 
#include <stdarg.h>
33
 
 
34
 
#include <libxml/xmlmemory.h>
35
 
#include <libxml/tree.h>
36
 
#include <libxml/HTMLtree.h>
37
 
#include <libxml/xmlerror.h>
38
 
#include <libxml/xmlIO.h>
39
 
#include "xsltutils.h"
40
 
#include "templates.h"
41
 
#include "xsltInternals.h"
42
 
#include "imports.h"
43
 
#include "transform.h"
44
 
 
45
 
/* gettimeofday on Windows ??? */
46
 
#if defined(WIN32) && !defined(__CYGWIN__)
47
 
#ifdef _MSC_VER
48
 
#include <winsock2.h>
49
 
#pragma comment(lib, "ws2_32.lib")
50
 
#define gettimeofday(p1,p2)
51
 
#define HAVE_GETTIMEOFDAY
52
 
#define XSLT_WIN32_PERFORMANCE_COUNTER
53
 
#endif /* _MS_VER */
54
 
#endif /* WIN32 */
55
 
 
56
 
/************************************************************************
57
 
 *                                                                      *
58
 
 *                      Convenience function                            *
59
 
 *                                                                      *
60
 
 ************************************************************************/
61
 
 
62
 
/**
63
 
 * xsltGetCNsProp:
64
 
 * @style: the stylesheet
65
 
 * @node:  the node
66
 
 * @name:  the attribute name
67
 
 * @nameSpace:  the URI of the namespace
68
 
 *
69
 
 * Similar to xmlGetNsProp() but with a slightly different semantic
70
 
 *
71
 
 * Search and get the value of an attribute associated to a node
72
 
 * This attribute has to be anchored in the namespace specified,
73
 
 * or has no namespace and the element is in that namespace.
74
 
 *
75
 
 * This does the entity substitution.
76
 
 * This function looks in DTD attribute declaration for #FIXED or
77
 
 * default declaration values unless DTD use has been turned off.
78
 
 *
79
 
 * Returns the attribute value or NULL if not found. The string is allocated
80
 
 *         in the stylesheet dictionary.
81
 
 */
82
 
const xmlChar *
83
 
xsltGetCNsProp(xsltStylesheetPtr style, xmlNodePtr node,
84
 
              const xmlChar *name, const xmlChar *nameSpace) {
85
 
    xmlAttrPtr prop;
86
 
    xmlDocPtr doc;
87
 
    xmlNsPtr ns;
88
 
    xmlChar *tmp;
89
 
    const xmlChar *ret;
90
 
 
91
 
    if ((node == NULL) || (style == NULL) || (style->dict == NULL))
92
 
        return(NULL);
93
 
 
94
 
    if (nameSpace == NULL)
95
 
        return xmlGetProp(node, name);
96
 
 
97
 
    if (node->type == XML_NAMESPACE_DECL)
98
 
        return(NULL);
99
 
    if (node->type == XML_ELEMENT_NODE)
100
 
        prop = node->properties;
101
 
    else
102
 
        prop = NULL;
103
 
    while (prop != NULL) {
104
 
        /*
105
 
         * One need to have
106
 
         *   - same attribute names
107
 
         *   - and the attribute carrying that namespace
108
 
         */
109
 
        if ((xmlStrEqual(prop->name, name)) &&
110
 
            (((prop->ns == NULL) && (node->ns != NULL) &&
111
 
              (xmlStrEqual(node->ns->href, nameSpace))) ||
112
 
             ((prop->ns != NULL) &&
113
 
              (xmlStrEqual(prop->ns->href, nameSpace))))) {
114
 
 
115
 
            tmp = xmlNodeListGetString(node->doc, prop->children, 1);
116
 
            if (tmp == NULL)
117
 
                ret = xmlDictLookup(style->dict, BAD_CAST "", 0);
118
 
            else {
119
 
                ret = xmlDictLookup(style->dict, tmp, -1);
120
 
                xmlFree(tmp);
121
 
            }
122
 
            return ret;
123
 
        }
124
 
        prop = prop->next;
125
 
    }
126
 
    tmp = NULL;
127
 
    /*
128
 
     * Check if there is a default declaration in the internal
129
 
     * or external subsets
130
 
     */
131
 
    doc =  node->doc;
132
 
    if (doc != NULL) {
133
 
        if (doc->intSubset != NULL) {
134
 
            xmlAttributePtr attrDecl;
135
 
 
136
 
            attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
137
 
            if ((attrDecl == NULL) && (doc->extSubset != NULL))
138
 
                attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
139
 
 
140
 
            if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
141
 
                /*
142
 
                 * The DTD declaration only allows a prefix search
143
 
                 */
144
 
                ns = xmlSearchNs(doc, node, attrDecl->prefix);
145
 
                if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
146
 
                    return(xmlDictLookup(style->dict,
147
 
                                         attrDecl->defaultValue, -1));
148
 
            }
149
 
        }
150
 
    }
151
 
    return(NULL);
152
 
}
153
 
/**
154
 
 * xsltGetNsProp:
155
 
 * @node:  the node
156
 
 * @name:  the attribute name
157
 
 * @nameSpace:  the URI of the namespace
158
 
 *
159
 
 * Similar to xmlGetNsProp() but with a slightly different semantic
160
 
 *
161
 
 * Search and get the value of an attribute associated to a node
162
 
 * This attribute has to be anchored in the namespace specified,
163
 
 * or has no namespace and the element is in that namespace.
164
 
 *
165
 
 * This does the entity substitution.
166
 
 * This function looks in DTD attribute declaration for #FIXED or
167
 
 * default declaration values unless DTD use has been turned off.
168
 
 *
169
 
 * Returns the attribute value or NULL if not found.
170
 
 *     It's up to the caller to free the memory.
171
 
 */
172
 
xmlChar *
173
 
xsltGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
174
 
    xmlAttrPtr prop;
175
 
    xmlDocPtr doc;
176
 
    xmlNsPtr ns;
177
 
 
178
 
    if (node == NULL)
179
 
        return(NULL);
180
 
 
181
 
    if (nameSpace == NULL)
182
 
        return xmlGetProp(node, name);
183
 
 
184
 
    if (node->type == XML_NAMESPACE_DECL)
185
 
        return(NULL);
186
 
    if (node->type == XML_ELEMENT_NODE)
187
 
        prop = node->properties;
188
 
    else
189
 
        prop = NULL;
190
 
    /*
191
 
    * TODO: Substitute xmlGetProp() for xmlGetNsProp(), since the former
192
 
    * is not namespace-aware and will return an attribute with equal
193
 
    * name regardless of its namespace.
194
 
    * Example:
195
 
    *   <xsl:element foo:name="myName"/>
196
 
    *   So this would return "myName" even if an attribute @name
197
 
    *   in the XSLT was requested.
198
 
    */
199
 
    while (prop != NULL) {
200
 
        /*
201
 
         * One need to have
202
 
         *   - same attribute names
203
 
         *   - and the attribute carrying that namespace
204
 
         */
205
 
        if ((xmlStrEqual(prop->name, name)) &&
206
 
            (((prop->ns == NULL) && (node->ns != NULL) &&
207
 
              (xmlStrEqual(node->ns->href, nameSpace))) ||
208
 
             ((prop->ns != NULL) &&
209
 
              (xmlStrEqual(prop->ns->href, nameSpace))))) {
210
 
            xmlChar *ret;
211
 
 
212
 
            ret = xmlNodeListGetString(node->doc, prop->children, 1);
213
 
            if (ret == NULL) return(xmlStrdup((xmlChar *)""));
214
 
            return(ret);
215
 
        }
216
 
        prop = prop->next;
217
 
    }
218
 
 
219
 
    /*
220
 
     * Check if there is a default declaration in the internal
221
 
     * or external subsets
222
 
     */
223
 
    doc =  node->doc;
224
 
    if (doc != NULL) {
225
 
        if (doc->intSubset != NULL) {
226
 
            xmlAttributePtr attrDecl;
227
 
 
228
 
            attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
229
 
            if ((attrDecl == NULL) && (doc->extSubset != NULL))
230
 
                attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
231
 
 
232
 
            if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
233
 
                /*
234
 
                 * The DTD declaration only allows a prefix search
235
 
                 */
236
 
                ns = xmlSearchNs(doc, node, attrDecl->prefix);
237
 
                if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
238
 
                    return(xmlStrdup(attrDecl->defaultValue));
239
 
            }
240
 
        }
241
 
    }
242
 
    return(NULL);
243
 
}
244
 
 
245
 
/**
246
 
 * xsltGetUTF8Char:
247
 
 * @utf:  a sequence of UTF-8 encoded bytes
248
 
 * @len:  a pointer to @bytes len
249
 
 *
250
 
 * Read one UTF8 Char from @utf
251
 
 * Function copied from libxml2 xmlGetUTF8Char() ... to discard ultimately
252
 
 * and use the original API
253
 
 *
254
 
 * Returns the char value or -1 in case of error and update @len with the
255
 
 *        number of bytes used
256
 
 */
257
 
int
258
 
xsltGetUTF8Char(const unsigned char *utf, int *len) {
259
 
    unsigned int c;
260
 
 
261
 
    if (utf == NULL)
262
 
        goto error;
263
 
    if (len == NULL)
264
 
        goto error;
265
 
    if (*len < 1)
266
 
        goto error;
267
 
 
268
 
    c = utf[0];
269
 
    if (c & 0x80) {
270
 
        if (*len < 2)
271
 
            goto error;
272
 
        if ((utf[1] & 0xc0) != 0x80)
273
 
            goto error;
274
 
        if ((c & 0xe0) == 0xe0) {
275
 
            if (*len < 3)
276
 
                goto error;
277
 
            if ((utf[2] & 0xc0) != 0x80)
278
 
                goto error;
279
 
            if ((c & 0xf0) == 0xf0) {
280
 
                if (*len < 4)
281
 
                    goto error;
282
 
                if ((c & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
283
 
                    goto error;
284
 
                *len = 4;
285
 
                /* 4-byte code */
286
 
                c = (utf[0] & 0x7) << 18;
287
 
                c |= (utf[1] & 0x3f) << 12;
288
 
                c |= (utf[2] & 0x3f) << 6;
289
 
                c |= utf[3] & 0x3f;
290
 
            } else {
291
 
              /* 3-byte code */
292
 
                *len = 3;
293
 
                c = (utf[0] & 0xf) << 12;
294
 
                c |= (utf[1] & 0x3f) << 6;
295
 
                c |= utf[2] & 0x3f;
296
 
            }
297
 
        } else {
298
 
          /* 2-byte code */
299
 
            *len = 2;
300
 
            c = (utf[0] & 0x1f) << 6;
301
 
            c |= utf[1] & 0x3f;
302
 
        }
303
 
    } else {
304
 
        /* 1-byte code */
305
 
        *len = 1;
306
 
    }
307
 
    return(c);
308
 
 
309
 
error:
310
 
    if (len != NULL)
311
 
        *len = 0;
312
 
    return(-1);
313
 
}
314
 
 
315
 
#ifdef XSLT_REFACTORED
316
 
 
317
 
/**
318
 
 * xsltPointerListAddSize:
319
 
 * @list: the pointer list structure
320
 
 * @item: the item to be stored
321
 
 * @initialSize: the initial size of the list
322
 
 *
323
 
 * Adds an item to the list.
324
 
 *
325
 
 * Returns the position of the added item in the list or
326
 
 *         -1 in case of an error.
327
 
 */
328
 
int
329
 
xsltPointerListAddSize(xsltPointerListPtr list,
330
 
                       void *item,
331
 
                       int initialSize)
332
 
{
333
 
    if (list->items == NULL) {
334
 
        if (initialSize <= 0)
335
 
            initialSize = 1;
336
 
        list->items = (void **) xmlMalloc(
337
 
            initialSize * sizeof(void *));
338
 
        if (list->items == NULL) {
339
 
            xsltGenericError(xsltGenericErrorContext,
340
 
             "xsltPointerListAddSize: memory allocation failure.\n");
341
 
            return(-1);
342
 
        }
343
 
        list->number = 0;
344
 
        list->size = initialSize;
345
 
    } else if (list->size <= list->number) {
346
 
        list->size *= 2;
347
 
        list->items = (void **) xmlRealloc(list->items,
348
 
            list->size * sizeof(void *));
349
 
        if (list->items == NULL) {
350
 
            xsltGenericError(xsltGenericErrorContext,
351
 
             "xsltPointerListAddSize: memory re-allocation failure.\n");
352
 
            list->size = 0;
353
 
            return(-1);
354
 
        }
355
 
    }
356
 
    list->items[list->number++] = item;
357
 
    return(0);
358
 
}
359
 
 
360
 
/**
361
 
 * xsltPointerListCreate:
362
 
 * @initialSize: the initial size for the list
363
 
 *
364
 
 * Creates an xsltPointerList structure.
365
 
 *
366
 
 * Returns a xsltPointerList structure or NULL in case of an error.
367
 
 */
368
 
xsltPointerListPtr
369
 
xsltPointerListCreate(int initialSize)
370
 
{
371
 
    xsltPointerListPtr ret;
372
 
 
373
 
    ret = xmlMalloc(sizeof(xsltPointerList));
374
 
    if (ret == NULL) {
375
 
        xsltGenericError(xsltGenericErrorContext,
376
 
             "xsltPointerListCreate: memory allocation failure.\n");
377
 
        return (NULL);
378
 
    }
379
 
    memset(ret, 0, sizeof(xsltPointerList));
380
 
    if (initialSize > 0) {
381
 
        xsltPointerListAddSize(ret, NULL, initialSize);
382
 
        ret->number = 0;
383
 
    }
384
 
    return (ret);
385
 
}
386
 
 
387
 
/**
388
 
 * xsltPointerListFree:
389
 
 * @list: pointer to the list to be freed
390
 
 *
391
 
 * Frees the xsltPointerList structure. This does not free
392
 
 * the content of the list.
393
 
 */
394
 
void
395
 
xsltPointerListFree(xsltPointerListPtr list)
396
 
{
397
 
    if (list == NULL)
398
 
        return;
399
 
    if (list->items != NULL)
400
 
        xmlFree(list->items);
401
 
    xmlFree(list);
402
 
}
403
 
 
404
 
/**
405
 
 * xsltPointerListClear:
406
 
 * @list: pointer to the list to be cleared
407
 
 *
408
 
 * Resets the list, but does not free the allocated array
409
 
 * and does not free the content of the list.
410
 
 */
411
 
void
412
 
xsltPointerListClear(xsltPointerListPtr list)
413
 
{
414
 
    if (list->items != NULL) {
415
 
        xmlFree(list->items);
416
 
        list->items = NULL;
417
 
    }
418
 
    list->number = 0;
419
 
    list->size = 0;
420
 
}
421
 
 
422
 
#endif /* XSLT_REFACTORED */
423
 
 
424
 
/************************************************************************
425
 
 *                                                                      *
426
 
 *              Handling of XSLT stylesheets messages                   *
427
 
 *                                                                      *
428
 
 ************************************************************************/
429
 
 
430
 
/**
431
 
 * xsltMessage:
432
 
 * @ctxt:  an XSLT processing context
433
 
 * @node:  The current node
434
 
 * @inst:  The node containing the message instruction
435
 
 *
436
 
 * Process and xsl:message construct
437
 
 */
438
 
void
439
 
xsltMessage(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst) {
440
 
    xmlGenericErrorFunc error = xsltGenericError;
441
 
    void *errctx = xsltGenericErrorContext;
442
 
    xmlChar *prop, *message;
443
 
    int terminate = 0;
444
 
 
445
 
    if ((ctxt == NULL) || (inst == NULL))
446
 
        return;
447
 
 
448
 
    if (ctxt->error != NULL) {
449
 
        error = ctxt->error;
450
 
        errctx = ctxt->errctx;
451
 
    }
452
 
 
453
 
    prop = xmlGetNsProp(inst, (const xmlChar *)"terminate", NULL);
454
 
    if (prop != NULL) {
455
 
        if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
456
 
            terminate = 1;
457
 
        } else if (xmlStrEqual(prop, (const xmlChar *)"no")) {
458
 
            terminate = 0;
459
 
        } else {
460
 
            error(errctx,
461
 
                "xsl:message : terminate expecting 'yes' or 'no'\n");
462
 
            ctxt->state = XSLT_STATE_ERROR;
463
 
        }
464
 
        xmlFree(prop);
465
 
    }
466
 
    message = xsltEvalTemplateString(ctxt, node, inst);
467
 
    if (message != NULL) {
468
 
        int len = xmlStrlen(message);
469
 
 
470
 
        error(errctx, "%s", (const char *)message);
471
 
        if ((len > 0) && (message[len - 1] != '\n'))
472
 
            error(errctx, "\n");
473
 
        xmlFree(message);
474
 
    }
475
 
    if (terminate)
476
 
        ctxt->state = XSLT_STATE_STOPPED;
477
 
}
478
 
 
479
 
/************************************************************************
480
 
 *                                                                      *
481
 
 *              Handling of out of context errors                       *
482
 
 *                                                                      *
483
 
 ************************************************************************/
484
 
 
485
 
#define XSLT_GET_VAR_STR(msg, str) {                            \
486
 
    int       size;                                             \
487
 
    int       chars;                                            \
488
 
    char      *larger;                                          \
489
 
    va_list   ap;                                               \
490
 
                                                                \
491
 
    str = (char *) xmlMalloc(150);                              \
492
 
    if (str == NULL)                                            \
493
 
        return;                                                 \
494
 
                                                                \
495
 
    size = 150;                                                 \
496
 
                                                                \
497
 
    while (size < 64000) {                                      \
498
 
        va_start(ap, msg);                                      \
499
 
        chars = vsnprintf(str, size, msg, ap);                  \
500
 
        va_end(ap);                                             \
501
 
        if ((chars > -1) && (chars < size))                     \
502
 
            break;                                              \
503
 
        if (chars > -1)                                         \
504
 
            size += chars + 1;                                  \
505
 
        else                                                    \
506
 
            size += 100;                                        \
507
 
        if ((larger = (char *) xmlRealloc(str, size)) == NULL) {\
508
 
            xmlFree(str);                                       \
509
 
            return;                                             \
510
 
        }                                                       \
511
 
        str = larger;                                           \
512
 
    }                                                           \
513
 
}
514
 
/**
515
 
 * xsltGenericErrorDefaultFunc:
516
 
 * @ctx:  an error context
517
 
 * @msg:  the message to display/transmit
518
 
 * @...:  extra parameters for the message display
519
 
 *
520
 
 * Default handler for out of context error messages.
521
 
 */
522
 
static void
523
 
xsltGenericErrorDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
524
 
    va_list args;
525
 
 
526
 
    if (xsltGenericErrorContext == NULL)
527
 
        xsltGenericErrorContext = (void *) stderr;
528
 
 
529
 
    va_start(args, msg);
530
 
    vfprintf((FILE *)xsltGenericErrorContext, msg, args);
531
 
    va_end(args);
532
 
}
533
 
 
534
 
xmlGenericErrorFunc xsltGenericError = xsltGenericErrorDefaultFunc;
535
 
void *xsltGenericErrorContext = NULL;
536
 
 
537
 
 
538
 
/**
539
 
 * xsltSetGenericErrorFunc:
540
 
 * @ctx:  the new error handling context
541
 
 * @handler:  the new handler function
542
 
 *
543
 
 * Function to reset the handler and the error context for out of
544
 
 * context error messages.
545
 
 * This simply means that @handler will be called for subsequent
546
 
 * error messages while not parsing nor validating. And @ctx will
547
 
 * be passed as first argument to @handler
548
 
 * One can simply force messages to be emitted to another FILE * than
549
 
 * stderr by setting @ctx to this file handle and @handler to NULL.
550
 
 */
551
 
void
552
 
xsltSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) {
553
 
    xsltGenericErrorContext = ctx;
554
 
    if (handler != NULL)
555
 
        xsltGenericError = handler;
556
 
    else
557
 
        xsltGenericError = xsltGenericErrorDefaultFunc;
558
 
}
559
 
 
560
 
/**
561
 
 * xsltGenericDebugDefaultFunc:
562
 
 * @ctx:  an error context
563
 
 * @msg:  the message to display/transmit
564
 
 * @...:  extra parameters for the message display
565
 
 *
566
 
 * Default handler for out of context error messages.
567
 
 */
568
 
static void
569
 
xsltGenericDebugDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
570
 
    va_list args;
571
 
 
572
 
    if (xsltGenericDebugContext == NULL)
573
 
        return;
574
 
 
575
 
    va_start(args, msg);
576
 
    vfprintf((FILE *)xsltGenericDebugContext, msg, args);
577
 
    va_end(args);
578
 
}
579
 
 
580
 
xmlGenericErrorFunc xsltGenericDebug = xsltGenericDebugDefaultFunc;
581
 
void *xsltGenericDebugContext = NULL;
582
 
 
583
 
 
584
 
/**
585
 
 * xsltSetGenericDebugFunc:
586
 
 * @ctx:  the new error handling context
587
 
 * @handler:  the new handler function
588
 
 *
589
 
 * Function to reset the handler and the error context for out of
590
 
 * context error messages.
591
 
 * This simply means that @handler will be called for subsequent
592
 
 * error messages while not parsing or validating. And @ctx will
593
 
 * be passed as first argument to @handler
594
 
 * One can simply force messages to be emitted to another FILE * than
595
 
 * stderr by setting @ctx to this file handle and @handler to NULL.
596
 
 */
597
 
void
598
 
xsltSetGenericDebugFunc(void *ctx, xmlGenericErrorFunc handler) {
599
 
    xsltGenericDebugContext = ctx;
600
 
    if (handler != NULL)
601
 
        xsltGenericDebug = handler;
602
 
    else
603
 
        xsltGenericDebug = xsltGenericDebugDefaultFunc;
604
 
}
605
 
 
606
 
/**
607
 
 * xsltPrintErrorContext:
608
 
 * @ctxt:  the transformation context
609
 
 * @style:  the stylesheet
610
 
 * @node:  the current node being processed
611
 
 *
612
 
 * Display the context of an error.
613
 
 */
614
 
void
615
 
xsltPrintErrorContext(xsltTransformContextPtr ctxt,
616
 
                      xsltStylesheetPtr style, xmlNodePtr node) {
617
 
    int line = 0;
618
 
    const xmlChar *file = NULL;
619
 
    const xmlChar *name = NULL;
620
 
    const char *type = "error";
621
 
    xmlGenericErrorFunc error = xsltGenericError;
622
 
    void *errctx = xsltGenericErrorContext;
623
 
 
624
 
    if (ctxt != NULL) {
625
 
        ctxt->state = XSLT_STATE_ERROR;
626
 
        if (ctxt->error != NULL) {
627
 
            error = ctxt->error;
628
 
            errctx = ctxt->errctx;
629
 
        }
630
 
    }
631
 
    if ((node == NULL) && (ctxt != NULL))
632
 
        node = ctxt->inst;
633
 
 
634
 
    if (node != NULL)  {
635
 
        if ((node->type == XML_DOCUMENT_NODE) ||
636
 
            (node->type == XML_HTML_DOCUMENT_NODE)) {
637
 
            xmlDocPtr doc = (xmlDocPtr) node;
638
 
 
639
 
            file = doc->URL;
640
 
        } else {
641
 
            line = xmlGetLineNo(node);
642
 
            if ((node->doc != NULL) && (node->doc->URL != NULL))
643
 
                file = node->doc->URL;
644
 
            if (node->name != NULL)
645
 
                name = node->name;
646
 
        }
647
 
    }
648
 
 
649
 
    if (ctxt != NULL)
650
 
        type = "runtime error";
651
 
    else if (style != NULL) {
652
 
#ifdef XSLT_REFACTORED
653
 
        if (XSLT_CCTXT(style)->errSeverity == XSLT_ERROR_SEVERITY_WARNING)
654
 
            type = "compilation warning";
655
 
        else
656
 
            type = "compilation error";
657
 
#else
658
 
        type = "compilation error";
659
 
#endif
660
 
    }
661
 
 
662
 
    if ((file != NULL) && (line != 0) && (name != NULL))
663
 
        error(errctx, "%s: file %s line %d element %s\n",
664
 
              type, file, line, name);
665
 
    else if ((file != NULL) && (name != NULL))
666
 
        error(errctx, "%s: file %s element %s\n", type, file, name);
667
 
    else if ((file != NULL) && (line != 0))
668
 
        error(errctx, "%s: file %s line %d\n", type, file, line);
669
 
    else if (file != NULL)
670
 
        error(errctx, "%s: file %s\n", type, file);
671
 
    else if (name != NULL)
672
 
        error(errctx, "%s: element %s\n", type, name);
673
 
    else
674
 
        error(errctx, "%s\n", type);
675
 
}
676
 
 
677
 
/**
678
 
 * xsltSetTransformErrorFunc:
679
 
 * @ctxt:  the XSLT transformation context
680
 
 * @ctx:  the new error handling context
681
 
 * @handler:  the new handler function
682
 
 *
683
 
 * Function to reset the handler and the error context for out of
684
 
 * context error messages specific to a given XSLT transromation.
685
 
 *
686
 
 * This simply means that @handler will be called for subsequent
687
 
 * error messages while running the transformation.
688
 
 */
689
 
void
690
 
xsltSetTransformErrorFunc(xsltTransformContextPtr ctxt,
691
 
                          void *ctx, xmlGenericErrorFunc handler)
692
 
{
693
 
    ctxt->error = handler;
694
 
    ctxt->errctx = ctx;
695
 
}
696
 
 
697
 
/**
698
 
 * xsltTransformError:
699
 
 * @ctxt:  an XSLT transformation context
700
 
 * @style:  the XSLT stylesheet used
701
 
 * @node:  the current node in the stylesheet
702
 
 * @msg:  the message to display/transmit
703
 
 * @...:  extra parameters for the message display
704
 
 *
705
 
 * Display and format an error messages, gives file, line, position and
706
 
 * extra parameters, will use the specific transformation context if available
707
 
 */
708
 
void
709
 
xsltTransformError(xsltTransformContextPtr ctxt,
710
 
                   xsltStylesheetPtr style,
711
 
                   xmlNodePtr node,
712
 
                   const char *msg, ...) {
713
 
    xmlGenericErrorFunc error = xsltGenericError;
714
 
    void *errctx = xsltGenericErrorContext;
715
 
    char * str;
716
 
 
717
 
    if (ctxt != NULL) {
718
 
        ctxt->state = XSLT_STATE_ERROR;
719
 
        if (ctxt->error != NULL) {
720
 
            error = ctxt->error;
721
 
            errctx = ctxt->errctx;
722
 
        }
723
 
    }
724
 
    if ((node == NULL) && (ctxt != NULL))
725
 
        node = ctxt->inst;
726
 
    xsltPrintErrorContext(ctxt, style, node);
727
 
    XSLT_GET_VAR_STR(msg, str);
728
 
    error(errctx, "%s", str);
729
 
    if (str != NULL)
730
 
        xmlFree(str);
731
 
}
732
 
 
733
 
/************************************************************************
734
 
 *                                                                      *
735
 
 *                              QNames                                  *
736
 
 *                                                                      *
737
 
 ************************************************************************/
738
 
 
739
 
/**
740
 
 * xsltSplitQName:
741
 
 * @dict: a dictionary
742
 
 * @name:  the full QName
743
 
 * @prefix: the return value
744
 
 *
745
 
 * Split QNames into prefix and local names, both allocated from a dictionary.
746
 
 *
747
 
 * Returns: the localname or NULL in case of error.
748
 
 */
749
 
const xmlChar *
750
 
xsltSplitQName(xmlDictPtr dict, const xmlChar *name, const xmlChar **prefix) {
751
 
    int len = 0;
752
 
    const xmlChar *ret = NULL;
753
 
 
754
 
    *prefix = NULL;
755
 
    if ((name == NULL) || (dict == NULL)) return(NULL);
756
 
    if (name[0] == ':')
757
 
        return(xmlDictLookup(dict, name, -1));
758
 
    while ((name[len] != 0) && (name[len] != ':')) len++;
759
 
    if (name[len] == 0) return(xmlDictLookup(dict, name, -1));
760
 
    *prefix = xmlDictLookup(dict, name, len);
761
 
    ret = xmlDictLookup(dict, &name[len + 1], -1);
762
 
    return(ret);
763
 
}
764
 
 
765
 
/**
766
 
 * xsltGetQNameURI:
767
 
 * @node:  the node holding the QName
768
 
 * @name:  pointer to the initial QName value
769
 
 *
770
 
 * This function analyzes @name, if the name contains a prefix,
771
 
 * the function seaches the associated namespace in scope for it.
772
 
 * It will also replace @name value with the NCName, the old value being
773
 
 * freed.
774
 
 * Errors in the prefix lookup are signalled by setting @name to NULL.
775
 
 *
776
 
 * NOTE: the namespace returned is a pointer to the place where it is
777
 
 *       defined and hence has the same lifespan as the document holding it.
778
 
 *
779
 
 * Returns the namespace URI if there is a prefix, or NULL if @name is
780
 
 *         not prefixed.
781
 
 */
782
 
const xmlChar *
783
 
xsltGetQNameURI(xmlNodePtr node, xmlChar ** name)
784
 
{
785
 
    int len = 0;
786
 
    xmlChar *qname;
787
 
    xmlNsPtr ns;
788
 
 
789
 
    if (name == NULL)
790
 
        return(NULL);
791
 
    qname = *name;
792
 
    if ((qname == NULL) || (*qname == 0))
793
 
        return(NULL);
794
 
    if (node == NULL) {
795
 
        xsltGenericError(xsltGenericErrorContext,
796
 
                         "QName: no element for namespace lookup %s\n",
797
 
                         qname);
798
 
        xmlFree(qname);
799
 
        *name = NULL;
800
 
        return(NULL);
801
 
    }
802
 
 
803
 
    /* nasty but valid */
804
 
    if (qname[0] == ':')
805
 
        return(NULL);
806
 
 
807
 
    /*
808
 
     * we are not trying to validate but just to cut, and yes it will
809
 
     * work even if this is a set of UTF-8 encoded chars
810
 
     */
811
 
    while ((qname[len] != 0) && (qname[len] != ':'))
812
 
        len++;
813
 
 
814
 
    if (qname[len] == 0)
815
 
        return(NULL);
816
 
 
817
 
    /*
818
 
     * handle xml: separately, this one is magical
819
 
     */
820
 
    if ((qname[0] == 'x') && (qname[1] == 'm') &&
821
 
        (qname[2] == 'l') && (qname[3] == ':')) {
822
 
        if (qname[4] == 0)
823
 
            return(NULL);
824
 
        *name = xmlStrdup(&qname[4]);
825
 
        xmlFree(qname);
826
 
        return(XML_XML_NAMESPACE);
827
 
    }
828
 
 
829
 
    qname[len] = 0;
830
 
    ns = xmlSearchNs(node->doc, node, qname);
831
 
    if (ns == NULL) {
832
 
        xsltGenericError(xsltGenericErrorContext,
833
 
                "%s:%s : no namespace bound to prefix %s\n",
834
 
                         qname, &qname[len + 1], qname);
835
 
        *name = NULL;
836
 
        xmlFree(qname);
837
 
        return(NULL);
838
 
    }
839
 
    *name = xmlStrdup(&qname[len + 1]);
840
 
    xmlFree(qname);
841
 
    return(ns->href);
842
 
}
843
 
 
844
 
/**
845
 
 * xsltGetQNameURI2:
846
 
 * @style:  stylesheet pointer
847
 
 * @node:   the node holding the QName
848
 
 * @name:   pointer to the initial QName value
849
 
 *
850
 
 * This function is similar to xsltGetQNameURI, but is used when
851
 
 * @name is a dictionary entry.
852
 
 *
853
 
 * Returns the namespace URI if there is a prefix, or NULL if @name is
854
 
 * not prefixed.
855
 
 */
856
 
const xmlChar *
857
 
xsltGetQNameURI2(xsltStylesheetPtr style, xmlNodePtr node,
858
 
                 const xmlChar **name) {
859
 
    int len = 0;
860
 
    xmlChar *qname;
861
 
    xmlNsPtr ns;
862
 
 
863
 
    if (name == NULL)
864
 
        return(NULL);
865
 
    qname = (xmlChar *)*name;
866
 
    if ((qname == NULL) || (*qname == 0))
867
 
        return(NULL);
868
 
    if (node == NULL) {
869
 
        xsltGenericError(xsltGenericErrorContext,
870
 
                         "QName: no element for namespace lookup %s\n",
871
 
                          qname);
872
 
        *name = NULL;
873
 
        return(NULL);
874
 
    }
875
 
 
876
 
    /*
877
 
     * we are not trying to validate but just to cut, and yes it will
878
 
     * work even if this is a set of UTF-8 encoded chars
879
 
     */
880
 
    while ((qname[len] != 0) && (qname[len] != ':'))
881
 
        len++;
882
 
 
883
 
    if (qname[len] == 0)
884
 
        return(NULL);
885
 
 
886
 
    /*
887
 
     * handle xml: separately, this one is magical
888
 
     */
889
 
    if ((qname[0] == 'x') && (qname[1] == 'm') &&
890
 
        (qname[2] == 'l') && (qname[3] == ':')) {
891
 
        if (qname[4] == 0)
892
 
            return(NULL);
893
 
        *name = xmlDictLookup(style->dict, &qname[4], -1);
894
 
        return(XML_XML_NAMESPACE);
895
 
    }
896
 
 
897
 
    qname = xmlStrndup(*name, len);
898
 
    ns = xmlSearchNs(node->doc, node, qname);
899
 
    if (ns == NULL) {
900
 
        if (style) {
901
 
            xsltTransformError(NULL, style, node,
902
 
                "No namespace bound to prefix '%s'.\n",
903
 
                qname);
904
 
            style->errors++;
905
 
        } else {
906
 
            xsltGenericError(xsltGenericErrorContext,
907
 
                "%s : no namespace bound to prefix %s\n",
908
 
                *name, qname);
909
 
        }
910
 
        *name = NULL;
911
 
        xmlFree(qname);
912
 
        return(NULL);
913
 
    }
914
 
    *name = xmlDictLookup(style->dict, (*name)+len+1, -1);
915
 
    xmlFree(qname);
916
 
    return(ns->href);
917
 
}
918
 
 
919
 
/************************************************************************
920
 
 *                                                                      *
921
 
 *                              Sorting                                 *
922
 
 *                                                                      *
923
 
 ************************************************************************/
924
 
 
925
 
/**
926
 
 * xsltDocumentSortFunction:
927
 
 * @list:  the node set
928
 
 *
929
 
 * reorder the current node list @list accordingly to the document order
930
 
 * This function is slow, obsolete and should not be used anymore.
931
 
 */
932
 
void
933
 
xsltDocumentSortFunction(xmlNodeSetPtr list) {
934
 
    int i, j;
935
 
    int len, tst;
936
 
    xmlNodePtr node;
937
 
 
938
 
    if (list == NULL)
939
 
        return;
940
 
    len = list->nodeNr;
941
 
    if (len <= 1)
942
 
        return;
943
 
    /* TODO: sort is really not optimized, does it needs to ? */
944
 
    for (i = 0;i < len -1;i++) {
945
 
        for (j = i + 1; j < len; j++) {
946
 
            tst = xmlXPathCmpNodes(list->nodeTab[i], list->nodeTab[j]);
947
 
            if (tst == -1) {
948
 
                node = list->nodeTab[i];
949
 
                list->nodeTab[i] = list->nodeTab[j];
950
 
                list->nodeTab[j] = node;
951
 
            }
952
 
        }
953
 
    }
954
 
}
955
 
 
956
 
/**
957
 
 * xsltComputeSortResult:
958
 
 * @ctxt:  a XSLT process context
959
 
 * @sort:  node list
960
 
 *
961
 
 * reorder the current node list accordingly to the set of sorting
962
 
 * requirement provided by the array of nodes.
963
 
 *
964
 
 * Returns a ordered XPath nodeset or NULL in case of error.
965
 
 */
966
 
xmlXPathObjectPtr *
967
 
xsltComputeSortResult(xsltTransformContextPtr ctxt, xmlNodePtr sort) {
968
 
#ifdef XSLT_REFACTORED
969
 
    xsltStyleItemSortPtr comp;
970
 
#else
971
 
    xsltStylePreCompPtr comp;
972
 
#endif
973
 
    xmlXPathObjectPtr *results = NULL;
974
 
    xmlNodeSetPtr list = NULL;
975
 
    xmlXPathObjectPtr res;
976
 
    int len = 0;
977
 
    int i;
978
 
    xmlNodePtr oldNode;
979
 
    xmlNodePtr oldInst;
980
 
    int oldPos, oldSize ;
981
 
    int oldNsNr;
982
 
    xmlNsPtr *oldNamespaces;
983
 
 
984
 
    comp = sort->psvi;
985
 
    if (comp == NULL) {
986
 
        xsltGenericError(xsltGenericErrorContext,
987
 
             "xsl:sort : compilation failed\n");
988
 
        return(NULL);
989
 
    }
990
 
 
991
 
    if ((comp->select == NULL) || (comp->comp == NULL))
992
 
        return(NULL);
993
 
 
994
 
    list = ctxt->nodeList;
995
 
    if ((list == NULL) || (list->nodeNr <= 1))
996
 
        return(NULL);
997
 
 
998
 
    len = list->nodeNr;
999
 
 
1000
 
    /* TODO: xsl:sort lang attribute */
1001
 
    /* TODO: xsl:sort case-order attribute */
1002
 
 
1003
 
 
1004
 
    results = xmlMalloc(len * sizeof(xmlXPathObjectPtr));
1005
 
    if (results == NULL) {
1006
 
        xsltGenericError(xsltGenericErrorContext,
1007
 
             "xsltComputeSortResult: memory allocation failure\n");
1008
 
        return(NULL);
1009
 
    }
1010
 
 
1011
 
    oldNode = ctxt->node;
1012
 
    oldInst = ctxt->inst;
1013
 
    oldPos = ctxt->xpathCtxt->proximityPosition;
1014
 
    oldSize = ctxt->xpathCtxt->contextSize;
1015
 
    oldNsNr = ctxt->xpathCtxt->nsNr;
1016
 
    oldNamespaces = ctxt->xpathCtxt->namespaces;
1017
 
    for (i = 0;i < len;i++) {
1018
 
        ctxt->inst = sort;
1019
 
        ctxt->xpathCtxt->contextSize = len;
1020
 
        ctxt->xpathCtxt->proximityPosition = i + 1;
1021
 
        ctxt->node = list->nodeTab[i];
1022
 
        ctxt->xpathCtxt->node = ctxt->node;
1023
 
#ifdef XSLT_REFACTORED
1024
 
        if (comp->inScopeNs != NULL) {
1025
 
            ctxt->xpathCtxt->namespaces = comp->inScopeNs->list;
1026
 
            ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber;
1027
 
        } else {
1028
 
            ctxt->xpathCtxt->namespaces = NULL;
1029
 
            ctxt->xpathCtxt->nsNr = 0;
1030
 
        }
1031
 
#else
1032
 
        ctxt->xpathCtxt->namespaces = comp->nsList;
1033
 
        ctxt->xpathCtxt->nsNr = comp->nsNr;
1034
 
#endif
1035
 
        res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);
1036
 
        if (res != NULL) {
1037
 
            if (res->type != XPATH_STRING)
1038
 
                res = xmlXPathConvertString(res);
1039
 
            if (comp->number)
1040
 
                res = xmlXPathConvertNumber(res);
1041
 
            res->index = i;     /* Save original pos for dupl resolv */
1042
 
            if (comp->number) {
1043
 
                if (res->type == XPATH_NUMBER) {
1044
 
                    results[i] = res;
1045
 
                } else {
1046
 
#ifdef WITH_XSLT_DEBUG_PROCESS
1047
 
                    xsltGenericDebug(xsltGenericDebugContext,
1048
 
                        "xsltComputeSortResult: select didn't evaluate to a number\n");
1049
 
#endif
1050
 
                    results[i] = NULL;
1051
 
                }
1052
 
            } else {
1053
 
                if (res->type == XPATH_STRING) {
1054
 
                    if (comp->locale != (xsltLocale)0) {
1055
 
                        xmlChar *str = res->stringval;
1056
 
                        res->stringval = (xmlChar *) xsltStrxfrm(comp->locale, str);
1057
 
                        xmlFree(str);
1058
 
                    }
1059
 
 
1060
 
                    results[i] = res;
1061
 
                } else {
1062
 
#ifdef WITH_XSLT_DEBUG_PROCESS
1063
 
                    xsltGenericDebug(xsltGenericDebugContext,
1064
 
                        "xsltComputeSortResult: select didn't evaluate to a string\n");
1065
 
#endif
1066
 
                    results[i] = NULL;
1067
 
                }
1068
 
            }
1069
 
        } else {
1070
 
            ctxt->state = XSLT_STATE_STOPPED;
1071
 
            results[i] = NULL;
1072
 
        }
1073
 
    }
1074
 
    ctxt->node = oldNode;
1075
 
    ctxt->inst = oldInst;
1076
 
    ctxt->xpathCtxt->contextSize = oldSize;
1077
 
    ctxt->xpathCtxt->proximityPosition = oldPos;
1078
 
    ctxt->xpathCtxt->nsNr = oldNsNr;
1079
 
    ctxt->xpathCtxt->namespaces = oldNamespaces;
1080
 
 
1081
 
    return(results);
1082
 
}
1083
 
 
1084
 
/**
1085
 
 * xsltDefaultSortFunction:
1086
 
 * @ctxt:  a XSLT process context
1087
 
 * @sorts:  array of sort nodes
1088
 
 * @nbsorts:  the number of sorts in the array
1089
 
 *
1090
 
 * reorder the current node list accordingly to the set of sorting
1091
 
 * requirement provided by the arry of nodes.
1092
 
 */
1093
 
void
1094
 
xsltDefaultSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts,
1095
 
                   int nbsorts) {
1096
 
#ifdef XSLT_REFACTORED
1097
 
    xsltStyleItemSortPtr comp;
1098
 
#else
1099
 
    xsltStylePreCompPtr comp;
1100
 
#endif
1101
 
    xmlXPathObjectPtr *resultsTab[XSLT_MAX_SORT];
1102
 
    xmlXPathObjectPtr *results = NULL, *res;
1103
 
    xmlNodeSetPtr list = NULL;
1104
 
    int descending, number, desc, numb;
1105
 
    int len = 0;
1106
 
    int i, j, incr;
1107
 
    int tst;
1108
 
    int depth;
1109
 
    xmlNodePtr node;
1110
 
    xmlXPathObjectPtr tmp;
1111
 
    int tempstype[XSLT_MAX_SORT], temporder[XSLT_MAX_SORT];
1112
 
 
1113
 
    if ((ctxt == NULL) || (sorts == NULL) || (nbsorts <= 0) ||
1114
 
        (nbsorts >= XSLT_MAX_SORT))
1115
 
        return;
1116
 
    if (sorts[0] == NULL)
1117
 
        return;
1118
 
    comp = sorts[0]->psvi;
1119
 
    if (comp == NULL)
1120
 
        return;
1121
 
 
1122
 
    list = ctxt->nodeList;
1123
 
    if ((list == NULL) || (list->nodeNr <= 1))
1124
 
        return; /* nothing to do */
1125
 
 
1126
 
    for (j = 0; j < nbsorts; j++) {
1127
 
        comp = sorts[j]->psvi;
1128
 
        tempstype[j] = 0;
1129
 
        if ((comp->stype == NULL) && (comp->has_stype != 0)) {
1130
 
            comp->stype =
1131
 
                xsltEvalAttrValueTemplate(ctxt, sorts[j],
1132
 
                                          (const xmlChar *) "data-type",
1133
 
                                          XSLT_NAMESPACE);
1134
 
            if (comp->stype != NULL) {
1135
 
                tempstype[j] = 1;
1136
 
                if (xmlStrEqual(comp->stype, (const xmlChar *) "text"))
1137
 
                    comp->number = 0;
1138
 
                else if (xmlStrEqual(comp->stype, (const xmlChar *) "number"))
1139
 
                    comp->number = 1;
1140
 
                else {
1141
 
                    xsltTransformError(ctxt, NULL, sorts[j],
1142
 
                          "xsltDoSortFunction: no support for data-type = %s\n",
1143
 
                                     comp->stype);
1144
 
                    comp->number = 0; /* use default */
1145
 
                }
1146
 
            }
1147
 
        }
1148
 
        temporder[j] = 0;
1149
 
        if ((comp->order == NULL) && (comp->has_order != 0)) {
1150
 
            comp->order = xsltEvalAttrValueTemplate(ctxt, sorts[j],
1151
 
                                                    (const xmlChar *) "order",
1152
 
                                                    XSLT_NAMESPACE);
1153
 
            if (comp->order != NULL) {
1154
 
                temporder[j] = 1;
1155
 
                if (xmlStrEqual(comp->order, (const xmlChar *) "ascending"))
1156
 
                    comp->descending = 0;
1157
 
                else if (xmlStrEqual(comp->order,
1158
 
                                     (const xmlChar *) "descending"))
1159
 
                    comp->descending = 1;
1160
 
                else {
1161
 
                    xsltTransformError(ctxt, NULL, sorts[j],
1162
 
                             "xsltDoSortFunction: invalid value %s for order\n",
1163
 
                                     comp->order);
1164
 
                    comp->descending = 0; /* use default */
1165
 
                }
1166
 
            }
1167
 
        }
1168
 
    }
1169
 
 
1170
 
    len = list->nodeNr;
1171
 
 
1172
 
    resultsTab[0] = xsltComputeSortResult(ctxt, sorts[0]);
1173
 
    for (i = 1;i < XSLT_MAX_SORT;i++)
1174
 
        resultsTab[i] = NULL;
1175
 
 
1176
 
    results = resultsTab[0];
1177
 
 
1178
 
    comp = sorts[0]->psvi;
1179
 
    descending = comp->descending;
1180
 
    number = comp->number;
1181
 
    if (results == NULL)
1182
 
        return;
1183
 
 
1184
 
    /* Shell's sort of node-set */
1185
 
    for (incr = len / 2; incr > 0; incr /= 2) {
1186
 
        for (i = incr; i < len; i++) {
1187
 
            j = i - incr;
1188
 
            if (results[i] == NULL)
1189
 
                continue;
1190
 
 
1191
 
            while (j >= 0) {
1192
 
                if (results[j] == NULL)
1193
 
                    tst = 1;
1194
 
                else {
1195
 
                    if (number) {
1196
 
                        /* We make NaN smaller than number in accordance
1197
 
                           with XSLT spec */
1198
 
                        if (xmlXPathIsNaN(results[j]->floatval)) {
1199
 
                            if (xmlXPathIsNaN(results[j + incr]->floatval))
1200
 
                                tst = 0;
1201
 
                            else
1202
 
                                tst = -1;
1203
 
                        } else if (xmlXPathIsNaN(results[j + incr]->floatval))
1204
 
                            tst = 1;
1205
 
                        else if (results[j]->floatval ==
1206
 
                                results[j + incr]->floatval)
1207
 
                            tst = 0;
1208
 
                        else if (results[j]->floatval >
1209
 
                                results[j + incr]->floatval)
1210
 
                            tst = 1;
1211
 
                        else tst = -1;
1212
 
                    } else if(comp->locale != (xsltLocale)0) {
1213
 
                        tst = xsltLocaleStrcmp(
1214
 
                            comp->locale,
1215
 
                            (xsltLocaleChar *) results[j]->stringval,
1216
 
                            (xsltLocaleChar *) results[j + incr]->stringval);
1217
 
                    } else {
1218
 
                        tst = xmlStrcmp(results[j]->stringval,
1219
 
                                     results[j + incr]->stringval);
1220
 
                    }
1221
 
                    if (descending)
1222
 
                        tst = -tst;
1223
 
                }
1224
 
                if (tst == 0) {
1225
 
                    /*
1226
 
                     * Okay we need to use multi level sorts
1227
 
                     */
1228
 
                    depth = 1;
1229
 
                    while (depth < nbsorts) {
1230
 
                        if (sorts[depth] == NULL)
1231
 
                            break;
1232
 
                        comp = sorts[depth]->psvi;
1233
 
                        if (comp == NULL)
1234
 
                            break;
1235
 
                        desc = comp->descending;
1236
 
                        numb = comp->number;
1237
 
 
1238
 
                        /*
1239
 
                         * Compute the result of the next level for the
1240
 
                         * full set, this might be optimized ... or not
1241
 
                         */
1242
 
                        if (resultsTab[depth] == NULL)
1243
 
                            resultsTab[depth] = xsltComputeSortResult(ctxt,
1244
 
                                                        sorts[depth]);
1245
 
                        res = resultsTab[depth];
1246
 
                        if (res == NULL)
1247
 
                            break;
1248
 
                        if (res[j] == NULL) {
1249
 
                            if (res[j+incr] != NULL)
1250
 
                                tst = 1;
1251
 
                        } else {
1252
 
                            if (numb) {
1253
 
                                /* We make NaN smaller than number in
1254
 
                                   accordance with XSLT spec */
1255
 
                                if (xmlXPathIsNaN(res[j]->floatval)) {
1256
 
                                    if (xmlXPathIsNaN(res[j +
1257
 
                                                incr]->floatval))
1258
 
                                        tst = 0;
1259
 
                                    else
1260
 
                                        tst = -1;
1261
 
                                } else if (xmlXPathIsNaN(res[j + incr]->
1262
 
                                                floatval))
1263
 
                                    tst = 1;
1264
 
                                else if (res[j]->floatval == res[j + incr]->
1265
 
                                                floatval)
1266
 
                                    tst = 0;
1267
 
                                else if (res[j]->floatval >
1268
 
                                        res[j + incr]->floatval)
1269
 
                                    tst = 1;
1270
 
                                else tst = -1;
1271
 
                            } else if(comp->locale != (xsltLocale)0) {
1272
 
                                tst = xsltLocaleStrcmp(
1273
 
                                    comp->locale,
1274
 
                                    (xsltLocaleChar *) res[j]->stringval,
1275
 
                                    (xsltLocaleChar *) res[j + incr]->stringval);
1276
 
                            } else {
1277
 
                                tst = xmlStrcmp(res[j]->stringval,
1278
 
                                             res[j + incr]->stringval);
1279
 
                            }
1280
 
                            if (desc)
1281
 
                                tst = -tst;
1282
 
                        }
1283
 
 
1284
 
                        /*
1285
 
                         * if we still can't differenciate at this level
1286
 
                         * try one level deeper.
1287
 
                         */
1288
 
                        if (tst != 0)
1289
 
                            break;
1290
 
                        depth++;
1291
 
                    }
1292
 
                }
1293
 
                if (tst == 0) {
1294
 
                    tst = results[j]->index > results[j + incr]->index;
1295
 
                }
1296
 
                if (tst > 0) {
1297
 
                    tmp = results[j];
1298
 
                    results[j] = results[j + incr];
1299
 
                    results[j + incr] = tmp;
1300
 
                    node = list->nodeTab[j];
1301
 
                    list->nodeTab[j] = list->nodeTab[j + incr];
1302
 
                    list->nodeTab[j + incr] = node;
1303
 
                    depth = 1;
1304
 
                    while (depth < nbsorts) {
1305
 
                        if (sorts[depth] == NULL)
1306
 
                            break;
1307
 
                        if (resultsTab[depth] == NULL)
1308
 
                            break;
1309
 
                        res = resultsTab[depth];
1310
 
                        tmp = res[j];
1311
 
                        res[j] = res[j + incr];
1312
 
                        res[j + incr] = tmp;
1313
 
                        depth++;
1314
 
                    }
1315
 
                    j -= incr;
1316
 
                } else
1317
 
                    break;
1318
 
            }
1319
 
        }
1320
 
    }
1321
 
 
1322
 
    for (j = 0; j < nbsorts; j++) {
1323
 
        comp = sorts[j]->psvi;
1324
 
        if (tempstype[j] == 1) {
1325
 
            /* The data-type needs to be recomputed each time */
1326
 
            xmlFree((void *)(comp->stype));
1327
 
            comp->stype = NULL;
1328
 
        }
1329
 
        if (temporder[j] == 1) {
1330
 
            /* The order needs to be recomputed each time */
1331
 
            xmlFree((void *)(comp->order));
1332
 
            comp->order = NULL;
1333
 
        }
1334
 
        if (resultsTab[j] != NULL) {
1335
 
            for (i = 0;i < len;i++)
1336
 
                xmlXPathFreeObject(resultsTab[j][i]);
1337
 
            xmlFree(resultsTab[j]);
1338
 
        }
1339
 
    }
1340
 
}
1341
 
 
1342
 
 
1343
 
static xsltSortFunc xsltSortFunction = xsltDefaultSortFunction;
1344
 
 
1345
 
/**
1346
 
 * xsltDoSortFunction:
1347
 
 * @ctxt:  a XSLT process context
1348
 
 * @sorts:  array of sort nodes
1349
 
 * @nbsorts:  the number of sorts in the array
1350
 
 *
1351
 
 * reorder the current node list accordingly to the set of sorting
1352
 
 * requirement provided by the arry of nodes.
1353
 
 * This is a wrapper function, the actual function used is specified
1354
 
 * using xsltSetCtxtSortFunc() to set the context specific sort function,
1355
 
 * or xsltSetSortFunc() to set the global sort function.
1356
 
 * If a sort function is set on the context, this will get called.
1357
 
 * Otherwise the global sort function is called.
1358
 
 */
1359
 
void
1360
 
xsltDoSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr * sorts,
1361
 
                   int nbsorts)
1362
 
{
1363
 
    if (ctxt->sortfunc != NULL)
1364
 
        (ctxt->sortfunc)(ctxt, sorts, nbsorts);
1365
 
    else if (xsltSortFunction != NULL)
1366
 
        xsltSortFunction(ctxt, sorts, nbsorts);
1367
 
}
1368
 
 
1369
 
/**
1370
 
 * xsltSetSortFunc:
1371
 
 * @handler:  the new handler function
1372
 
 *
1373
 
 * Function to reset the global handler for XSLT sorting.
1374
 
 * If the handler is NULL, the default sort function will be used.
1375
 
 */
1376
 
void
1377
 
xsltSetSortFunc(xsltSortFunc handler) {
1378
 
    if (handler != NULL)
1379
 
        xsltSortFunction = handler;
1380
 
    else
1381
 
        xsltSortFunction = xsltDefaultSortFunction;
1382
 
}
1383
 
 
1384
 
/**
1385
 
 * xsltSetCtxtSortFunc:
1386
 
 * @ctxt:  a XSLT process context
1387
 
 * @handler:  the new handler function
1388
 
 *
1389
 
 * Function to set the handler for XSLT sorting
1390
 
 * for the specified context.
1391
 
 * If the handler is NULL, then the global
1392
 
 * sort function will be called
1393
 
 */
1394
 
void
1395
 
xsltSetCtxtSortFunc(xsltTransformContextPtr ctxt, xsltSortFunc handler) {
1396
 
    ctxt->sortfunc = handler;
1397
 
}
1398
 
 
1399
 
/************************************************************************
1400
 
 *                                                                      *
1401
 
 *                              Parsing options                         *
1402
 
 *                                                                      *
1403
 
 ************************************************************************/
1404
 
 
1405
 
/**
1406
 
 * xsltSetCtxtParseOptions:
1407
 
 * @ctxt:  a XSLT process context
1408
 
 * @options:  a combination of libxml2 xmlParserOption
1409
 
 *
1410
 
 * Change the default parser option passed by the XSLT engine to the
1411
 
 * parser when using document() loading.
1412
 
 *
1413
 
 * Returns the previous options or -1 in case of error
1414
 
 */
1415
 
int
1416
 
xsltSetCtxtParseOptions(xsltTransformContextPtr ctxt, int options)
1417
 
{
1418
 
    int oldopts;
1419
 
 
1420
 
    if (ctxt == NULL)
1421
 
        return(-1);
1422
 
    oldopts = ctxt->parserOptions;
1423
 
    if (ctxt->xinclude)
1424
 
        oldopts |= XML_PARSE_XINCLUDE;
1425
 
    ctxt->parserOptions = options;
1426
 
    if (options & XML_PARSE_XINCLUDE)
1427
 
        ctxt->xinclude = 1;
1428
 
    else
1429
 
        ctxt->xinclude = 0;
1430
 
    return(oldopts);
1431
 
}
1432
 
 
1433
 
/************************************************************************
1434
 
 *                                                                      *
1435
 
 *                              Output                                  *
1436
 
 *                                                                      *
1437
 
 ************************************************************************/
1438
 
 
1439
 
/**
1440
 
 * xsltSaveResultTo:
1441
 
 * @buf:  an output buffer
1442
 
 * @result:  the result xmlDocPtr
1443
 
 * @style:  the stylesheet
1444
 
 *
1445
 
 * Save the result @result obtained by applying the @style stylesheet
1446
 
 * to an I/O output channel @buf
1447
 
 *
1448
 
 * Returns the number of byte written or -1 in case of failure.
1449
 
 */
1450
 
int
1451
 
xsltSaveResultTo(xmlOutputBufferPtr buf, xmlDocPtr result,
1452
 
               xsltStylesheetPtr style) {
1453
 
    const xmlChar *encoding;
1454
 
    int base;
1455
 
    const xmlChar *method;
1456
 
    int indent;
1457
 
 
1458
 
    if ((buf == NULL) || (result == NULL) || (style == NULL))
1459
 
        return(-1);
1460
 
    if ((result->children == NULL) ||
1461
 
        ((result->children->type == XML_DTD_NODE) &&
1462
 
         (result->children->next == NULL)))
1463
 
        return(0);
1464
 
 
1465
 
    if ((style->methodURI != NULL) &&
1466
 
        ((style->method == NULL) ||
1467
 
         (!xmlStrEqual(style->method, (const xmlChar *) "xhtml")))) {
1468
 
        xsltGenericError(xsltGenericErrorContext,
1469
 
                "xsltSaveResultTo : unknown ouput method\n");
1470
 
        return(-1);
1471
 
    }
1472
 
 
1473
 
    base = buf->written;
1474
 
 
1475
 
    XSLT_GET_IMPORT_PTR(method, style, method)
1476
 
    XSLT_GET_IMPORT_PTR(encoding, style, encoding)
1477
 
    XSLT_GET_IMPORT_INT(indent, style, indent);
1478
 
 
1479
 
    if ((method == NULL) && (result->type == XML_HTML_DOCUMENT_NODE))
1480
 
        method = (const xmlChar *) "html";
1481
 
 
1482
 
    if ((method != NULL) &&
1483
 
        (xmlStrEqual(method, (const xmlChar *) "html"))) {
1484
 
        if (encoding != NULL) {
1485
 
            htmlSetMetaEncoding(result, (const xmlChar *) encoding);
1486
 
        } else {
1487
 
            htmlSetMetaEncoding(result, (const xmlChar *) "UTF-8");
1488
 
        }
1489
 
        if (indent == -1)
1490
 
            indent = 1;
1491
 
        htmlDocContentDumpFormatOutput(buf, result, (const char *) encoding,
1492
 
                                       indent);
1493
 
        xmlOutputBufferFlush(buf);
1494
 
    } else if ((method != NULL) &&
1495
 
        (xmlStrEqual(method, (const xmlChar *) "xhtml"))) {
1496
 
        if (encoding != NULL) {
1497
 
            htmlSetMetaEncoding(result, (const xmlChar *) encoding);
1498
 
        } else {
1499
 
            htmlSetMetaEncoding(result, (const xmlChar *) "UTF-8");
1500
 
        }
1501
 
        htmlDocContentDumpOutput(buf, result, (const char *) encoding);
1502
 
        xmlOutputBufferFlush(buf);
1503
 
    } else if ((method != NULL) &&
1504
 
               (xmlStrEqual(method, (const xmlChar *) "text"))) {
1505
 
        xmlNodePtr cur;
1506
 
 
1507
 
        cur = result->children;
1508
 
        while (cur != NULL) {
1509
 
            if (cur->type == XML_TEXT_NODE)
1510
 
                xmlOutputBufferWriteString(buf, (const char *) cur->content);
1511
 
 
1512
 
            /*
1513
 
             * Skip to next node
1514
 
             */
1515
 
            if (cur->children != NULL) {
1516
 
                if ((cur->children->type != XML_ENTITY_DECL) &&
1517
 
                    (cur->children->type != XML_ENTITY_REF_NODE) &&
1518
 
                    (cur->children->type != XML_ENTITY_NODE)) {
1519
 
                    cur = cur->children;
1520
 
                    continue;
1521
 
                }
1522
 
            }
1523
 
            if (cur->next != NULL) {
1524
 
                cur = cur->next;
1525
 
                continue;
1526
 
            }
1527
 
 
1528
 
            do {
1529
 
                cur = cur->parent;
1530
 
                if (cur == NULL)
1531
 
                    break;
1532
 
                if (cur == (xmlNodePtr) style->doc) {
1533
 
                    cur = NULL;
1534
 
                    break;
1535
 
                }
1536
 
                if (cur->next != NULL) {
1537
 
                    cur = cur->next;
1538
 
                    break;
1539
 
                }
1540
 
            } while (cur != NULL);
1541
 
        }
1542
 
        xmlOutputBufferFlush(buf);
1543
 
    } else {
1544
 
        int omitXmlDecl;
1545
 
        int standalone;
1546
 
 
1547
 
        XSLT_GET_IMPORT_INT(omitXmlDecl, style, omitXmlDeclaration);
1548
 
        XSLT_GET_IMPORT_INT(standalone, style, standalone);
1549
 
 
1550
 
        if (omitXmlDecl != 1) {
1551
 
            xmlOutputBufferWriteString(buf, "<?xml version=");
1552
 
            if (result->version != NULL) {
1553
 
                xmlOutputBufferWriteString(buf, "\"");
1554
 
                xmlOutputBufferWriteString(buf, (const char *)result->version);
1555
 
                xmlOutputBufferWriteString(buf, "\"");
1556
 
            } else
1557
 
                xmlOutputBufferWriteString(buf, "\"1.0\"");
1558
 
            if (encoding == NULL) {
1559
 
                if (result->encoding != NULL)
1560
 
                    encoding = result->encoding;
1561
 
                else if (result->charset != XML_CHAR_ENCODING_UTF8)
1562
 
                    encoding = (const xmlChar *)
1563
 
                               xmlGetCharEncodingName((xmlCharEncoding)
1564
 
                                                      result->charset);
1565
 
            }
1566
 
            if (encoding != NULL) {
1567
 
                xmlOutputBufferWriteString(buf, " encoding=");
1568
 
                xmlOutputBufferWriteString(buf, "\"");
1569
 
                xmlOutputBufferWriteString(buf, (const char *) encoding);
1570
 
                xmlOutputBufferWriteString(buf, "\"");
1571
 
            }
1572
 
            switch (standalone) {
1573
 
                case 0:
1574
 
                    xmlOutputBufferWriteString(buf, " standalone=\"no\"");
1575
 
                    break;
1576
 
                case 1:
1577
 
                    xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
1578
 
                    break;
1579
 
                default:
1580
 
                    break;
1581
 
            }
1582
 
            xmlOutputBufferWriteString(buf, "?>\n");
1583
 
        }
1584
 
        if (result->children != NULL) {
1585
 
            xmlNodePtr child = result->children;
1586
 
 
1587
 
            while (child != NULL) {
1588
 
                xmlNodeDumpOutput(buf, result, child, 0, (indent == 1),
1589
 
                                  (const char *) encoding);
1590
 
                if (indent && ((child->type == XML_DTD_NODE) ||
1591
 
                    ((child->type == XML_COMMENT_NODE) &&
1592
 
                     (child->next != NULL))))
1593
 
                    xmlOutputBufferWriteString(buf, "\n");
1594
 
                child = child->next;
1595
 
            }
1596
 
            if (indent)
1597
 
                        xmlOutputBufferWriteString(buf, "\n");
1598
 
        }
1599
 
        xmlOutputBufferFlush(buf);
1600
 
    }
1601
 
    return(buf->written - base);
1602
 
}
1603
 
 
1604
 
/**
1605
 
 * xsltSaveResultToFilename:
1606
 
 * @URL:  a filename or URL
1607
 
 * @result:  the result xmlDocPtr
1608
 
 * @style:  the stylesheet
1609
 
 * @compression:  the compression factor (0 - 9 included)
1610
 
 *
1611
 
 * Save the result @result obtained by applying the @style stylesheet
1612
 
 * to a file or @URL
1613
 
 *
1614
 
 * Returns the number of byte written or -1 in case of failure.
1615
 
 */
1616
 
int
1617
 
xsltSaveResultToFilename(const char *URL, xmlDocPtr result,
1618
 
                         xsltStylesheetPtr style, int compression) {
1619
 
    xmlOutputBufferPtr buf;
1620
 
    const xmlChar *encoding;
1621
 
    int ret;
1622
 
 
1623
 
    if ((URL == NULL) || (result == NULL) || (style == NULL))
1624
 
        return(-1);
1625
 
    if (result->children == NULL)
1626
 
        return(0);
1627
 
 
1628
 
    XSLT_GET_IMPORT_PTR(encoding, style, encoding)
1629
 
    if (encoding != NULL) {
1630
 
        xmlCharEncodingHandlerPtr encoder;
1631
 
 
1632
 
        encoder = xmlFindCharEncodingHandler((char *)encoding);
1633
 
        if ((encoder != NULL) &&
1634
 
            (xmlStrEqual((const xmlChar *)encoder->name,
1635
 
                         (const xmlChar *) "UTF-8")))
1636
 
            encoder = NULL;
1637
 
        buf = xmlOutputBufferCreateFilename(URL, encoder, compression);
1638
 
    } else {
1639
 
        buf = xmlOutputBufferCreateFilename(URL, NULL, compression);
1640
 
    }
1641
 
    if (buf == NULL)
1642
 
        return(-1);
1643
 
    xsltSaveResultTo(buf, result, style);
1644
 
    ret = xmlOutputBufferClose(buf);
1645
 
    return(ret);
1646
 
}
1647
 
 
1648
 
/**
1649
 
 * xsltSaveResultToFile:
1650
 
 * @file:  a FILE * I/O
1651
 
 * @result:  the result xmlDocPtr
1652
 
 * @style:  the stylesheet
1653
 
 *
1654
 
 * Save the result @result obtained by applying the @style stylesheet
1655
 
 * to an open FILE * I/O.
1656
 
 * This does not close the FILE @file
1657
 
 *
1658
 
 * Returns the number of bytes written or -1 in case of failure.
1659
 
 */
1660
 
int
1661
 
xsltSaveResultToFile(FILE *file, xmlDocPtr result, xsltStylesheetPtr style) {
1662
 
    xmlOutputBufferPtr buf;
1663
 
    const xmlChar *encoding;
1664
 
    int ret;
1665
 
 
1666
 
    if ((file == NULL) || (result == NULL) || (style == NULL))
1667
 
        return(-1);
1668
 
    if (result->children == NULL)
1669
 
        return(0);
1670
 
 
1671
 
    XSLT_GET_IMPORT_PTR(encoding, style, encoding)
1672
 
    if (encoding != NULL) {
1673
 
        xmlCharEncodingHandlerPtr encoder;
1674
 
 
1675
 
        encoder = xmlFindCharEncodingHandler((char *)encoding);
1676
 
        if ((encoder != NULL) &&
1677
 
            (xmlStrEqual((const xmlChar *)encoder->name,
1678
 
                         (const xmlChar *) "UTF-8")))
1679
 
            encoder = NULL;
1680
 
        buf = xmlOutputBufferCreateFile(file, encoder);
1681
 
    } else {
1682
 
        buf = xmlOutputBufferCreateFile(file, NULL);
1683
 
    }
1684
 
 
1685
 
    if (buf == NULL)
1686
 
        return(-1);
1687
 
    xsltSaveResultTo(buf, result, style);
1688
 
    ret = xmlOutputBufferClose(buf);
1689
 
    return(ret);
1690
 
}
1691
 
 
1692
 
/**
1693
 
 * xsltSaveResultToFd:
1694
 
 * @fd:  a file descriptor
1695
 
 * @result:  the result xmlDocPtr
1696
 
 * @style:  the stylesheet
1697
 
 *
1698
 
 * Save the result @result obtained by applying the @style stylesheet
1699
 
 * to an open file descriptor
1700
 
 * This does not close the descriptor.
1701
 
 *
1702
 
 * Returns the number of bytes written or -1 in case of failure.
1703
 
 */
1704
 
int
1705
 
xsltSaveResultToFd(int fd, xmlDocPtr result, xsltStylesheetPtr style) {
1706
 
    xmlOutputBufferPtr buf;
1707
 
    const xmlChar *encoding;
1708
 
    int ret;
1709
 
 
1710
 
    if ((fd < 0) || (result == NULL) || (style == NULL))
1711
 
        return(-1);
1712
 
    if (result->children == NULL)
1713
 
        return(0);
1714
 
 
1715
 
    XSLT_GET_IMPORT_PTR(encoding, style, encoding)
1716
 
    if (encoding != NULL) {
1717
 
        xmlCharEncodingHandlerPtr encoder;
1718
 
 
1719
 
        encoder = xmlFindCharEncodingHandler((char *)encoding);
1720
 
        if ((encoder != NULL) &&
1721
 
            (xmlStrEqual((const xmlChar *)encoder->name,
1722
 
                         (const xmlChar *) "UTF-8")))
1723
 
            encoder = NULL;
1724
 
        buf = xmlOutputBufferCreateFd(fd, encoder);
1725
 
    } else {
1726
 
        buf = xmlOutputBufferCreateFd(fd, NULL);
1727
 
    }
1728
 
    if (buf == NULL)
1729
 
        return(-1);
1730
 
    xsltSaveResultTo(buf, result, style);
1731
 
    ret = xmlOutputBufferClose(buf);
1732
 
    return(ret);
1733
 
}
1734
 
 
1735
 
/**
1736
 
 * xsltSaveResultToString:
1737
 
 * @doc_txt_ptr:  Memory pointer for allocated XML text
1738
 
 * @doc_txt_len:  Length of the generated XML text
1739
 
 * @result:  the result xmlDocPtr
1740
 
 * @style:  the stylesheet
1741
 
 *
1742
 
 * Save the result @result obtained by applying the @style stylesheet
1743
 
 * to a new allocated string.
1744
 
 *
1745
 
 * Returns 0 in case of success and -1 in case of error
1746
 
 */
1747
 
int
1748
 
xsltSaveResultToString(xmlChar **doc_txt_ptr, int * doc_txt_len,
1749
 
                       xmlDocPtr result, xsltStylesheetPtr style) {
1750
 
    xmlOutputBufferPtr buf;
1751
 
    const xmlChar *encoding;
1752
 
 
1753
 
    *doc_txt_ptr = NULL;
1754
 
    *doc_txt_len = 0;
1755
 
    if (result->children == NULL)
1756
 
        return(0);
1757
 
 
1758
 
    XSLT_GET_IMPORT_PTR(encoding, style, encoding)
1759
 
    if (encoding != NULL) {
1760
 
        xmlCharEncodingHandlerPtr encoder;
1761
 
 
1762
 
        encoder = xmlFindCharEncodingHandler((char *)encoding);
1763
 
        if ((encoder != NULL) &&
1764
 
            (xmlStrEqual((const xmlChar *)encoder->name,
1765
 
                         (const xmlChar *) "UTF-8")))
1766
 
            encoder = NULL;
1767
 
        buf = xmlAllocOutputBuffer(encoder);
1768
 
    } else {
1769
 
        buf = xmlAllocOutputBuffer(NULL);
1770
 
    }
1771
 
    if (buf == NULL)
1772
 
        return(-1);
1773
 
    xsltSaveResultTo(buf, result, style);
1774
 
#ifdef LIBXML2_NEW_BUFFER
1775
 
    if (buf->conv != NULL) {
1776
 
        *doc_txt_len = xmlBufUse(buf->conv);
1777
 
        *doc_txt_ptr = xmlStrndup(xmlBufContent(buf->conv), *doc_txt_len);
1778
 
    } else {
1779
 
        *doc_txt_len = xmlBufUse(buf->buffer);
1780
 
        *doc_txt_ptr = xmlStrndup(xmlBufContent(buf->buffer), *doc_txt_len);
1781
 
    }
1782
 
#else
1783
 
    if (buf->conv != NULL) {
1784
 
        *doc_txt_len = buf->conv->use;
1785
 
        *doc_txt_ptr = xmlStrndup(buf->conv->content, *doc_txt_len);
1786
 
    } else {
1787
 
        *doc_txt_len = buf->buffer->use;
1788
 
        *doc_txt_ptr = xmlStrndup(buf->buffer->content, *doc_txt_len);
1789
 
    }
1790
 
#endif
1791
 
    (void)xmlOutputBufferClose(buf);
1792
 
    return 0;
1793
 
}
1794
 
 
1795
 
/************************************************************************
1796
 
 *                                                                      *
1797
 
 *              Generating profiling informations                       *
1798
 
 *                                                                      *
1799
 
 ************************************************************************/
1800
 
 
1801
 
static long calibration = -1;
1802
 
 
1803
 
/**
1804
 
 * xsltCalibrateTimestamps:
1805
 
 *
1806
 
 * Used for to calibrate the xsltTimestamp() function
1807
 
 * Should work if launched at startup and we don't loose our quantum :-)
1808
 
 *
1809
 
 * Returns the number of milliseconds used by xsltTimestamp()
1810
 
 */
1811
 
static long
1812
 
xsltCalibrateTimestamps(void) {
1813
 
    register int i;
1814
 
 
1815
 
    for (i = 0;i < 999;i++)
1816
 
        xsltTimestamp();
1817
 
    return(xsltTimestamp() / 1000);
1818
 
}
1819
 
 
1820
 
/**
1821
 
 * xsltCalibrateAdjust:
1822
 
 * @delta:  a negative dealy value found
1823
 
 *
1824
 
 * Used for to correct the calibration for xsltTimestamp()
1825
 
 */
1826
 
void
1827
 
xsltCalibrateAdjust(long delta) {
1828
 
    calibration += delta;
1829
 
}
1830
 
 
1831
 
/**
1832
 
 * xsltTimestamp:
1833
 
 *
1834
 
 * Used for gathering profiling data
1835
 
 *
1836
 
 * Returns the number of tenth of milliseconds since the beginning of the
1837
 
 * profiling
1838
 
 */
1839
 
long
1840
 
xsltTimestamp(void)
1841
 
{
1842
 
#ifdef XSLT_WIN32_PERFORMANCE_COUNTER
1843
 
    BOOL ok;
1844
 
    LARGE_INTEGER performanceCount;
1845
 
    LARGE_INTEGER performanceFrequency;
1846
 
    LONGLONG quadCount;
1847
 
    double seconds;
1848
 
    static LONGLONG startupQuadCount = 0;
1849
 
    static LONGLONG startupQuadFreq = 0;
1850
 
 
1851
 
    ok = QueryPerformanceCounter(&performanceCount);
1852
 
    if (!ok)
1853
 
        return 0;
1854
 
    quadCount = performanceCount.QuadPart;
1855
 
    if (calibration < 0) {
1856
 
        calibration = 0;
1857
 
        ok = QueryPerformanceFrequency(&performanceFrequency);
1858
 
        if (!ok)
1859
 
            return 0;
1860
 
        startupQuadFreq = performanceFrequency.QuadPart;
1861
 
        startupQuadCount = quadCount;
1862
 
        return (0);
1863
 
    }
1864
 
    if (startupQuadFreq == 0)
1865
 
        return 0;
1866
 
    seconds = (quadCount - startupQuadCount) / (double) startupQuadFreq;
1867
 
    return (long) (seconds * XSLT_TIMESTAMP_TICS_PER_SEC);
1868
 
 
1869
 
#else /* XSLT_WIN32_PERFORMANCE_COUNTER */
1870
 
#ifdef HAVE_CLOCK_GETTIME
1871
 
#  if defined(CLOCK_MONOTONIC)
1872
 
#    define XSLT_CLOCK CLOCK_MONOTONIC
1873
 
#  elif defined(CLOCK_HIGHRES)
1874
 
#    define XSLT_CLOCK CLOCK_HIGHRES
1875
 
#  else
1876
 
#    define XSLT_CLOCK CLOCK_REALTIME
1877
 
#  endif
1878
 
    static struct timespec startup;
1879
 
    struct timespec cur;
1880
 
    long tics;
1881
 
 
1882
 
    if (calibration < 0) {
1883
 
        clock_gettime(XSLT_CLOCK, &startup);
1884
 
        calibration = 0;
1885
 
        calibration = xsltCalibrateTimestamps();
1886
 
        clock_gettime(XSLT_CLOCK, &startup);
1887
 
        return (0);
1888
 
    }
1889
 
 
1890
 
    clock_gettime(XSLT_CLOCK, &cur);
1891
 
    tics = (cur.tv_sec - startup.tv_sec) * XSLT_TIMESTAMP_TICS_PER_SEC;
1892
 
    tics += (cur.tv_nsec - startup.tv_nsec) /
1893
 
                          (1000000000l / XSLT_TIMESTAMP_TICS_PER_SEC);
1894
 
 
1895
 
    tics -= calibration;
1896
 
    return(tics);
1897
 
 
1898
 
#elif HAVE_GETTIMEOFDAY
1899
 
    static struct timeval startup;
1900
 
    struct timeval cur;
1901
 
    long tics;
1902
 
 
1903
 
    if (calibration < 0) {
1904
 
        gettimeofday(&startup, NULL);
1905
 
        calibration = 0;
1906
 
        calibration = xsltCalibrateTimestamps();
1907
 
        gettimeofday(&startup, NULL);
1908
 
        return (0);
1909
 
    }
1910
 
 
1911
 
    gettimeofday(&cur, NULL);
1912
 
    tics = (cur.tv_sec - startup.tv_sec) * XSLT_TIMESTAMP_TICS_PER_SEC;
1913
 
    tics += (cur.tv_usec - startup.tv_usec) /
1914
 
                          (1000000l / XSLT_TIMESTAMP_TICS_PER_SEC);
1915
 
 
1916
 
    tics -= calibration;
1917
 
    return(tics);
1918
 
#else
1919
 
 
1920
 
    /* Neither gettimeofday() nor Win32 performance counter available */
1921
 
 
1922
 
    return (0);
1923
 
 
1924
 
#endif /* HAVE_GETTIMEOFDAY */
1925
 
#endif /* XSLT_WIN32_PERFORMANCE_COUNTER */
1926
 
}
1927
 
 
1928
 
static char *
1929
 
pretty_templ_match(xsltTemplatePtr templ) {
1930
 
  static char dst[1001];
1931
 
  char *src = (char *)templ->match;
1932
 
  int i=0,j;
1933
 
 
1934
 
  /* strip white spaces */
1935
 
  for (j=0; i<1000 && src[j]; i++,j++) {
1936
 
      for(;src[j]==' ';j++);
1937
 
      dst[i]=src[j];
1938
 
  }
1939
 
  if(i<998 && templ->mode) {
1940
 
    /* append [mode] */
1941
 
    dst[i++]='[';
1942
 
    src=(char *)templ->mode;
1943
 
    for (j=0; i<999 && src[j]; i++,j++) {
1944
 
      dst[i]=src[j];
1945
 
    }
1946
 
    dst[i++]=']';
1947
 
  }
1948
 
  dst[i]='\0';
1949
 
  return dst;
1950
 
}
1951
 
 
1952
 
#define MAX_TEMPLATES 10000
1953
 
 
1954
 
/**
1955
 
 * xsltSaveProfiling:
1956
 
 * @ctxt:  an XSLT context
1957
 
 * @output:  a FILE * for saving the informations
1958
 
 *
1959
 
 * Save the profiling informations on @output
1960
 
 */
1961
 
void
1962
 
xsltSaveProfiling(xsltTransformContextPtr ctxt, FILE *output) {
1963
 
    int nb, i,j,k,l;
1964
 
    int max;
1965
 
    int total;
1966
 
    long totalt;
1967
 
    xsltTemplatePtr *templates;
1968
 
    xsltStylesheetPtr style;
1969
 
    xsltTemplatePtr templ1,templ2;
1970
 
    int *childt;
1971
 
 
1972
 
    if ((output == NULL) || (ctxt == NULL))
1973
 
        return;
1974
 
    if (ctxt->profile == 0)
1975
 
        return;
1976
 
 
1977
 
    nb = 0;
1978
 
    max = MAX_TEMPLATES;
1979
 
    templates = xmlMalloc(max * sizeof(xsltTemplatePtr));
1980
 
    if (templates == NULL)
1981
 
        return;
1982
 
 
1983
 
    style = ctxt->style;
1984
 
    while (style != NULL) {
1985
 
        templ1 = style->templates;
1986
 
        while (templ1 != NULL) {
1987
 
            if (nb >= max)
1988
 
                break;
1989
 
 
1990
 
            if (templ1->nbCalls > 0)
1991
 
                templates[nb++] = templ1;
1992
 
            templ1 = templ1->next;
1993
 
        }
1994
 
 
1995
 
        style = xsltNextImport(style);
1996
 
    }
1997
 
 
1998
 
    for (i = 0;i < nb -1;i++) {
1999
 
        for (j = i + 1; j < nb; j++) {
2000
 
            if ((templates[i]->time <= templates[j]->time) ||
2001
 
                ((templates[i]->time == templates[j]->time) &&
2002
 
                 (templates[i]->nbCalls <= templates[j]->nbCalls))) {
2003
 
                templ1 = templates[j];
2004
 
                templates[j] = templates[i];
2005
 
                templates[i] = templ1;
2006
 
            }
2007
 
        }
2008
 
    }
2009
 
 
2010
 
 
2011
 
    /* print flat profile */
2012
 
 
2013
 
    fprintf(output, "%6s%20s%20s%10s  Calls Tot 100us Avg\n\n",
2014
 
            "number", "match", "name", "mode");
2015
 
    total = 0;
2016
 
    totalt = 0;
2017
 
    for (i = 0;i < nb;i++) {
2018
 
         templ1 = templates[i];
2019
 
        fprintf(output, "%5d ", i);
2020
 
        if (templ1->match != NULL) {
2021
 
            if (xmlStrlen(templ1->match) > 20)
2022
 
                fprintf(output, "%s\n%26s", templ1->match, "");
2023
 
            else
2024
 
                fprintf(output, "%20s", templ1->match);
2025
 
        } else {
2026
 
            fprintf(output, "%20s", "");
2027
 
        }
2028
 
        if (templ1->name != NULL) {
2029
 
            if (xmlStrlen(templ1->name) > 20)
2030
 
                fprintf(output, "%s\n%46s", templ1->name, "");
2031
 
            else
2032
 
                fprintf(output, "%20s", templ1->name);
2033
 
        } else {
2034
 
            fprintf(output, "%20s", "");
2035
 
        }
2036
 
        if (templ1->mode != NULL) {
2037
 
            if (xmlStrlen(templ1->mode) > 10)
2038
 
                fprintf(output, "%s\n%56s", templ1->mode, "");
2039
 
            else
2040
 
                fprintf(output, "%10s", templ1->mode);
2041
 
        } else {
2042
 
            fprintf(output, "%10s", "");
2043
 
        }
2044
 
        fprintf(output, " %6d", templ1->nbCalls);
2045
 
        fprintf(output, " %6ld %6ld\n", templ1->time,
2046
 
                templ1->time / templ1->nbCalls);
2047
 
        total += templ1->nbCalls;
2048
 
        totalt += templ1->time;
2049
 
    }
2050
 
    fprintf(output, "\n%30s%26s %6d %6ld\n", "Total", "", total, totalt);
2051
 
 
2052
 
 
2053
 
    /* print call graph */
2054
 
 
2055
 
    childt = xmlMalloc((nb + 1) * sizeof(int));
2056
 
    if (childt == NULL)
2057
 
        return;
2058
 
 
2059
 
    /* precalculate children times */
2060
 
    for (i = 0; i < nb; i++) {
2061
 
        templ1 = templates[i];
2062
 
 
2063
 
        childt[i] = 0;
2064
 
        for (k = 0; k < nb; k++) {
2065
 
            templ2 = templates[k];
2066
 
            for (l = 0; l < templ2->templNr; l++) {
2067
 
                if (templ2->templCalledTab[l] == templ1) {
2068
 
                    childt[i] +=templ2->time;
2069
 
                }
2070
 
            }
2071
 
        }
2072
 
    }
2073
 
    childt[i] = 0;
2074
 
 
2075
 
    fprintf(output, "\nindex %% time    self  children    called     name\n");
2076
 
 
2077
 
    for (i = 0; i < nb; i++) {
2078
 
        char ix_str[20], timep_str[20], times_str[20], timec_str[20], called_str[20];
2079
 
        int t;
2080
 
 
2081
 
        templ1 = templates[i];
2082
 
        /* callers */
2083
 
        for (j = 0; j < templ1->templNr; j++) {
2084
 
            templ2 = templ1->templCalledTab[j];
2085
 
            for (k = 0; k < nb; k++) {
2086
 
              if (templates[k] == templ2)
2087
 
                break;
2088
 
            }
2089
 
            t=templ2?templ2->time:totalt;
2090
 
            sprintf(times_str,"%8.3f",(float)t/XSLT_TIMESTAMP_TICS_PER_SEC);
2091
 
            sprintf(timec_str,"%8.3f",(float)childt[k]/XSLT_TIMESTAMP_TICS_PER_SEC);
2092
 
            sprintf(called_str,"%6d/%d",
2093
 
                templ1->templCountTab[j], /* number of times caller calls 'this' */
2094
 
                templ1->nbCalls);         /* total number of calls to 'this' */
2095
 
 
2096
 
            fprintf(output, "             %-8s %-8s %-12s     %s [%d]\n",
2097
 
                times_str,timec_str,called_str,
2098
 
                (templ2?(templ2->name?(char *)templ2->name:pretty_templ_match(templ2)):"-"),k);
2099
 
        }
2100
 
        /* this */
2101
 
        sprintf(ix_str,"[%d]",i);
2102
 
        sprintf(timep_str,"%6.2f",(float)templ1->time*100.0/totalt);
2103
 
        sprintf(times_str,"%8.3f",(float)templ1->time/XSLT_TIMESTAMP_TICS_PER_SEC);
2104
 
        sprintf(timec_str,"%8.3f",(float)childt[i]/XSLT_TIMESTAMP_TICS_PER_SEC);
2105
 
        fprintf(output, "%-5s %-6s %-8s %-8s %6d     %s [%d]\n",
2106
 
            ix_str, timep_str,times_str,timec_str,
2107
 
            templ1->nbCalls,
2108
 
            templ1->name?(char *)templ1->name:pretty_templ_match(templ1),i);
2109
 
        /* callees
2110
 
         * - go over templates[0..nb] and their templCalledTab[]
2111
 
         * - print those where we in the the call-stack
2112
 
         */
2113
 
        total = 0;
2114
 
        for (k = 0; k < nb; k++) {
2115
 
            templ2 = templates[k];
2116
 
            for (l = 0; l < templ2->templNr; l++) {
2117
 
                if (templ2->templCalledTab[l] == templ1) {
2118
 
                    total+=templ2->templCountTab[l];
2119
 
                }
2120
 
            }
2121
 
        }
2122
 
        for (k = 0; k < nb; k++) {
2123
 
            templ2 = templates[k];
2124
 
            for (l = 0; l < templ2->templNr; l++) {
2125
 
                if (templ2->templCalledTab[l] == templ1) {
2126
 
                    sprintf(times_str,"%8.3f",(float)templ2->time/XSLT_TIMESTAMP_TICS_PER_SEC);
2127
 
                    sprintf(timec_str,"%8.3f",(float)childt[k]/XSLT_TIMESTAMP_TICS_PER_SEC);
2128
 
                    sprintf(called_str,"%6d/%d",
2129
 
                        templ2->templCountTab[l], /* number of times 'this' calls callee */
2130
 
                        total);                   /* total number of calls from 'this' */
2131
 
                    fprintf(output, "             %-8s %-8s %-12s     %s [%d]\n",
2132
 
                        times_str,timec_str,called_str,
2133
 
                        templ2->name?(char *)templ2->name:pretty_templ_match(templ2),k);
2134
 
                }
2135
 
            }
2136
 
        }
2137
 
        fprintf(output, "-----------------------------------------------\n");
2138
 
    }
2139
 
 
2140
 
    fprintf(output, "\f\nIndex by function name\n");
2141
 
    for (i = 0; i < nb; i++) {
2142
 
        templ1 = templates[i];
2143
 
        fprintf(output, "[%d] %s (%s:%d)\n",
2144
 
            i, templ1->name?(char *)templ1->name:pretty_templ_match(templ1),
2145
 
            templ1->style->doc->URL,templ1->elem->line);
2146
 
    }
2147
 
 
2148
 
    fprintf(output, "\f\n");
2149
 
    xmlFree(childt);
2150
 
 
2151
 
    xmlFree(templates);
2152
 
}
2153
 
 
2154
 
/************************************************************************
2155
 
 *                                                                      *
2156
 
 *              Fetching profiling informations                         *
2157
 
 *                                                                      *
2158
 
 ************************************************************************/
2159
 
 
2160
 
/**
2161
 
 * xsltGetProfileInformation:
2162
 
 * @ctxt:  a transformation context
2163
 
 *
2164
 
 * This function should be called after the transformation completed
2165
 
 * to extract template processing profiling informations if availble.
2166
 
 * The informations are returned as an XML document tree like
2167
 
 * <?xml version="1.0"?>
2168
 
 * <profile>
2169
 
 * <template rank="1" match="*" name=""
2170
 
 *         mode="" calls="6" time="48" average="8"/>
2171
 
 * <template rank="2" match="item2|item3" name=""
2172
 
 *         mode="" calls="10" time="30" average="3"/>
2173
 
 * <template rank="3" match="item1" name=""
2174
 
 *         mode="" calls="5" time="17" average="3"/>
2175
 
 * </profile>
2176
 
 * The caller will need to free up the returned tree with xmlFreeDoc()
2177
 
 *
2178
 
 * Returns the xmlDocPtr corresponding to the result or NULL if not available.
2179
 
 */
2180
 
 
2181
 
xmlDocPtr
2182
 
xsltGetProfileInformation(xsltTransformContextPtr ctxt)
2183
 
{
2184
 
    xmlDocPtr ret = NULL;
2185
 
    xmlNodePtr root, child;
2186
 
    char buf[100];
2187
 
 
2188
 
    xsltStylesheetPtr style;
2189
 
    xsltTemplatePtr *templates;
2190
 
    xsltTemplatePtr templ;
2191
 
    int nb = 0, max = 0, i, j;
2192
 
 
2193
 
    if (!ctxt)
2194
 
        return NULL;
2195
 
 
2196
 
    if (!ctxt->profile)
2197
 
        return NULL;
2198
 
 
2199
 
    nb = 0;
2200
 
    max = 10000;
2201
 
    templates =
2202
 
        (xsltTemplatePtr *) xmlMalloc(max * sizeof(xsltTemplatePtr));
2203
 
    if (templates == NULL)
2204
 
        return NULL;
2205
 
 
2206
 
    /*
2207
 
     * collect all the templates in an array
2208
 
     */
2209
 
    style = ctxt->style;
2210
 
    while (style != NULL) {
2211
 
        templ = style->templates;
2212
 
        while (templ != NULL) {
2213
 
            if (nb >= max)
2214
 
                break;
2215
 
 
2216
 
            if (templ->nbCalls > 0)
2217
 
                templates[nb++] = templ;
2218
 
            templ = templ->next;
2219
 
        }
2220
 
 
2221
 
        style = (xsltStylesheetPtr) xsltNextImport(style);
2222
 
    }
2223
 
 
2224
 
    /*
2225
 
     * Sort the array by time spent
2226
 
     */
2227
 
    for (i = 0; i < nb - 1; i++) {
2228
 
        for (j = i + 1; j < nb; j++) {
2229
 
            if ((templates[i]->time <= templates[j]->time) ||
2230
 
                ((templates[i]->time == templates[j]->time) &&
2231
 
                 (templates[i]->nbCalls <= templates[j]->nbCalls))) {
2232
 
                templ = templates[j];
2233
 
                templates[j] = templates[i];
2234
 
                templates[i] = templ;
2235
 
            }
2236
 
        }
2237
 
    }
2238
 
 
2239
 
    /*
2240
 
     * Generate a document corresponding to the results.
2241
 
     */
2242
 
    ret = xmlNewDoc(BAD_CAST "1.0");
2243
 
    root = xmlNewDocNode(ret, NULL, BAD_CAST "profile", NULL);
2244
 
    xmlDocSetRootElement(ret, root);
2245
 
 
2246
 
    for (i = 0; i < nb; i++) {
2247
 
        child = xmlNewChild(root, NULL, BAD_CAST "template", NULL);
2248
 
        sprintf(buf, "%d", i + 1);
2249
 
        xmlSetProp(child, BAD_CAST "rank", BAD_CAST buf);
2250
 
        xmlSetProp(child, BAD_CAST "match", BAD_CAST templates[i]->match);
2251
 
        xmlSetProp(child, BAD_CAST "name", BAD_CAST templates[i]->name);
2252
 
        xmlSetProp(child, BAD_CAST "mode", BAD_CAST templates[i]->mode);
2253
 
 
2254
 
        sprintf(buf, "%d", templates[i]->nbCalls);
2255
 
        xmlSetProp(child, BAD_CAST "calls", BAD_CAST buf);
2256
 
 
2257
 
        sprintf(buf, "%ld", templates[i]->time);
2258
 
        xmlSetProp(child, BAD_CAST "time", BAD_CAST buf);
2259
 
 
2260
 
        sprintf(buf, "%ld", templates[i]->time / templates[i]->nbCalls);
2261
 
        xmlSetProp(child, BAD_CAST "average", BAD_CAST buf);
2262
 
    };
2263
 
 
2264
 
    xmlFree(templates);
2265
 
 
2266
 
    return ret;
2267
 
}
2268
 
 
2269
 
/************************************************************************
2270
 
 *                                                                      *
2271
 
 *              Hooks for libxml2 XPath                                 *
2272
 
 *                                                                      *
2273
 
 ************************************************************************/
2274
 
 
2275
 
/**
2276
 
 * xsltXPathCompileFlags:
2277
 
 * @style: the stylesheet
2278
 
 * @str:  the XPath expression
2279
 
 * @flags: extra compilation flags to pass down to libxml2 XPath
2280
 
 *
2281
 
 * Compile an XPath expression
2282
 
 *
2283
 
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
2284
 
 *         the caller has to free the object.
2285
 
 */
2286
 
xmlXPathCompExprPtr
2287
 
xsltXPathCompileFlags(xsltStylesheetPtr style, const xmlChar *str, int flags) {
2288
 
    xmlXPathContextPtr xpathCtxt;
2289
 
    xmlXPathCompExprPtr ret;
2290
 
 
2291
 
    if (style != NULL) {
2292
 
#ifdef XSLT_REFACTORED_XPATHCOMP
2293
 
        if (XSLT_CCTXT(style)) {
2294
 
            /*
2295
 
            * Proposed by Jerome Pesenti
2296
 
            * --------------------------
2297
 
            * For better efficiency we'll reuse the compilation
2298
 
            * context's XPath context. For the common stylesheet using
2299
 
            * XPath expressions this will reduce compilation time to
2300
 
            * about 50%.
2301
 
            *
2302
 
            * See http://mail.gnome.org/archives/xslt/2006-April/msg00037.html
2303
 
            */
2304
 
            xpathCtxt = XSLT_CCTXT(style)->xpathCtxt;
2305
 
            xpathCtxt->doc = style->doc;
2306
 
        } else
2307
 
            xpathCtxt = xmlXPathNewContext(style->doc);
2308
 
#else
2309
 
        xpathCtxt = xmlXPathNewContext(style->doc);
2310
 
#endif
2311
 
        if (xpathCtxt == NULL)
2312
 
            return NULL;
2313
 
        xpathCtxt->dict = style->dict;
2314
 
    } else {
2315
 
        xpathCtxt = xmlXPathNewContext(NULL);
2316
 
        if (xpathCtxt == NULL)
2317
 
            return NULL;
2318
 
    }
2319
 
    xpathCtxt->flags = flags;
2320
 
 
2321
 
    /*
2322
 
    * Compile the expression.
2323
 
    */
2324
 
    ret = xmlXPathCtxtCompile(xpathCtxt, str);
2325
 
 
2326
 
#ifdef XSLT_REFACTORED_XPATHCOMP
2327
 
    if ((style == NULL) || (! XSLT_CCTXT(style))) {
2328
 
        xmlXPathFreeContext(xpathCtxt);
2329
 
    }
2330
 
#else
2331
 
    xmlXPathFreeContext(xpathCtxt);
2332
 
#endif
2333
 
    /*
2334
 
     * TODO: there is a lot of optimizations which should be possible
2335
 
     *       like variable slot precomputations, function precomputations, etc.
2336
 
     */
2337
 
 
2338
 
    return(ret);
2339
 
}
2340
 
 
2341
 
/**
2342
 
 * xsltXPathCompile:
2343
 
 * @style: the stylesheet
2344
 
 * @str:  the XPath expression
2345
 
 *
2346
 
 * Compile an XPath expression
2347
 
 *
2348
 
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
2349
 
 *         the caller has to free the object.
2350
 
 */
2351
 
xmlXPathCompExprPtr
2352
 
xsltXPathCompile(xsltStylesheetPtr style, const xmlChar *str) {
2353
 
    return(xsltXPathCompileFlags(style, str, 0));
2354
 
}
2355
 
 
2356
 
/************************************************************************
2357
 
 *                                                                      *
2358
 
 *              Hooks for the debugger                                  *
2359
 
 *                                                                      *
2360
 
 ************************************************************************/
2361
 
 
2362
 
/*
2363
 
 * There is currently only 3 debugging callback defined
2364
 
 * Debugger callbacks are disabled by default
2365
 
 */
2366
 
#define XSLT_CALLBACK_NUMBER 3
2367
 
 
2368
 
typedef struct _xsltDebuggerCallbacks xsltDebuggerCallbacks;
2369
 
typedef xsltDebuggerCallbacks *xsltDebuggerCallbacksPtr;
2370
 
struct _xsltDebuggerCallbacks {
2371
 
    xsltHandleDebuggerCallback handler;
2372
 
    xsltAddCallCallback add;
2373
 
    xsltDropCallCallback drop;
2374
 
};
2375
 
 
2376
 
static xsltDebuggerCallbacks xsltDebuggerCurrentCallbacks = {
2377
 
    NULL, /* handler */
2378
 
    NULL, /* add */
2379
 
    NULL  /* drop */
2380
 
};
2381
 
 
2382
 
int xslDebugStatus;
2383
 
 
2384
 
/**
2385
 
 * xsltSetDebuggerStatus:
2386
 
 * @value : the value to be set
2387
 
 *
2388
 
 * This function sets the value of xslDebugStatus.
2389
 
 */
2390
 
void
2391
 
xsltSetDebuggerStatus(int value)
2392
 
{
2393
 
    xslDebugStatus = value;
2394
 
}
2395
 
 
2396
 
/**
2397
 
 * xsltGetDebuggerStatus:
2398
 
 *
2399
 
 * Get xslDebugStatus.
2400
 
 *
2401
 
 * Returns the value of xslDebugStatus.
2402
 
 */
2403
 
int
2404
 
xsltGetDebuggerStatus(void)
2405
 
{
2406
 
    return(xslDebugStatus);
2407
 
}
2408
 
 
2409
 
/**
2410
 
 * xsltSetDebuggerCallbacks:
2411
 
 * @no : number of callbacks
2412
 
 * @block : the block of callbacks
2413
 
 *
2414
 
 * This function allow to plug a debugger into the XSLT library
2415
 
 * @block points to a block of memory containing the address of @no
2416
 
 * callback routines.
2417
 
 *
2418
 
 * Returns 0 in case of success and -1 in case of error
2419
 
 */
2420
 
int
2421
 
xsltSetDebuggerCallbacks(int no, void *block)
2422
 
{
2423
 
    xsltDebuggerCallbacksPtr callbacks;
2424
 
 
2425
 
    if ((block == NULL) || (no != XSLT_CALLBACK_NUMBER))
2426
 
        return(-1);
2427
 
 
2428
 
    callbacks = (xsltDebuggerCallbacksPtr) block;
2429
 
    xsltDebuggerCurrentCallbacks.handler = callbacks->handler;
2430
 
    xsltDebuggerCurrentCallbacks.add  = callbacks->add;
2431
 
    xsltDebuggerCurrentCallbacks.drop  = callbacks->drop;
2432
 
    return(0);
2433
 
}
2434
 
 
2435
 
/**
2436
 
 * xslHandleDebugger:
2437
 
 * @cur : source node being executed
2438
 
 * @node : data node being processed
2439
 
 * @templ : temlate that applies to node
2440
 
 * @ctxt : the xslt transform context
2441
 
 *
2442
 
 * If either cur or node are a breakpoint, or xslDebugStatus in state
2443
 
 *   where debugging must occcur at this time then transfer control
2444
 
 *   to the xslDebugBreak function
2445
 
 */
2446
 
void
2447
 
xslHandleDebugger(xmlNodePtr cur, xmlNodePtr node, xsltTemplatePtr templ,
2448
 
                  xsltTransformContextPtr ctxt)
2449
 
{
2450
 
    if (xsltDebuggerCurrentCallbacks.handler != NULL)
2451
 
        xsltDebuggerCurrentCallbacks.handler(cur, node, templ, ctxt);
2452
 
}
2453
 
 
2454
 
/**
2455
 
 * xslAddCall:
2456
 
 * @templ : current template being applied
2457
 
 * @source : the source node being processed
2458
 
 *
2459
 
 * Add template "call" to call stack
2460
 
 * Returns : 1 on sucess 0 otherwise an error may be printed if
2461
 
 *            WITH_XSLT_DEBUG_BREAKPOINTS is defined
2462
 
 */
2463
 
int
2464
 
xslAddCall(xsltTemplatePtr templ, xmlNodePtr source)
2465
 
{
2466
 
    if (xsltDebuggerCurrentCallbacks.add != NULL)
2467
 
        return(xsltDebuggerCurrentCallbacks.add(templ, source));
2468
 
    return(0);
2469
 
}
2470
 
 
2471
 
/**
2472
 
 * xslDropCall:
2473
 
 *
2474
 
 * Drop the topmost item off the call stack
2475
 
 */
2476
 
void
2477
 
xslDropCall(void)
2478
 
{
2479
 
    if (xsltDebuggerCurrentCallbacks.drop != NULL)
2480
 
        xsltDebuggerCurrentCallbacks.drop();
2481
 
}
2482