Coverage Report

Created: 2026-03-31 11:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/workdir/UnpackedTarball/libxslt/libxslt/variables.c
Line
Count
Source
1
/*
2
 * variables.c: Implementation of the variable storage and lookup
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
#include <string.h>
16
17
#include <libxml/xmlmemory.h>
18
#include <libxml/tree.h>
19
#include <libxml/valid.h>
20
#include <libxml/hash.h>
21
#include <libxml/xmlerror.h>
22
#include <libxml/xpath.h>
23
#include <libxml/xpathInternals.h>
24
#include <libxml/parserInternals.h>
25
#include <libxml/dict.h>
26
#include "xslt.h"
27
#include "xsltInternals.h"
28
#include "xsltutils.h"
29
#include "variables.h"
30
#include "transform.h"
31
#include "imports.h"
32
#include "preproc.h"
33
#include "keys.h"
34
35
#ifdef WITH_XSLT_DEBUG
36
 #define WITH_XSLT_DEBUG_VARIABLE
37
#endif
38
39
#ifdef XSLT_REFACTORED
40
const xmlChar *xsltDocFragFake = (const xmlChar *) " fake node libxslt";
41
#endif
42
43
static const xmlChar *xsltComputingGlobalVarMarker =
44
 (const xmlChar *) " var/param being computed";
45
46
#define XSLT_VAR_GLOBAL (1<<0)
47
0
#define XSLT_VAR_IN_SELECT (1<<1)
48
0
#define XSLT_TCTXT_VARIABLE(c) ((xsltStackElemPtr) (c)->contextVariable)
49
50
static xsltRVTListPtr
51
xsltRVTListCreate(void)
52
0
{
53
0
    xsltRVTListPtr ret;
54
55
0
    ret = (xsltRVTListPtr) xmlMalloc(sizeof(xsltRVTList));
56
0
    if (ret == NULL) {
57
0
  xsltTransformError(NULL, NULL, NULL,
58
0
      "xsltRVTListCreate: malloc failed\n");
59
0
  return(NULL);
60
0
    }
61
0
    memset(ret, 0, sizeof(xsltRVTList));
62
0
    return(ret);
63
0
}
64
65
/************************************************************************
66
 *                  *
67
 *  Result Value Tree (Result Tree Fragment) interfaces     *
68
 *                  *
69
 ************************************************************************/
70
/**
71
 * xsltCreateRVT:
72
 * @ctxt:  an XSLT transformation context
73
 *
74
 * Creates a Result Value Tree
75
 * (the XSLT 1.0 term for this is "Result Tree Fragment")
76
 *
77
 * Returns the result value tree or NULL in case of API or internal errors.
78
 */
79
xmlDocPtr
80
xsltCreateRVT(xsltTransformContextPtr ctxt)
81
0
{
82
0
    xsltRVTListPtr rvtList;
83
0
    xmlDocPtr container;
84
85
    /*
86
    * Question: Why is this function public?
87
    * Answer: It is called by the EXSLT module.
88
    */
89
0
    if (ctxt == NULL)
90
0
  return(NULL);
91
92
    /*
93
    * Reuse a RTF from the cache if available.
94
    */
95
0
    if (ctxt->cache->rvtList) {
96
0
        rvtList = ctxt->cache->rvtList;
97
0
  container = ctxt->cache->rvtList->RVT;
98
0
  ctxt->cache->rvtList = rvtList->next;
99
0
        xmlFree(rvtList);
100
0
  if (ctxt->cache->nbRVT > 0)
101
0
      ctxt->cache->nbRVT--;
102
#ifdef XSLT_DEBUG_PROFILE_CACHE
103
  ctxt->cache->dbgReusedRVTs++;
104
#endif
105
0
  return(container);
106
0
    }
107
108
0
    container = xmlNewDoc(NULL);
109
0
    if (container == NULL)
110
0
  return(NULL);
111
0
    container->dict = ctxt->dict;
112
0
    xmlDictReference(container->dict);
113
0
    XSLT_MARK_RES_TREE_FRAG(container);
114
0
    container->doc = container;
115
0
    container->parent = NULL;
116
0
    return(container);
117
0
}
118
119
/**
120
 * xsltRegisterTmpRVT:
121
 * @ctxt:  an XSLT transformation context
122
 * @RVT:  a result value tree (Result Tree Fragment)
123
 *
124
 * Registers the result value tree (XSLT 1.0 term: Result Tree Fragment)
125
 * in the garbage collector.
126
 * The fragment will be freed at the exit of the currently
127
 * instantiated xsl:template.
128
 * Obsolete; this function might produce massive memory overhead,
129
 * since the fragment is only freed when the current xsl:template
130
 * exits. Use xsltRegisterLocalRVT() instead.
131
 *
132
 * Returns 0 in case of success and -1 in case of API or internal errors.
133
 */
134
int
135
xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
136
0
{
137
0
    xsltRVTListPtr list;
138
139
0
    if ((ctxt == NULL) || (RVT == NULL))
140
0
  return(-1);
141
142
0
    list = xsltRVTListCreate();
143
0
    if (list == NULL) return(-1);
144
145
0
    RVT->compression = XSLT_RVT_LOCAL;
146
0
    list->RVT = RVT;
147
148
    /*
149
    * We'll restrict the lifetime of user-created fragments
150
    * insinde an xsl:variable and xsl:param to the lifetime of the
151
    * var/param itself.
152
    */
153
0
    if (ctxt->contextVariable != NULL) {
154
0
  list->next = XSLT_TCTXT_VARIABLE(ctxt)->fragment;
155
0
  XSLT_TCTXT_VARIABLE(ctxt)->fragment = list;
156
0
  return(0);
157
0
    }
158
159
0
    list->next = ctxt->tmpRVTList;
160
0
    ctxt->tmpRVTList = list;
161
0
    return(0);
162
0
}
163
164
/**
165
 * xsltRegisterLocalRVT:
166
 * @ctxt:  an XSLT transformation context
167
 * @RVT:  a result value tree (Result Tree Fragment; xmlDocPtr)
168
 *
169
 * Registers a result value tree (XSLT 1.0 term: Result Tree Fragment)
170
 * in the RVT garbage collector.
171
 * The fragment will be freed when the instruction which created the
172
 * fragment exits.
173
 *
174
 * Returns 0 in case of success and -1 in case of API or internal errors.
175
 */
176
int
177
xsltRegisterLocalRVT(xsltTransformContextPtr ctxt,
178
         xmlDocPtr RVT)
179
0
{
180
0
    xsltRVTListPtr list;
181
182
0
    if ((ctxt == NULL) || (RVT == NULL))
183
0
  return(-1);
184
185
0
    list = xsltRVTListCreate();
186
0
    if (list == NULL) return(-1);
187
188
0
    RVT->compression = XSLT_RVT_LOCAL;
189
0
    list->RVT = RVT;
190
191
    /*
192
    * When evaluating "select" expressions of xsl:variable
193
    * and xsl:param, we need to bind newly created tree fragments
194
    * to the variable itself; otherwise the fragment will be
195
    * freed before we leave the scope of a var.
196
    */
197
0
    if ((ctxt->contextVariable != NULL) &&
198
0
  (XSLT_TCTXT_VARIABLE(ctxt)->flags & XSLT_VAR_IN_SELECT))
199
0
    {
200
0
  list->next = XSLT_TCTXT_VARIABLE(ctxt)->fragment;
201
0
  XSLT_TCTXT_VARIABLE(ctxt)->fragment = list;
202
0
  return(0);
203
0
    }
204
    /*
205
    * Store the fragment in the scope of the current instruction.
206
    * If not reference by a returning instruction (like EXSLT's function),
207
    * then this fragment will be freed, when the instruction exits.
208
    */
209
0
    list->next = ctxt->localRVTList;
210
0
    ctxt->localRVTList = list;
211
0
    return(0);
212
0
}
213
214
/**
215
 * xsltExtensionInstructionResultFinalize:
216
 * @ctxt:  an XSLT transformation context
217
 *
218
 * Finalizes the data (e.g. result tree fragments) created
219
 * within a value-returning process (e.g. EXSLT's function).
220
 * Tree fragments marked as being returned by a function are
221
 * set to normal state, which means that the fragment garbage
222
 * collector will free them after the function-calling process exits.
223
 *
224
 * Returns 0 in case of success and -1 in case of API or internal errors.
225
 *
226
 * This function is unsupported in newer releases of libxslt.
227
 */
228
int
229
xsltExtensionInstructionResultFinalize(
230
        xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED)
231
0
{
232
0
    xmlGenericError(xmlGenericErrorContext,
233
0
            "xsltExtensionInstructionResultFinalize is unsupported "
234
0
            "in this release of libxslt.\n");
235
0
    return(-1);
236
0
}
237
238
/**
239
 * xsltExtensionInstructionResultRegister:
240
 * @ctxt: an XSLT transformation context
241
 * @obj: an XPath object to be inspected for result tree fragments
242
 *
243
 * Marks the result of a value-returning extension instruction
244
 * in order to avoid it being garbage collected before the
245
 * extension instruction exits.
246
 * Note that one still has to additionally register any newly created
247
 * tree fragments (via xsltCreateRVT()) with xsltRegisterLocalRVT().
248
 *
249
 * Returns 0 in case of success and -1 in case of error.
250
 *
251
 * It isn't necessary to call this function in newer releases of
252
 * libxslt.
253
 */
254
int
255
xsltExtensionInstructionResultRegister(
256
        xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
257
  xmlXPathObjectPtr obj ATTRIBUTE_UNUSED)
258
0
{
259
0
    return(0);
260
0
}
261
262
/**
263
 * xsltFlagRVTs:
264
 * @ctxt: an XSLT transformation context
265
 * @obj: an XPath object to be inspected for result tree fragments
266
 * @val: the flag value
267
 *
268
 * Updates ownership information of RVTs in @obj according to @val.
269
 *
270
 * @val = XSLT_RVT_FUNC_RESULT for the result of an extension function, so its
271
 *        RVTs won't be destroyed after leaving the returning scope.
272
 * @val = XSLT_RVT_LOCAL for the result of an extension function to reset
273
 *        the state of its RVTs after it was returned to a new scope.
274
 * @val = XSLT_RVT_GLOBAL for parts of global variables.
275
 *
276
 * Returns 0 in case of success and -1 in case of error.
277
 */
278
int
279
0
xsltFlagRVTs(xsltTransformContextPtr ctxt, xmlXPathObjectPtr obj, int val) {
280
0
    int i;
281
0
    xmlNodePtr cur;
282
0
    xmlDocPtr doc;
283
284
0
    if ((ctxt == NULL) || (obj == NULL))
285
0
  return(-1);
286
287
    /*
288
    * OPTIMIZE TODO: If no local variables/params and no local tree
289
    * fragments were created, then we don't need to analyse the XPath
290
    * objects for tree fragments.
291
    */
292
293
0
    if ((obj->type != XPATH_NODESET) && (obj->type != XPATH_XSLT_TREE))
294
0
  return(0);
295
0
    if ((obj->nodesetval == NULL) || (obj->nodesetval->nodeNr == 0))
296
0
  return(0);
297
298
0
    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
299
0
  cur = obj->nodesetval->nodeTab[i];
300
0
  if (cur->type == XML_NAMESPACE_DECL) {
301
      /*
302
      * The XPath module sets the owner element of a ns-node on
303
      * the ns->next field.
304
      */
305
0
      if ((((xmlNsPtr) cur)->next != NULL) &&
306
0
    (((xmlNsPtr) cur)->next->type == XML_ELEMENT_NODE))
307
0
      {
308
0
    cur = (xmlNodePtr) ((xmlNsPtr) cur)->next;
309
0
    doc = cur->doc;
310
0
      } else {
311
0
    xsltTransformError(ctxt, NULL, ctxt->inst,
312
0
        "Internal error in xsltFlagRVTs(): "
313
0
        "Cannot retrieve the doc of a namespace node.\n");
314
0
    return(-1);
315
0
      }
316
0
  } else {
317
0
      doc = cur->doc;
318
0
  }
319
0
  if (doc == NULL) {
320
0
      xsltTransformError(ctxt, NULL, ctxt->inst,
321
0
    "Internal error in xsltFlagRVTs(): "
322
0
    "Cannot retrieve the doc of a node.\n");
323
0
      return(-1);
324
0
  }
325
0
  if (doc->name && (doc->name[0] == ' ') &&
326
0
            doc->compression != XSLT_RVT_GLOBAL) {
327
      /*
328
      * This is a result tree fragment.
329
      * We store ownership information in the @compression field.
330
      * TODO: How do we know if this is a doc acquired via the
331
      *  document() function?
332
      */
333
#ifdef WITH_XSLT_DEBUG_VARIABLE
334
            XSLT_TRACE(ctxt, XSLT_TRACE_VARIABLES,
335
                       xsltGenericDebug(xsltGenericDebugContext,
336
                       "Flagging RVT %p: %d -> %d\n",
337
                       (void *) doc, doc->compression, val));
338
#endif
339
340
0
            if (val == XSLT_RVT_LOCAL) {
341
0
                if (doc->compression == XSLT_RVT_FUNC_RESULT)
342
0
                    doc->compression = XSLT_RVT_LOCAL;
343
0
            } else if (val == XSLT_RVT_GLOBAL) {
344
0
                if (doc->compression != XSLT_RVT_LOCAL) {
345
0
        xmlGenericError(xmlGenericErrorContext,
346
0
                            "xsltFlagRVTs: Invalid transition %d => GLOBAL\n",
347
0
                            doc->compression);
348
0
                    doc->compression = XSLT_RVT_GLOBAL;
349
0
                    return(-1);
350
0
                }
351
352
                /* Will be registered as persistant in xsltReleaseLocalRVTs. */
353
0
                doc->compression = XSLT_RVT_GLOBAL;
354
0
            } else if (val == XSLT_RVT_FUNC_RESULT) {
355
0
          doc->compression = val;
356
0
            }
357
0
  }
358
0
    }
359
360
0
    return(0);
361
0
}
362
363
/**
364
 * xsltReleaseRVT:
365
 * @ctxt:  an XSLT transformation context
366
 * @RVT:  a result value tree (Result Tree Fragment)
367
 *
368
 * Either frees the RVT (which is an xmlDoc) or stores it in the context's
369
 * cache for later reuse. Preserved for ABI/API compatibility; internal use
370
 * has all migrated to xsltReleaseRVTList().
371
 */
372
void
373
xsltReleaseRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
374
0
{
375
0
    if (RVT == NULL)
376
0
  return;
377
378
0
    xsltRVTListPtr list = xsltRVTListCreate();
379
0
    if (list == NULL) {
380
0
        if (RVT->_private != NULL) {
381
0
            xsltFreeDocumentKeys((xsltDocumentPtr) RVT->_private);
382
0
            xmlFree(RVT->_private);
383
0
        }
384
0
        xmlFreeDoc(RVT);
385
0
        return;
386
0
    }
387
388
0
    xsltReleaseRVTList(ctxt, list);
389
0
}
390
391
/**
392
 * xsltReleaseRVTList:
393
 * @ctxt:  an XSLT transformation context
394
 * @list:  a list node containing a result value tree (Result Tree Fragment)
395
 *
396
 * Either frees the list node or stores it in the context's cache for later
397
 * reuse. Optimization to avoid adding a fallible allocation path when the
398
 * caller already has a RVT list node.
399
 */
400
void
401
xsltReleaseRVTList(xsltTransformContextPtr ctxt, xsltRVTListPtr list)
402
0
{
403
0
    if (list == NULL)
404
0
  return;
405
406
0
    if (ctxt && (ctxt->cache->nbRVT < 40)) {
407
  /*
408
  * Store the Result Tree Fragment.
409
  * Free the document info.
410
  */
411
0
  if (list->RVT->_private != NULL) {
412
0
      xsltFreeDocumentKeys((xsltDocumentPtr) list->RVT->_private);
413
0
      xmlFree(list->RVT->_private);
414
0
      list->RVT->_private = NULL;
415
0
  }
416
  /*
417
  * Clear the document tree.
418
  */
419
0
  if (list->RVT->children != NULL) {
420
0
      xmlFreeNodeList(list->RVT->children);
421
0
      list->RVT->children = NULL;
422
0
      list->RVT->last = NULL;
423
0
  }
424
0
  if (list->RVT->ids != NULL) {
425
0
      xmlFreeIDTable((xmlIDTablePtr) list->RVT->ids);
426
0
      list->RVT->ids = NULL;
427
0
  }
428
429
  /*
430
  * Reset the ownership information.
431
  */
432
0
  list->RVT->compression = 0;
433
434
0
  list->next = ctxt->cache->rvtList;
435
0
  ctxt->cache->rvtList = list;
436
437
0
  ctxt->cache->nbRVT++;
438
439
#ifdef XSLT_DEBUG_PROFILE_CACHE
440
  ctxt->cache->dbgCachedRVTs++;
441
#endif
442
0
  return;
443
0
    }
444
    /*
445
    * Free it.
446
    */
447
0
    if (list->RVT->_private != NULL) {
448
0
  xsltFreeDocumentKeys((xsltDocumentPtr) list->RVT->_private);
449
0
  xmlFree(list->RVT->_private);
450
0
    }
451
0
    xmlFreeDoc(list->RVT);
452
0
    xmlFree(list);
453
0
}
454
455
/**
456
 * xsltRegisterPersistRVT:
457
 * @ctxt:  an XSLT transformation context
458
 * @RVT:  a result value tree (Result Tree Fragment)
459
 *
460
 * Register the result value tree (XSLT 1.0 term: Result Tree Fragment)
461
 * in the fragment garbage collector.
462
 * The fragment will be freed when the transformation context is
463
 * freed.
464
 *
465
 * Returns 0 in case of success and -1 in case of error.
466
 */
467
int
468
xsltRegisterPersistRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
469
0
{
470
0
    xsltRVTListPtr list;
471
472
0
    if ((ctxt == NULL) || (RVT == NULL)) return(-1);
473
474
0
    list = xsltRVTListCreate();
475
0
    if (list == NULL) return(-1);
476
477
0
    RVT->compression = XSLT_RVT_GLOBAL;
478
0
    list->RVT = RVT;
479
0
    list->next = ctxt->persistRVTList;
480
0
    ctxt->persistRVTList = list;
481
0
    return(0);
482
0
}
483
484
/**
485
 * xsltFreeRVTs:
486
 * @ctxt:  an XSLT transformation context
487
 *
488
 * Frees all registered result value trees (Result Tree Fragments)
489
 * of the transformation. Internal function; should not be called
490
 * by user-code.
491
 */
492
void
493
xsltFreeRVTs(xsltTransformContextPtr ctxt)
494
0
{
495
0
    xsltRVTListPtr cur, next;
496
497
0
    if (ctxt == NULL)
498
0
  return;
499
    /*
500
    * Local fragments.
501
    */
502
0
    cur = ctxt->localRVTList;
503
0
    while (cur != NULL) {
504
0
        next = cur->next;
505
0
  if (cur->RVT->_private != NULL) {
506
0
      xsltFreeDocumentKeys(cur->RVT->_private);
507
0
      xmlFree(cur->RVT->_private);
508
0
  }
509
0
  xmlFreeDoc(cur->RVT);
510
0
        xmlFree(cur);
511
0
  cur = next;
512
0
    }
513
0
    ctxt->localRVTList = NULL;
514
    /*
515
    * User-created per-template fragments.
516
    */
517
0
    cur = ctxt->tmpRVTList;
518
0
    while (cur != NULL) {
519
0
        next = cur->next;
520
0
  if (cur->RVT->_private != NULL) {
521
0
      xsltFreeDocumentKeys(cur->RVT->_private);
522
0
      xmlFree(cur->RVT->_private);
523
0
  }
524
0
  xmlFreeDoc(cur->RVT);
525
0
        xmlFree(cur);
526
0
  cur = next;
527
0
    }
528
0
    ctxt->tmpRVTList = NULL;
529
    /*
530
    * Global fragments.
531
    */
532
0
    cur = ctxt->persistRVTList;
533
0
    while (cur != NULL) {
534
0
        next = cur->next;
535
0
  if (cur->RVT->_private != NULL) {
536
0
      xsltFreeDocumentKeys(cur->RVT->_private);
537
0
      xmlFree(cur->RVT->_private);
538
0
  }
539
0
  xmlFreeDoc(cur->RVT);
540
0
        xmlFree(cur);
541
0
  cur = next;
542
0
    }
543
0
    ctxt->persistRVTList = NULL;
544
0
}
545
546
/************************************************************************
547
 *                  *
548
 *      Module interfaces       *
549
 *                  *
550
 ************************************************************************/
551
552
/**
553
 * xsltNewStackElem:
554
 *
555
 * Create a new XSLT ParserContext
556
 *
557
 * Returns the newly allocated xsltParserStackElem or NULL in case of error
558
 */
559
static xsltStackElemPtr
560
xsltNewStackElem(xsltTransformContextPtr ctxt)
561
0
{
562
0
    xsltStackElemPtr ret;
563
    /*
564
    * Reuse a stack item from the cache if available.
565
    */
566
0
    if (ctxt && ctxt->cache->stackItems) {
567
0
  ret = ctxt->cache->stackItems;
568
0
  ctxt->cache->stackItems = ret->next;
569
0
  ret->next = NULL;
570
0
  ctxt->cache->nbStackItems--;
571
#ifdef XSLT_DEBUG_PROFILE_CACHE
572
  ctxt->cache->dbgReusedVars++;
573
#endif
574
0
  return(ret);
575
0
    }
576
0
    ret = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
577
0
    if (ret == NULL) {
578
0
  xsltTransformError(NULL, NULL, NULL,
579
0
    "xsltNewStackElem : malloc failed\n");
580
0
  return(NULL);
581
0
    }
582
0
    memset(ret, 0, sizeof(xsltStackElem));
583
0
    ret->context = ctxt;
584
0
    return(ret);
585
0
}
586
587
/**
588
 * xsltCopyStackElem:
589
 * @elem:  an XSLT stack element
590
 *
591
 * Makes a copy of the stack element
592
 *
593
 * Returns the copy of NULL
594
 */
595
static xsltStackElemPtr
596
0
xsltCopyStackElem(xsltStackElemPtr elem) {
597
0
    xsltStackElemPtr cur;
598
599
0
    cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
600
0
    if (cur == NULL) {
601
0
  xsltTransformError(NULL, NULL, NULL,
602
0
    "xsltCopyStackElem : malloc failed\n");
603
0
  return(NULL);
604
0
    }
605
0
    memset(cur, 0, sizeof(xsltStackElem));
606
0
    cur->context = elem->context;
607
0
    cur->name = elem->name;
608
0
    cur->nameURI = elem->nameURI;
609
0
    cur->select = elem->select;
610
0
    cur->tree = elem->tree;
611
0
    cur->comp = elem->comp;
612
0
    return(cur);
613
0
}
614
615
/**
616
 * xsltFreeStackElem:
617
 * @elem:  an XSLT stack element
618
 *
619
 * Free up the memory allocated by @elem
620
 */
621
static void
622
0
xsltFreeStackElem(xsltStackElemPtr elem) {
623
0
    if (elem == NULL)
624
0
  return;
625
0
    if (elem->value != NULL)
626
0
  xmlXPathFreeObject(elem->value);
627
    /*
628
    * Release the list of temporary Result Tree Fragments.
629
    */
630
0
    if (elem->context) {
631
0
  xsltRVTListPtr cur;
632
633
0
  while (elem->fragment != NULL) {
634
0
      cur = elem->fragment;
635
0
      elem->fragment = cur->next;
636
637
0
            if (cur->RVT->compression == XSLT_RVT_LOCAL) {
638
0
    xsltReleaseRVTList(elem->context, cur);
639
0
            } else if (cur->RVT->compression == XSLT_RVT_FUNC_RESULT) {
640
0
                xsltRegisterLocalRVT(elem->context, cur->RVT);
641
0
                cur->RVT->compression = XSLT_RVT_FUNC_RESULT;
642
0
                xmlFree(cur);
643
0
            } else {
644
0
                xmlGenericError(xmlGenericErrorContext,
645
0
                        "xsltFreeStackElem: Unexpected RVT flag %d\n",
646
0
                        cur->RVT->compression);
647
0
            }
648
0
  }
649
0
    }
650
    /*
651
    * Cache or free the variable structure.
652
    */
653
0
    if (elem->context && (elem->context->cache->nbStackItems < 50)) {
654
  /*
655
  * Store the item in the cache.
656
  */
657
0
  xsltTransformContextPtr ctxt = elem->context;
658
0
  memset(elem, 0, sizeof(xsltStackElem));
659
0
  elem->context = ctxt;
660
0
  elem->next = ctxt->cache->stackItems;
661
0
  ctxt->cache->stackItems = elem;
662
0
  ctxt->cache->nbStackItems++;
663
#ifdef XSLT_DEBUG_PROFILE_CACHE
664
  ctxt->cache->dbgCachedVars++;
665
#endif
666
0
  return;
667
0
    }
668
0
    xmlFree(elem);
669
0
}
670
671
static void
672
0
xsltFreeStackElemEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
673
0
    xsltFreeStackElem((xsltStackElemPtr) payload);
674
0
}
675
676
677
/**
678
 * xsltFreeStackElemList:
679
 * @elem:  an XSLT stack element
680
 *
681
 * Free up the memory allocated by @elem
682
 */
683
void
684
0
xsltFreeStackElemList(xsltStackElemPtr elem) {
685
0
    xsltStackElemPtr next;
686
687
0
    while (elem != NULL) {
688
0
  next = elem->next;
689
0
  xsltFreeStackElem(elem);
690
0
  elem = next;
691
0
    }
692
0
}
693
694
/**
695
 * xsltStackLookup:
696
 * @ctxt:  an XSLT transformation context
697
 * @name:  the local part of the name
698
 * @nameURI:  the URI part of the name
699
 *
700
 * Locate an element in the stack based on its name.
701
 */
702
static xsltStackElemPtr
703
xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
704
0
          const xmlChar *nameURI) {
705
0
    int i;
706
0
    xsltStackElemPtr cur;
707
708
0
    if ((ctxt == NULL) || (name == NULL) || (ctxt->varsNr == 0))
709
0
  return(NULL);
710
711
    /*
712
     * Do the lookup from the top of the stack, but
713
     * don't use params being computed in a call-param
714
     * First lookup expects the variable name and URI to
715
     * come from the disctionnary and hence pointer comparison.
716
     */
717
0
    for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
718
0
  cur = ctxt->varsTab[i-1];
719
0
  while (cur != NULL) {
720
0
      if ((cur->name == name) && (cur->nameURI == nameURI)) {
721
0
    return(cur);
722
0
      }
723
0
      cur = cur->next;
724
0
  }
725
0
    }
726
727
    /*
728
     * Redo the lookup with interned string compares
729
     * to avoid string compares.
730
     */
731
0
    name = xmlDictLookup(ctxt->dict, name, -1);
732
0
    if (nameURI != NULL)
733
0
        nameURI = xmlDictLookup(ctxt->dict, nameURI, -1);
734
735
0
    for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
736
0
  cur = ctxt->varsTab[i-1];
737
0
  while (cur != NULL) {
738
0
      if ((cur->name == name) && (cur->nameURI == nameURI)) {
739
0
    return(cur);
740
0
      }
741
0
      cur = cur->next;
742
0
  }
743
0
    }
744
745
0
    return(NULL);
746
0
}
747
748
#ifdef XSLT_REFACTORED
749
#else
750
751
/**
752
 * xsltCheckStackElem:
753
 * @ctxt:  xn XSLT transformation context
754
 * @name:  the variable name
755
 * @nameURI:  the variable namespace URI
756
 *
757
 * Checks whether a variable or param is already defined.
758
 *
759
 * URGENT TODO: Checks for redefinition of vars/params should be
760
 *  done only at compilation time.
761
 *
762
 * Returns 1 if variable is present, 2 if param is present, 3 if this
763
 *         is an inherited param, 0 if not found, -1 in case of failure.
764
 */
765
static int
766
xsltCheckStackElem(xsltTransformContextPtr ctxt, const xmlChar *name,
767
0
             const xmlChar *nameURI) {
768
0
    xsltStackElemPtr cur;
769
770
0
    if ((ctxt == NULL) || (name == NULL))
771
0
  return(-1);
772
773
0
    cur = xsltStackLookup(ctxt, name, nameURI);
774
0
    if (cur == NULL)
775
0
        return(0);
776
0
    if (cur->comp != NULL) {
777
0
        if (cur->comp->type == XSLT_FUNC_WITHPARAM)
778
0
      return(3);
779
0
  else if (cur->comp->type == XSLT_FUNC_PARAM)
780
0
      return(2);
781
0
    }
782
783
0
    return(1);
784
0
}
785
786
#endif /* XSLT_REFACTORED */
787
788
/**
789
 * xsltAddStackElem:
790
 * @ctxt:  xn XSLT transformation context
791
 * @elem:  a stack element
792
 *
793
 * Push an element (or list) onto the stack.
794
 * In case of a list, each member will be pushed into
795
 * a seperate slot; i.e. there's always 1 stack entry for
796
 * 1 stack element.
797
 *
798
 * Returns 0 in case of success, -1 in case of failure.
799
 */
800
static int
801
xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem)
802
0
{
803
0
    if ((ctxt == NULL) || (elem == NULL))
804
0
  return(-1);
805
806
0
    do {
807
0
  if (ctxt->varsNr >= ctxt->varsMax) {
808
0
            xsltStackElemPtr *tmp;
809
0
            int newMax = ctxt->varsMax == 0 ? 10 : 2 * ctxt->varsMax;
810
811
0
            tmp = (xsltStackElemPtr *) xmlRealloc(ctxt->varsTab,
812
0
                    newMax * sizeof(*tmp));
813
0
            if (tmp == NULL) {
814
0
                xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
815
0
                return (-1);
816
0
            }
817
0
            ctxt->varsTab = tmp;
818
0
            ctxt->varsMax = newMax;
819
0
  }
820
0
  ctxt->varsTab[ctxt->varsNr++] = elem;
821
0
  ctxt->vars = elem;
822
823
0
  elem = elem->next;
824
0
    } while (elem != NULL);
825
826
0
    return(0);
827
0
}
828
829
/**
830
 * xsltAddStackElemList:
831
 * @ctxt:  xn XSLT transformation context
832
 * @elems:  a stack element list
833
 *
834
 * Push an element list onto the stack.
835
 *
836
 * Returns 0 in case of success, -1 in case of failure.
837
 */
838
int
839
xsltAddStackElemList(xsltTransformContextPtr ctxt, xsltStackElemPtr elems)
840
0
{
841
0
    return(xsltAddStackElem(ctxt, elems));
842
0
}
843
844
/************************************************************************
845
 *                  *
846
 *      Module interfaces       *
847
 *                  *
848
 ************************************************************************/
849
850
/**
851
 * xsltEvalVariable:
852
 * @ctxt:  the XSLT transformation context
853
 * @variable:  the variable or parameter item
854
 * @comp: the compiled XSLT instruction
855
 *
856
 * Evaluate a variable value.
857
 *
858
 * Returns the XPath Object value or NULL in case of error
859
 */
860
static xmlXPathObjectPtr
861
xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr variable,
862
           xsltStylePreCompPtr castedComp)
863
0
{
864
#ifdef XSLT_REFACTORED
865
    xsltStyleItemVariablePtr comp =
866
  (xsltStyleItemVariablePtr) castedComp;
867
#else
868
0
    xsltStylePreCompPtr comp = castedComp;
869
0
#endif
870
0
    xmlXPathObjectPtr result = NULL;
871
0
    xmlNodePtr oldInst;
872
873
0
    if ((ctxt == NULL) || (variable == NULL))
874
0
  return(NULL);
875
876
    /*
877
    * A variable or parameter are evaluated on demand; thus the
878
    * context (of XSLT and XPath) need to be temporarily adjusted and
879
    * restored on exit.
880
    */
881
0
    oldInst = ctxt->inst;
882
883
#ifdef WITH_XSLT_DEBUG_VARIABLE
884
    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
885
  "Evaluating variable '%s'\n", variable->name));
886
#endif
887
0
    if (variable->select != NULL) {
888
0
  xmlXPathCompExprPtr xpExpr = NULL;
889
0
  xmlDocPtr oldXPDoc;
890
0
  xmlNodePtr oldXPContextNode;
891
0
  int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
892
0
  xmlNsPtr *oldXPNamespaces;
893
0
  xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
894
0
  xsltStackElemPtr oldVar = ctxt->contextVariable;
895
896
0
  if ((comp != NULL) && (comp->comp != NULL)) {
897
0
      xpExpr = comp->comp;
898
0
  } else {
899
0
      xpExpr = xmlXPathCtxtCompile(ctxt->xpathCtxt, variable->select);
900
0
  }
901
0
  if (xpExpr == NULL)
902
0
      return(NULL);
903
  /*
904
  * Save context states.
905
  */
906
0
  oldXPDoc = xpctxt->doc;
907
0
  oldXPContextNode = xpctxt->node;
908
0
  oldXPProximityPosition = xpctxt->proximityPosition;
909
0
  oldXPContextSize = xpctxt->contextSize;
910
0
  oldXPNamespaces = xpctxt->namespaces;
911
0
  oldXPNsNr = xpctxt->nsNr;
912
913
0
  xpctxt->node = ctxt->node;
914
  /*
915
  * OPTIMIZE TODO: Lame try to set the context doc.
916
  *   Get rid of this somehow in xpath.c.
917
  */
918
0
  if ((ctxt->node->type != XML_NAMESPACE_DECL) &&
919
0
      ctxt->node->doc)
920
0
      xpctxt->doc = ctxt->node->doc;
921
  /*
922
  * BUG TODO: The proximity position and the context size will
923
  *  potentially be wrong.
924
  *  Example:
925
  *  <xsl:template select="foo">
926
  *    <xsl:variable name="pos" select="position()"/>
927
  *    <xsl:for-each select="bar">
928
  *      <xsl:value-of select="$pos"/>
929
  *    </xsl:for-each>
930
  *  </xsl:template>
931
  *  Here the proximity position and context size are changed
932
  *  to the context of <xsl:for-each select="bar">, but
933
  *  the variable needs to be evaluated in the context of
934
  *  <xsl:template select="foo">.
935
  */
936
0
  if (comp != NULL) {
937
938
#ifdef XSLT_REFACTORED
939
      if (comp->inScopeNs != NULL) {
940
    xpctxt->namespaces = comp->inScopeNs->list;
941
    xpctxt->nsNr = comp->inScopeNs->xpathNumber;
942
      } else {
943
    xpctxt->namespaces = NULL;
944
    xpctxt->nsNr = 0;
945
      }
946
#else
947
0
      xpctxt->namespaces = comp->nsList;
948
0
      xpctxt->nsNr = comp->nsNr;
949
0
#endif
950
0
  } else {
951
0
      xpctxt->namespaces = NULL;
952
0
      xpctxt->nsNr = 0;
953
0
  }
954
955
  /*
956
  * We need to mark that we are "selecting" a var's value;
957
  * if any tree fragments are created inside the expression,
958
  * then those need to be stored inside the variable; otherwise
959
  * we'll eventually free still referenced fragments, before
960
  * we leave the scope of the variable.
961
  */
962
0
  ctxt->contextVariable = variable;
963
0
  variable->flags |= XSLT_VAR_IN_SELECT;
964
965
0
  result = xmlXPathCompiledEval(xpExpr, xpctxt);
966
967
0
  variable->flags ^= XSLT_VAR_IN_SELECT;
968
  /*
969
  * Restore Context states.
970
  */
971
0
  ctxt->contextVariable = oldVar;
972
973
0
  xpctxt->doc = oldXPDoc;
974
0
  xpctxt->node = oldXPContextNode;
975
0
  xpctxt->contextSize = oldXPContextSize;
976
0
  xpctxt->proximityPosition = oldXPProximityPosition;
977
0
  xpctxt->namespaces = oldXPNamespaces;
978
0
  xpctxt->nsNr = oldXPNsNr;
979
980
0
  if ((comp == NULL) || (comp->comp == NULL))
981
0
      xmlXPathFreeCompExpr(xpExpr);
982
0
  if (result == NULL) {
983
0
      xsltTransformError(ctxt, NULL,
984
0
    (comp != NULL) ? comp->inst : NULL,
985
0
    "Failed to evaluate the expression of variable '%s'.\n",
986
0
    variable->name);
987
0
      ctxt->state = XSLT_STATE_STOPPED;
988
989
#ifdef WITH_XSLT_DEBUG_VARIABLE
990
#ifdef LIBXML_DEBUG_ENABLED
991
  } else {
992
      if ((xsltGenericDebugContext == stdout) ||
993
    (xsltGenericDebugContext == stderr))
994
    xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
995
          result, 0);
996
#endif
997
#endif
998
0
  }
999
0
    } else {
1000
0
  if (variable->tree == NULL) {
1001
0
      result = xmlXPathNewCString("");
1002
0
  } else {
1003
0
      if (variable->tree) {
1004
0
    xmlDocPtr container;
1005
0
                xsltRVTListPtr rvtList;
1006
0
    xmlNodePtr oldInsert;
1007
0
    xmlDocPtr  oldOutput;
1008
0
                const xmlChar *oldLastText;
1009
0
                int oldLastTextSize, oldLastTextUse;
1010
0
    xsltStackElemPtr oldVar = ctxt->contextVariable;
1011
1012
    /*
1013
    * Generate a result tree fragment.
1014
    */
1015
0
    container = xsltCreateRVT(ctxt);
1016
0
    if (container == NULL)
1017
0
        goto error;
1018
    /*
1019
    * NOTE: Local Result Tree Fragments of params/variables
1020
    * are not registered globally anymore; the life-time
1021
    * is not directly dependant of the param/variable itself.
1022
    *
1023
    * OLD: xsltRegisterTmpRVT(ctxt, container);
1024
    */
1025
    /*
1026
    * Attach the Result Tree Fragment to the variable;
1027
    * when the variable is freed, it will also free
1028
    * the Result Tree Fragment.
1029
    */
1030
0
                rvtList = xsltRVTListCreate();
1031
0
                if (rvtList == NULL)
1032
0
                    goto error;
1033
0
                rvtList->RVT = container;
1034
0
    variable->fragment = rvtList;
1035
0
                container->compression = XSLT_RVT_LOCAL;
1036
1037
0
    oldOutput = ctxt->output;
1038
0
    oldInsert = ctxt->insert;
1039
0
                oldLastText = ctxt->lasttext;
1040
0
                oldLastTextSize = ctxt->lasttsize;
1041
0
                oldLastTextUse = ctxt->lasttuse;
1042
1043
0
    ctxt->output = container;
1044
0
    ctxt->insert = (xmlNodePtr) container;
1045
0
    ctxt->contextVariable = variable;
1046
    /*
1047
    * Process the sequence constructor (variable->tree).
1048
    * The resulting tree will be held by @container.
1049
    */
1050
0
    xsltApplyOneTemplate(ctxt, ctxt->node, variable->tree,
1051
0
        NULL, NULL);
1052
1053
0
    ctxt->contextVariable = oldVar;
1054
0
    ctxt->insert = oldInsert;
1055
0
    ctxt->output = oldOutput;
1056
0
                ctxt->lasttext = oldLastText;
1057
0
                ctxt->lasttsize = oldLastTextSize;
1058
0
                ctxt->lasttuse = oldLastTextUse;
1059
1060
0
    result = xmlXPathNewValueTree((xmlNodePtr) container);
1061
0
      }
1062
0
      if (result == NULL) {
1063
0
    result = xmlXPathNewCString("");
1064
0
      } else {
1065
                /*
1066
                 * This stops older libxml2 versions from freeing the nodes
1067
                 * in the tree.
1068
                 */
1069
0
          result->boolval = 0;
1070
0
      }
1071
#ifdef WITH_XSLT_DEBUG_VARIABLE
1072
#ifdef LIBXML_DEBUG_ENABLED
1073
1074
      if ((xsltGenericDebugContext == stdout) ||
1075
    (xsltGenericDebugContext == stderr))
1076
    xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
1077
          result, 0);
1078
#endif
1079
#endif
1080
0
  }
1081
0
    }
1082
1083
0
error:
1084
0
    ctxt->inst = oldInst;
1085
0
    return(result);
1086
0
}
1087
1088
/**
1089
 * xsltEvalGlobalVariable:
1090
 * @elem:  the variable or parameter
1091
 * @ctxt:  the XSLT transformation context
1092
 *
1093
 * Evaluates a the value of a global xsl:variable or
1094
 * xsl:param declaration.
1095
 *
1096
 * Returns the XPath Object value or NULL in case of error
1097
 */
1098
static xmlXPathObjectPtr
1099
xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt)
1100
0
{
1101
0
    xmlXPathObjectPtr result = NULL;
1102
0
    xmlNodePtr oldInst;
1103
0
    const xmlChar* oldVarName;
1104
0
    xsltStackElemPtr oldCtxtVar = ctxt->contextVariable;
1105
1106
#ifdef XSLT_REFACTORED
1107
    xsltStyleBasicItemVariablePtr comp;
1108
#else
1109
0
    xsltStylePreCompPtr comp;
1110
0
#endif
1111
1112
0
    if ((ctxt == NULL) || (elem == NULL))
1113
0
  return(NULL);
1114
0
    if (elem->computed)
1115
0
  return(elem->value);
1116
1117
1118
#ifdef WITH_XSLT_DEBUG_VARIABLE
1119
    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1120
  "Evaluating global variable %s\n", elem->name));
1121
#endif
1122
1123
#ifdef WITH_DEBUGGER
1124
    if ((ctxt->debugStatus != XSLT_DEBUG_NONE) &&
1125
        elem->comp && elem->comp->inst)
1126
        xslHandleDebugger(elem->comp->inst, NULL, NULL, ctxt);
1127
#endif
1128
1129
0
    oldInst = ctxt->inst;
1130
#ifdef XSLT_REFACTORED
1131
    comp = (xsltStyleBasicItemVariablePtr) elem->comp;
1132
#else
1133
0
    comp = elem->comp;
1134
0
#endif
1135
0
    oldVarName = elem->name;
1136
0
    elem->name = xsltComputingGlobalVarMarker;
1137
1138
    /*
1139
     * The "context variable" isn't used for globals, so we must
1140
     * make sure to set it to NULL.
1141
     */
1142
0
    oldCtxtVar = ctxt->contextVariable;
1143
0
    ctxt->contextVariable = NULL;
1144
1145
    /*
1146
    * OPTIMIZE TODO: We should consider instantiating global vars/params
1147
    *  on-demand. The vars/params don't need to be evaluated if never
1148
    *  called; and in the case of global params, if values for such params
1149
    *  are provided by the user.
1150
    */
1151
0
    if (elem->select != NULL) {
1152
0
  xmlXPathCompExprPtr xpExpr = NULL;
1153
0
  xmlDocPtr oldXPDoc;
1154
0
  xmlNodePtr oldXPContextNode;
1155
0
  int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
1156
0
  xmlNsPtr *oldXPNamespaces;
1157
0
  xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
1158
1159
0
  if ((comp != NULL) && (comp->comp != NULL)) {
1160
0
      xpExpr = comp->comp;
1161
0
  } else {
1162
0
      xpExpr = xmlXPathCtxtCompile(ctxt->xpathCtxt, elem->select);
1163
0
  }
1164
0
  if (xpExpr == NULL)
1165
0
      goto error;
1166
1167
1168
0
  if (comp != NULL)
1169
0
      ctxt->inst = comp->inst;
1170
0
  else
1171
0
      ctxt->inst = NULL;
1172
  /*
1173
  * SPEC XSLT 1.0:
1174
  * "At top-level, the expression or template specifying the
1175
  *  variable value is evaluated with the same context as that used
1176
  *  to process the root node of the source document: the current
1177
  *  node is the root node of the source document and the current
1178
  *  node list is a list containing just the root node of the source
1179
  *  document."
1180
  */
1181
  /*
1182
  * Save context states.
1183
  */
1184
0
  oldXPDoc = xpctxt->doc;
1185
0
  oldXPContextNode = xpctxt->node;
1186
0
  oldXPProximityPosition = xpctxt->proximityPosition;
1187
0
  oldXPContextSize = xpctxt->contextSize;
1188
0
  oldXPNamespaces = xpctxt->namespaces;
1189
0
  oldXPNsNr = xpctxt->nsNr;
1190
1191
0
  xpctxt->node = ctxt->initialContextNode;
1192
0
  xpctxt->doc = ctxt->initialContextDoc;
1193
0
  xpctxt->contextSize = 1;
1194
0
  xpctxt->proximityPosition = 1;
1195
1196
0
  if (comp != NULL) {
1197
1198
#ifdef XSLT_REFACTORED
1199
      if (comp->inScopeNs != NULL) {
1200
    xpctxt->namespaces = comp->inScopeNs->list;
1201
    xpctxt->nsNr = comp->inScopeNs->xpathNumber;
1202
      } else {
1203
    xpctxt->namespaces = NULL;
1204
    xpctxt->nsNr = 0;
1205
      }
1206
#else
1207
0
      xpctxt->namespaces = comp->nsList;
1208
0
      xpctxt->nsNr = comp->nsNr;
1209
0
#endif
1210
0
  } else {
1211
0
      xpctxt->namespaces = NULL;
1212
0
      xpctxt->nsNr = 0;
1213
0
  }
1214
1215
0
  result = xmlXPathCompiledEval(xpExpr, xpctxt);
1216
1217
  /*
1218
  * Restore Context states.
1219
  */
1220
0
  xpctxt->doc = oldXPDoc;
1221
0
  xpctxt->node = oldXPContextNode;
1222
0
  xpctxt->contextSize = oldXPContextSize;
1223
0
  xpctxt->proximityPosition = oldXPProximityPosition;
1224
0
  xpctxt->namespaces = oldXPNamespaces;
1225
0
  xpctxt->nsNr = oldXPNsNr;
1226
1227
0
  if ((comp == NULL) || (comp->comp == NULL))
1228
0
      xmlXPathFreeCompExpr(xpExpr);
1229
0
  if (result == NULL) {
1230
0
      if (comp == NULL)
1231
0
    xsltTransformError(ctxt, NULL, NULL,
1232
0
        "Evaluating global variable %s failed\n", elem->name);
1233
0
      else
1234
0
    xsltTransformError(ctxt, NULL, comp->inst,
1235
0
        "Evaluating global variable %s failed\n", elem->name);
1236
0
      ctxt->state = XSLT_STATE_STOPPED;
1237
0
            goto error;
1238
0
        }
1239
1240
        /*
1241
         * Mark all RVTs that are referenced from result as part
1242
         * of this variable so they won't be freed too early.
1243
         */
1244
0
        xsltFlagRVTs(ctxt, result, XSLT_RVT_GLOBAL);
1245
1246
#ifdef WITH_XSLT_DEBUG_VARIABLE
1247
#ifdef LIBXML_DEBUG_ENABLED
1248
  if ((xsltGenericDebugContext == stdout) ||
1249
      (xsltGenericDebugContext == stderr))
1250
      xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
1251
            result, 0);
1252
#endif
1253
#endif
1254
0
    } else {
1255
0
  if (elem->tree == NULL) {
1256
0
      result = xmlXPathNewCString("");
1257
0
  } else {
1258
0
      xmlDocPtr container;
1259
0
      xmlNodePtr oldInsert;
1260
0
      xmlDocPtr  oldOutput, oldXPDoc;
1261
      /*
1262
      * Generate a result tree fragment.
1263
      */
1264
0
      container = xsltCreateRVT(ctxt);
1265
0
      if (container == NULL)
1266
0
    goto error;
1267
      /*
1268
      * Let the lifetime of the tree fragment be handled by
1269
      * the Libxslt's garbage collector.
1270
      */
1271
0
      xsltRegisterPersistRVT(ctxt, container);
1272
1273
0
      oldOutput = ctxt->output;
1274
0
      oldInsert = ctxt->insert;
1275
1276
0
      oldXPDoc = ctxt->xpathCtxt->doc;
1277
1278
0
      ctxt->output = container;
1279
0
      ctxt->insert = (xmlNodePtr) container;
1280
1281
0
      ctxt->xpathCtxt->doc = ctxt->initialContextDoc;
1282
      /*
1283
      * Process the sequence constructor.
1284
      */
1285
0
      xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL);
1286
1287
0
      ctxt->xpathCtxt->doc = oldXPDoc;
1288
1289
0
      ctxt->insert = oldInsert;
1290
0
      ctxt->output = oldOutput;
1291
1292
0
      result = xmlXPathNewValueTree((xmlNodePtr) container);
1293
0
      if (result == NULL) {
1294
0
    result = xmlXPathNewCString("");
1295
0
      } else {
1296
                /*
1297
                 * This stops older libxml2 versions from freeing the nodes
1298
                 * in the tree.
1299
                 */
1300
0
          result->boolval = 0;
1301
0
      }
1302
#ifdef WITH_XSLT_DEBUG_VARIABLE
1303
#ifdef LIBXML_DEBUG_ENABLED
1304
      if ((xsltGenericDebugContext == stdout) ||
1305
    (xsltGenericDebugContext == stderr))
1306
    xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
1307
          result, 0);
1308
#endif
1309
#endif
1310
0
  }
1311
0
    }
1312
1313
0
error:
1314
0
    ctxt->contextVariable = oldCtxtVar;
1315
1316
0
    elem->name = oldVarName;
1317
0
    ctxt->inst = oldInst;
1318
0
    if (result != NULL) {
1319
0
  elem->value = result;
1320
0
  elem->computed = 1;
1321
0
    }
1322
0
    return(result);
1323
0
}
1324
1325
/**
1326
 * xsltEvalGlobalVariables:
1327
 * @ctxt:  the XSLT transformation context
1328
 *
1329
 * Evaluates all global variables and parameters of a stylesheet.
1330
 * For internal use only. This is called at start of a transformation.
1331
 *
1332
 * Returns 0 in case of success, -1 in case of error
1333
 */
1334
int
1335
0
xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
1336
0
    xsltStackElemPtr elem;
1337
0
    xsltStackElemPtr head = NULL;
1338
0
    xsltStylesheetPtr style;
1339
1340
0
    if ((ctxt == NULL) || (ctxt->document == NULL))
1341
0
  return(-1);
1342
1343
#ifdef WITH_XSLT_DEBUG_VARIABLE
1344
    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1345
  "Registering global variables\n"));
1346
#endif
1347
    /*
1348
     * Walk the list from the stylesheets and populate the hash table
1349
     */
1350
0
    style = ctxt->style;
1351
0
    while (style != NULL) {
1352
0
  elem = style->variables;
1353
1354
#ifdef WITH_XSLT_DEBUG_VARIABLE
1355
  if ((style->doc != NULL) && (style->doc->URL != NULL)) {
1356
      XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1357
           "Registering global variables from %s\n",
1358
                 style->doc->URL));
1359
  }
1360
#endif
1361
1362
0
  while (elem != NULL) {
1363
0
      xsltStackElemPtr def;
1364
1365
      /*
1366
       * Global variables are stored in the variables pool.
1367
       */
1368
0
      def = (xsltStackElemPtr)
1369
0
        xmlHashLookup2(ctxt->globalVars,
1370
0
                     elem->name, elem->nameURI);
1371
0
      if (def == NULL) {
1372
1373
0
    def = xsltCopyStackElem(elem);
1374
0
    if (xmlHashAddEntry2(ctxt->globalVars,
1375
0
             elem->name, elem->nameURI, def) < 0) {
1376
0
                    xmlGenericError(xmlGenericErrorContext,
1377
0
                                    "hash update failed\n");
1378
0
                    xsltFreeStackElem(def);
1379
0
                    return(-1);
1380
0
                }
1381
0
                def->next = head;
1382
0
                head = def;
1383
0
      } else if ((elem->comp != NULL) &&
1384
0
           (elem->comp->type == XSLT_FUNC_VARIABLE)) {
1385
    /*
1386
     * Redefinition of variables from a different stylesheet
1387
     * should not generate a message.
1388
     */
1389
0
    if ((elem->comp->inst != NULL) &&
1390
0
        (def->comp != NULL) && (def->comp->inst != NULL) &&
1391
0
        (elem->comp->inst->doc == def->comp->inst->doc))
1392
0
    {
1393
0
        xsltTransformError(ctxt, style, elem->comp->inst,
1394
0
      "Global variable %s already defined\n", elem->name);
1395
0
        if (style != NULL) style->errors++;
1396
0
    }
1397
0
      }
1398
0
      elem = elem->next;
1399
0
  }
1400
1401
0
  style = xsltNextImport(style);
1402
0
    }
1403
1404
    /*
1405
     * This part does the actual evaluation. Note that scanning the hash
1406
     * table would result in a non-deterministic order, leading to
1407
     * non-deterministic generated IDs.
1408
     */
1409
0
    elem = head;
1410
0
    while (elem != NULL) {
1411
0
        xsltStackElemPtr next;
1412
1413
0
        xsltEvalGlobalVariable(elem, ctxt);
1414
0
        next = elem->next;
1415
0
        elem->next = NULL;
1416
0
        elem = next;
1417
0
    }
1418
1419
0
    return(0);
1420
0
}
1421
1422
/**
1423
 * xsltRegisterGlobalVariable:
1424
 * @style:  the XSLT transformation context
1425
 * @name:  the variable name
1426
 * @ns_uri:  the variable namespace URI
1427
 * @sel:  the expression which need to be evaluated to generate a value
1428
 * @tree:  the subtree if sel is NULL
1429
 * @comp:  the precompiled value
1430
 * @value:  the string value if available
1431
 *
1432
 * Register a new variable value. If @value is NULL it unregisters
1433
 * the variable
1434
 *
1435
 * Returns 0 in case of success, -1 in case of error
1436
 */
1437
static int
1438
xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name,
1439
         const xmlChar *ns_uri, const xmlChar *sel,
1440
         xmlNodePtr tree, xsltStylePreCompPtr comp,
1441
0
         const xmlChar *value) {
1442
0
    xsltStackElemPtr elem, tmp;
1443
0
    if (style == NULL)
1444
0
  return(-1);
1445
0
    if (name == NULL)
1446
0
  return(-1);
1447
0
    if (comp == NULL)
1448
0
  return(-1);
1449
1450
#ifdef WITH_XSLT_DEBUG_VARIABLE
1451
    if (comp->type == XSLT_FUNC_PARAM)
1452
  xsltGenericDebug(xsltGenericDebugContext,
1453
       "Defining global param %s\n", name);
1454
    else
1455
  xsltGenericDebug(xsltGenericDebugContext,
1456
       "Defining global variable %s\n", name);
1457
#endif
1458
1459
0
    elem = xsltNewStackElem(NULL);
1460
0
    if (elem == NULL)
1461
0
  return(-1);
1462
0
    elem->comp = comp;
1463
0
    elem->name = xmlDictLookup(style->dict, name, -1);
1464
0
    elem->select = xmlDictLookup(style->dict, sel, -1);
1465
0
    if (ns_uri)
1466
0
  elem->nameURI = xmlDictLookup(style->dict, ns_uri, -1);
1467
0
    elem->tree = tree;
1468
0
    tmp = style->variables;
1469
0
    while (tmp != NULL) {
1470
0
        if ((elem->comp->type == XSLT_FUNC_VARIABLE) &&
1471
0
            (tmp->comp->type == XSLT_FUNC_VARIABLE) &&
1472
0
            (xmlStrEqual(elem->name, tmp->name)) &&
1473
0
            ((elem->nameURI == tmp->nameURI) ||
1474
0
             (xmlStrEqual(elem->nameURI, tmp->nameURI))))
1475
0
        {
1476
0
            xsltTransformError(NULL, style, comp->inst,
1477
0
            "redefinition of global variable %s\n", elem->name);
1478
0
            style->errors++;
1479
0
        }
1480
0
        tmp = tmp->next;
1481
0
    }
1482
0
    elem->next = style->variables;;
1483
0
    style->variables = elem;
1484
0
    if (value != NULL) {
1485
0
  elem->computed = 1;
1486
0
  elem->value = xmlXPathNewString(value);
1487
0
    }
1488
0
    return(0);
1489
0
}
1490
1491
/**
1492
 * xsltProcessUserParamInternal
1493
 *
1494
 * @ctxt:  the XSLT transformation context
1495
 * @name:  a null terminated parameter name
1496
 * @value: a null terminated value (may be an XPath expression)
1497
 * @eval:  0 to treat the value literally, else evaluate as XPath expression
1498
 *
1499
 * If @eval is 0 then @value is treated literally and is stored in the global
1500
 * parameter/variable table without any change.
1501
 *
1502
 * Uf @eval is 1 then @value is treated as an XPath expression and is
1503
 * evaluated.  In this case, if you want to pass a string which will be
1504
 * interpreted literally then it must be enclosed in single or double quotes.
1505
 * If the string contains single quotes (double quotes) then it cannot be
1506
 * enclosed single quotes (double quotes).  If the string which you want to
1507
 * be treated literally contains both single and double quotes (e.g. Meet
1508
 * at Joe's for "Twelfth Night" at 7 o'clock) then there is no suitable
1509
 * quoting character.  You cannot use &apos; or &quot; inside the string
1510
 * because the replacement of character entities with their equivalents is
1511
 * done at a different stage of processing.  The solution is to call
1512
 * xsltQuoteUserParams or xsltQuoteOneUserParam.
1513
 *
1514
 * This needs to be done on parsed stylesheets before starting to apply
1515
 * transformations.  Normally this will be called (directly or indirectly)
1516
 * only from xsltEvalUserParams, xsltEvalOneUserParam, xsltQuoteUserParams,
1517
 * or xsltQuoteOneUserParam.
1518
 *
1519
 * Returns 0 in case of success, -1 in case of error
1520
 */
1521
1522
static
1523
int
1524
xsltProcessUserParamInternal(xsltTransformContextPtr ctxt,
1525
                 const xmlChar * name,
1526
           const xmlChar * value,
1527
0
           int eval) {
1528
1529
0
    xsltStylesheetPtr style;
1530
0
    const xmlChar *prefix;
1531
0
    const xmlChar *href;
1532
0
    xmlXPathCompExprPtr xpExpr;
1533
0
    xmlXPathObjectPtr result;
1534
1535
0
    xsltStackElemPtr elem;
1536
0
    int res;
1537
0
    void *res_ptr;
1538
1539
0
    if (ctxt == NULL)
1540
0
  return(-1);
1541
0
    if (name == NULL)
1542
0
  return(0);
1543
0
    if (value == NULL)
1544
0
  return(0);
1545
1546
0
    style = ctxt->style;
1547
1548
#ifdef WITH_XSLT_DEBUG_VARIABLE
1549
    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1550
      "Evaluating user parameter %s=%s\n", name, value));
1551
#endif
1552
1553
    /*
1554
     * Name lookup
1555
     */
1556
0
    href = NULL;
1557
1558
0
    if (name[0] == '{') {
1559
0
        int len = 0;
1560
1561
0
        while ((name[len] != 0) && (name[len] != '}')) len++;
1562
0
        if (name[len] == 0) {
1563
0
           xsltTransformError(ctxt, style, NULL,
1564
0
           "user param : malformed parameter name : %s\n", name);
1565
0
        } else {
1566
0
           href = xmlDictLookup(ctxt->dict, &name[1], len-1);
1567
0
           name = xmlDictLookup(ctxt->dict, &name[len + 1], -1);
1568
0
       }
1569
0
    }
1570
0
    else {
1571
0
        name = xsltSplitQName(ctxt->dict, name, &prefix);
1572
0
        if (prefix != NULL) {
1573
0
            xmlNsPtr ns;
1574
1575
0
            ns = xmlSearchNs(style->doc, xmlDocGetRootElement(style->doc),
1576
0
                             prefix);
1577
0
            if (ns == NULL) {
1578
0
                xsltTransformError(ctxt, style, NULL,
1579
0
                "user param : no namespace bound to prefix %s\n", prefix);
1580
0
                href = NULL;
1581
0
            } else {
1582
0
                href = ns->href;
1583
0
            }
1584
0
        }
1585
0
    }
1586
1587
0
    if (name == NULL)
1588
0
  return (-1);
1589
1590
0
    res_ptr = xmlHashLookup2(ctxt->globalVars, name, href);
1591
0
    if (res_ptr != 0) {
1592
0
  xsltTransformError(ctxt, style, NULL,
1593
0
      "Global parameter %s already defined\n", name);
1594
0
    }
1595
0
    if (ctxt->globalVars == NULL)
1596
0
  ctxt->globalVars = xmlHashCreate(20);
1597
1598
    /*
1599
     * do not overwrite variables with parameters from the command line
1600
     */
1601
0
    while (style != NULL) {
1602
0
        elem = ctxt->style->variables;
1603
0
  while (elem != NULL) {
1604
0
      if ((elem->comp != NULL) &&
1605
0
          (elem->comp->type == XSLT_FUNC_VARIABLE) &&
1606
0
    (xmlStrEqual(elem->name, name)) &&
1607
0
    (xmlStrEqual(elem->nameURI, href))) {
1608
0
    return(0);
1609
0
      }
1610
0
            elem = elem->next;
1611
0
  }
1612
0
        style = xsltNextImport(style);
1613
0
    }
1614
0
    style = ctxt->style;
1615
0
    elem = NULL;
1616
1617
    /*
1618
     * Do the evaluation if @eval is non-zero.
1619
     */
1620
1621
0
    result = NULL;
1622
0
    if (eval != 0) {
1623
0
        xpExpr = xmlXPathCtxtCompile(ctxt->xpathCtxt, value);
1624
0
  if (xpExpr != NULL) {
1625
0
      xmlDocPtr oldXPDoc;
1626
0
      xmlNodePtr oldXPContextNode;
1627
0
      int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
1628
0
      xmlNsPtr *oldXPNamespaces;
1629
0
      xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
1630
1631
      /*
1632
      * Save context states.
1633
      */
1634
0
      oldXPDoc = xpctxt->doc;
1635
0
      oldXPContextNode = xpctxt->node;
1636
0
      oldXPProximityPosition = xpctxt->proximityPosition;
1637
0
      oldXPContextSize = xpctxt->contextSize;
1638
0
      oldXPNamespaces = xpctxt->namespaces;
1639
0
      oldXPNsNr = xpctxt->nsNr;
1640
1641
      /*
1642
      * SPEC XSLT 1.0:
1643
      * "At top-level, the expression or template specifying the
1644
      *  variable value is evaluated with the same context as that used
1645
      *  to process the root node of the source document: the current
1646
      *  node is the root node of the source document and the current
1647
      *  node list is a list containing just the root node of the source
1648
      *  document."
1649
      */
1650
0
      xpctxt->doc = ctxt->initialContextDoc;
1651
0
      xpctxt->node = ctxt->initialContextNode;
1652
0
      xpctxt->contextSize = 1;
1653
0
      xpctxt->proximityPosition = 1;
1654
      /*
1655
      * There is really no in scope namespace for parameters on the
1656
      * command line.
1657
      */
1658
0
      xpctxt->namespaces = NULL;
1659
0
      xpctxt->nsNr = 0;
1660
1661
0
      result = xmlXPathCompiledEval(xpExpr, xpctxt);
1662
1663
      /*
1664
      * Restore Context states.
1665
      */
1666
0
      xpctxt->doc = oldXPDoc;
1667
0
      xpctxt->node = oldXPContextNode;
1668
0
      xpctxt->contextSize = oldXPContextSize;
1669
0
      xpctxt->proximityPosition = oldXPProximityPosition;
1670
0
      xpctxt->namespaces = oldXPNamespaces;
1671
0
      xpctxt->nsNr = oldXPNsNr;
1672
1673
0
      xmlXPathFreeCompExpr(xpExpr);
1674
0
  }
1675
0
  if (result == NULL) {
1676
0
      xsltTransformError(ctxt, style, NULL,
1677
0
    "Evaluating user parameter %s failed\n", name);
1678
0
      ctxt->state = XSLT_STATE_STOPPED;
1679
0
      return(-1);
1680
0
  }
1681
0
    }
1682
1683
    /*
1684
     * If @eval is 0 then @value is to be taken literally and result is NULL
1685
     *
1686
     * If @eval is not 0, then @value is an XPath expression and has been
1687
     * successfully evaluated and result contains the resulting value and
1688
     * is not NULL.
1689
     *
1690
     * Now create an xsltStackElemPtr for insertion into the context's
1691
     * global variable/parameter hash table.
1692
     */
1693
1694
#ifdef WITH_XSLT_DEBUG_VARIABLE
1695
#ifdef LIBXML_DEBUG_ENABLED
1696
    if ((xsltGenericDebugContext == stdout) ||
1697
        (xsltGenericDebugContext == stderr))
1698
      xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
1699
            result, 0);
1700
#endif
1701
#endif
1702
1703
0
    elem = xsltNewStackElem(NULL);
1704
0
    if (elem != NULL) {
1705
0
  elem->name = name;
1706
0
  elem->select = xmlDictLookup(ctxt->dict, value, -1);
1707
0
  if (href != NULL)
1708
0
      elem->nameURI = xmlDictLookup(ctxt->dict, href, -1);
1709
0
  elem->tree = NULL;
1710
0
  elem->computed = 1;
1711
0
  if (eval == 0) {
1712
0
      elem->value = xmlXPathNewString(value);
1713
0
  }
1714
0
  else {
1715
0
      elem->value = result;
1716
0
  }
1717
0
    }
1718
1719
    /*
1720
     * Global parameters are stored in the XPath context variables pool.
1721
     */
1722
1723
0
    res = xmlHashAddEntry2(ctxt->globalVars, name, href, elem);
1724
0
    if (res != 0) {
1725
0
  xsltFreeStackElem(elem);
1726
0
  xsltTransformError(ctxt, style, NULL,
1727
0
      "Global parameter %s already defined\n", name);
1728
0
    }
1729
0
    return(0);
1730
0
}
1731
1732
/**
1733
 * xsltEvalUserParams:
1734
 *
1735
 * @ctxt:  the XSLT transformation context
1736
 * @params:  a NULL terminated array of parameters name/value tuples
1737
 *
1738
 * Evaluate the global variables of a stylesheet. This needs to be
1739
 * done on parsed stylesheets before starting to apply transformations.
1740
 * Each of the parameters is evaluated as an XPath expression and stored
1741
 * in the global variables/parameter hash table.  If you want your
1742
 * parameter used literally, use xsltQuoteUserParams.
1743
 *
1744
 * Returns 0 in case of success, -1 in case of error
1745
 */
1746
1747
int
1748
0
xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) {
1749
0
    size_t indx = 0;
1750
0
    const xmlChar *name;
1751
0
    const xmlChar *value;
1752
1753
0
    if (params == NULL)
1754
0
  return(0);
1755
0
    while (params[indx] != NULL) {
1756
0
  name = (const xmlChar *) params[indx++];
1757
0
  value = (const xmlChar *) params[indx++];
1758
0
  if (xsltEvalOneUserParam(ctxt, name, value) != 0)
1759
0
      return(-1);
1760
0
    }
1761
0
    return 0;
1762
0
}
1763
1764
/**
1765
 * xsltQuoteUserParams:
1766
 *
1767
 * @ctxt:  the XSLT transformation context
1768
 * @params:  a NULL terminated arry of parameters names/values tuples
1769
 *
1770
 * Similar to xsltEvalUserParams, but the values are treated literally and
1771
 * are * *not* evaluated as XPath expressions. This should be done on parsed
1772
 * stylesheets before starting to apply transformations.
1773
 *
1774
 * Returns 0 in case of success, -1 in case of error.
1775
 */
1776
1777
int
1778
0
xsltQuoteUserParams(xsltTransformContextPtr ctxt, const char **params) {
1779
0
    size_t indx = 0;
1780
0
    const xmlChar *name;
1781
0
    const xmlChar *value;
1782
1783
0
    if (params == NULL)
1784
0
  return(0);
1785
0
    while (params[indx] != NULL) {
1786
0
  name = (const xmlChar *) params[indx++];
1787
0
  value = (const xmlChar *) params[indx++];
1788
0
  if (xsltQuoteOneUserParam(ctxt, name, value) != 0)
1789
0
      return(-1);
1790
0
    }
1791
0
    return 0;
1792
0
}
1793
1794
/**
1795
 * xsltEvalOneUserParam:
1796
 * @ctxt:  the XSLT transformation context
1797
 * @name:  a null terminated string giving the name of the parameter
1798
 * @value:  a null terminated string giving the XPath expression to be evaluated
1799
 *
1800
 * This is normally called from xsltEvalUserParams to process a single
1801
 * parameter from a list of parameters.  The @value is evaluated as an
1802
 * XPath expression and the result is stored in the context's global
1803
 * variable/parameter hash table.
1804
 *
1805
 * To have a parameter treated literally (not as an XPath expression)
1806
 * use xsltQuoteUserParams (or xsltQuoteOneUserParam).  For more
1807
 * details see description of xsltProcessOneUserParamInternal.
1808
 *
1809
 * Returns 0 in case of success, -1 in case of error.
1810
 */
1811
1812
int
1813
xsltEvalOneUserParam(xsltTransformContextPtr ctxt,
1814
         const xmlChar * name,
1815
0
         const xmlChar * value) {
1816
0
    return xsltProcessUserParamInternal(ctxt, name, value,
1817
0
                            1 /* xpath eval ? */);
1818
0
}
1819
1820
/**
1821
 * xsltQuoteOneUserParam:
1822
 * @ctxt:  the XSLT transformation context
1823
 * @name:  a null terminated string giving the name of the parameter
1824
 * @value:  a null terminated string giving the parameter value
1825
 *
1826
 * This is normally called from xsltQuoteUserParams to process a single
1827
 * parameter from a list of parameters.  The @value is stored in the
1828
 * context's global variable/parameter hash table.
1829
 *
1830
 * Returns 0 in case of success, -1 in case of error.
1831
 */
1832
1833
int
1834
xsltQuoteOneUserParam(xsltTransformContextPtr ctxt,
1835
       const xmlChar * name,
1836
0
       const xmlChar * value) {
1837
0
    return xsltProcessUserParamInternal(ctxt, name, value,
1838
0
          0 /* xpath eval ? */);
1839
0
}
1840
1841
/**
1842
 * xsltBuildVariable:
1843
 * @ctxt:  the XSLT transformation context
1844
 * @comp:  the precompiled form
1845
 * @tree:  the tree if select is NULL
1846
 *
1847
 * Computes a new variable value.
1848
 *
1849
 * Returns the xsltStackElemPtr or NULL in case of error
1850
 */
1851
static xsltStackElemPtr
1852
xsltBuildVariable(xsltTransformContextPtr ctxt,
1853
      xsltStylePreCompPtr castedComp,
1854
      xmlNodePtr tree)
1855
0
{
1856
#ifdef XSLT_REFACTORED
1857
    xsltStyleBasicItemVariablePtr comp =
1858
  (xsltStyleBasicItemVariablePtr) castedComp;
1859
#else
1860
0
    xsltStylePreCompPtr comp = castedComp;
1861
0
#endif
1862
0
    xsltStackElemPtr elem;
1863
1864
#ifdef WITH_XSLT_DEBUG_VARIABLE
1865
    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1866
         "Building variable %s", comp->name));
1867
    if (comp->select != NULL)
1868
  XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1869
       " select %s", comp->select));
1870
    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, "\n"));
1871
#endif
1872
1873
0
    elem = xsltNewStackElem(ctxt);
1874
0
    if (elem == NULL)
1875
0
  return(NULL);
1876
0
    elem->comp = (xsltStylePreCompPtr) comp;
1877
0
    elem->name = comp->name;
1878
0
    elem->select = comp->select;
1879
0
    elem->nameURI = comp->ns;
1880
0
    elem->tree = tree;
1881
0
    elem->value = xsltEvalVariable(ctxt, elem,
1882
0
  (xsltStylePreCompPtr) comp);
1883
0
    elem->computed = 1;
1884
0
    return(elem);
1885
0
}
1886
1887
/**
1888
 * xsltRegisterVariable:
1889
 * @ctxt:  the XSLT transformation context
1890
 * @comp: the compiled XSLT-variable (or param) instruction
1891
 * @tree:  the tree if select is NULL
1892
 * @isParam:  indicates if this is a parameter
1893
 *
1894
 * Computes and registers a new variable.
1895
 *
1896
 * Returns 0 in case of success, -1 in case of error
1897
 */
1898
static int
1899
xsltRegisterVariable(xsltTransformContextPtr ctxt,
1900
         xsltStylePreCompPtr castedComp,
1901
         xmlNodePtr tree, int isParam)
1902
0
{
1903
#ifdef XSLT_REFACTORED
1904
    xsltStyleBasicItemVariablePtr comp =
1905
  (xsltStyleBasicItemVariablePtr) castedComp;
1906
#else
1907
0
    xsltStylePreCompPtr comp = castedComp;
1908
0
    int present;
1909
0
#endif
1910
0
    xsltStackElemPtr variable;
1911
1912
#ifdef XSLT_REFACTORED
1913
    /*
1914
    * REFACTORED NOTE: Redefinitions of vars/params are checked
1915
    *  at compilation time in the refactored code.
1916
    * xsl:with-param parameters are checked in xsltApplyXSLTTemplate().
1917
    */
1918
#else
1919
0
    present = xsltCheckStackElem(ctxt, comp->name, comp->ns);
1920
0
    if (isParam == 0) {
1921
0
  if ((present != 0) && (present != 3)) {
1922
      /* TODO: report QName. */
1923
0
      xsltTransformError(ctxt, NULL, comp->inst,
1924
0
    "XSLT-variable: Redefinition of variable '%s'.\n", comp->name);
1925
0
      return(0);
1926
0
  }
1927
0
    } else if (present != 0) {
1928
0
  if ((present == 1) || (present == 2)) {
1929
      /* TODO: report QName. */
1930
0
      xsltTransformError(ctxt, NULL, comp->inst,
1931
0
    "XSLT-param: Redefinition of parameter '%s'.\n", comp->name);
1932
0
      return(0);
1933
0
  }
1934
#ifdef WITH_XSLT_DEBUG_VARIABLE
1935
  XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1936
     "param %s defined by caller\n", comp->name));
1937
#endif
1938
0
  return(0);
1939
0
    }
1940
0
#endif /* else of XSLT_REFACTORED */
1941
1942
0
    variable = xsltBuildVariable(ctxt, (xsltStylePreCompPtr) comp, tree);
1943
0
    if (xsltAddStackElem(ctxt, variable) < 0) {
1944
0
        xsltFreeStackElem(variable);
1945
0
        return(-1);
1946
0
    }
1947
0
    return(0);
1948
0
}
1949
1950
/**
1951
 * xsltGlobalVariableLookup:
1952
 * @ctxt:  the XSLT transformation context
1953
 * @name:  the variable name
1954
 * @ns_uri:  the variable namespace URI
1955
 *
1956
 * Search in the Variable array of the context for the given
1957
 * variable value.
1958
 *
1959
 * Returns the value or NULL if not found
1960
 */
1961
static xmlXPathObjectPtr
1962
xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
1963
0
             const xmlChar *ns_uri) {
1964
0
    xsltStackElemPtr elem;
1965
0
    xmlXPathObjectPtr ret = NULL;
1966
1967
    /*
1968
     * Lookup the global variables in XPath global variable hash table
1969
     */
1970
0
    if ((ctxt->xpathCtxt == NULL) || (ctxt->globalVars == NULL))
1971
0
  return(NULL);
1972
0
    elem = (xsltStackElemPtr)
1973
0
      xmlHashLookup2(ctxt->globalVars, name, ns_uri);
1974
0
    if (elem == NULL) {
1975
#ifdef WITH_XSLT_DEBUG_VARIABLE
1976
  XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1977
       "global variable not found %s\n", name));
1978
#endif
1979
0
  return(NULL);
1980
0
    }
1981
    /*
1982
    * URGENT TODO: Move the detection of recursive definitions
1983
    * to compile-time.
1984
    */
1985
0
    if (elem->computed == 0) {
1986
0
  if (elem->name == xsltComputingGlobalVarMarker) {
1987
0
      xsltTransformError(ctxt, NULL, elem->comp->inst,
1988
0
    "Recursive definition of %s\n", name);
1989
0
      return(NULL);
1990
0
  }
1991
0
  ret = xsltEvalGlobalVariable(elem, ctxt);
1992
0
    } else
1993
0
  ret = elem->value;
1994
0
    return(xmlXPathObjectCopy(ret));
1995
0
}
1996
1997
/**
1998
 * xsltVariableLookup:
1999
 * @ctxt:  the XSLT transformation context
2000
 * @name:  the variable name
2001
 * @ns_uri:  the variable namespace URI
2002
 *
2003
 * Search in the Variable array of the context for the given
2004
 * variable value.
2005
 *
2006
 * Returns the value or NULL if not found
2007
 */
2008
xmlXPathObjectPtr
2009
xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
2010
0
       const xmlChar *ns_uri) {
2011
0
    xsltStackElemPtr elem;
2012
2013
0
    if (ctxt == NULL)
2014
0
  return(NULL);
2015
2016
0
    elem = xsltStackLookup(ctxt, name, ns_uri);
2017
0
    if (elem == NULL) {
2018
0
  return(xsltGlobalVariableLookup(ctxt, name, ns_uri));
2019
0
    }
2020
0
    if (elem->computed == 0) {
2021
#ifdef WITH_XSLT_DEBUG_VARIABLE
2022
  XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2023
             "uncomputed variable %s\n", name));
2024
#endif
2025
0
        elem->value = xsltEvalVariable(ctxt, elem, NULL);
2026
0
  elem->computed = 1;
2027
0
    }
2028
0
    if (elem->value != NULL)
2029
0
  return(xmlXPathObjectCopy(elem->value));
2030
#ifdef WITH_XSLT_DEBUG_VARIABLE
2031
    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2032
         "variable not found %s\n", name));
2033
#endif
2034
0
    return(NULL);
2035
0
}
2036
2037
/**
2038
 * xsltParseStylesheetCallerParam:
2039
 * @ctxt:  the XSLT transformation context
2040
 * @inst:  the xsl:with-param instruction element
2041
 *
2042
 * Processes an xsl:with-param instruction at transformation time.
2043
 * The value is computed, but not recorded.
2044
 * NOTE that this is also called with an *xsl:param* element
2045
 * from exsltFuncFunctionFunction().
2046
 *
2047
 * Returns the new xsltStackElemPtr or NULL
2048
 */
2049
2050
xsltStackElemPtr
2051
xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr inst)
2052
0
{
2053
#ifdef XSLT_REFACTORED
2054
    xsltStyleBasicItemVariablePtr comp;
2055
#else
2056
0
    xsltStylePreCompPtr comp;
2057
0
#endif
2058
0
    xmlNodePtr tree = NULL; /* The first child node of the instruction or
2059
                               the instruction itself. */
2060
0
    xsltStackElemPtr param = NULL;
2061
2062
0
    if ((ctxt == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
2063
0
  return(NULL);
2064
2065
#ifdef XSLT_REFACTORED
2066
    comp = (xsltStyleBasicItemVariablePtr) inst->psvi;
2067
#else
2068
0
    comp = (xsltStylePreCompPtr) inst->psvi;
2069
0
#endif
2070
2071
0
    if (comp == NULL) {
2072
0
        xsltTransformError(ctxt, NULL, inst,
2073
0
      "Internal error in xsltParseStylesheetCallerParam(): "
2074
0
      "The XSLT 'with-param' instruction was not compiled.\n");
2075
0
        return(NULL);
2076
0
    }
2077
0
    if (comp->name == NULL) {
2078
0
  xsltTransformError(ctxt, NULL, inst,
2079
0
      "Internal error in xsltParseStylesheetCallerParam(): "
2080
0
      "XSLT 'with-param': The attribute 'name' was not compiled.\n");
2081
0
  return(NULL);
2082
0
    }
2083
2084
#ifdef WITH_XSLT_DEBUG_VARIABLE
2085
    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2086
      "Handling xsl:with-param %s\n", comp->name));
2087
#endif
2088
2089
0
    if (comp->select == NULL) {
2090
0
  tree = inst->children;
2091
0
    } else {
2092
#ifdef WITH_XSLT_DEBUG_VARIABLE
2093
  XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2094
      "        select %s\n", comp->select));
2095
#endif
2096
0
  tree = inst;
2097
0
    }
2098
2099
0
    param = xsltBuildVariable(ctxt, (xsltStylePreCompPtr) comp, tree);
2100
2101
0
    return(param);
2102
0
}
2103
2104
/**
2105
 * xsltParseGlobalVariable:
2106
 * @style:  the XSLT stylesheet
2107
 * @cur:  the "variable" element
2108
 *
2109
 * Parses a global XSLT 'variable' declaration at compilation time
2110
 * and registers it
2111
 */
2112
void
2113
xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur)
2114
0
{
2115
#ifdef XSLT_REFACTORED
2116
    xsltStyleItemVariablePtr comp;
2117
#else
2118
0
    xsltStylePreCompPtr comp;
2119
0
#endif
2120
2121
0
    if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
2122
0
  return;
2123
2124
#ifdef XSLT_REFACTORED
2125
    /*
2126
    * Note that xsltStylePreCompute() will be called from
2127
    * xslt.c only.
2128
    */
2129
    comp = (xsltStyleItemVariablePtr) cur->psvi;
2130
#else
2131
0
    xsltStylePreCompute(style, cur);
2132
0
    comp = (xsltStylePreCompPtr) cur->psvi;
2133
0
#endif
2134
0
    if (comp == NULL) {
2135
0
  xsltTransformError(NULL, style, cur,
2136
0
       "xsl:variable : compilation failed\n");
2137
0
  return;
2138
0
    }
2139
2140
0
    if (comp->name == NULL) {
2141
0
  xsltTransformError(NULL, style, cur,
2142
0
      "xsl:variable : missing name attribute\n");
2143
0
  return;
2144
0
    }
2145
2146
    /*
2147
    * Parse the content (a sequence constructor) of xsl:variable.
2148
    */
2149
0
    if (cur->children != NULL) {
2150
#ifdef XSLT_REFACTORED
2151
        xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children);
2152
#else
2153
0
        xsltParseTemplateContent(style, cur);
2154
0
#endif
2155
0
    }
2156
#ifdef WITH_XSLT_DEBUG_VARIABLE
2157
    xsltGenericDebug(xsltGenericDebugContext,
2158
  "Registering global variable %s\n", comp->name);
2159
#endif
2160
2161
0
    xsltRegisterGlobalVariable(style, comp->name, comp->ns,
2162
0
  comp->select, cur->children, (xsltStylePreCompPtr) comp,
2163
0
  NULL);
2164
0
}
2165
2166
/**
2167
 * xsltParseGlobalParam:
2168
 * @style:  the XSLT stylesheet
2169
 * @cur:  the "param" element
2170
 *
2171
 * parse an XSLT transformation param declaration and record
2172
 * its value.
2173
 */
2174
2175
void
2176
0
xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) {
2177
#ifdef XSLT_REFACTORED
2178
    xsltStyleItemParamPtr comp;
2179
#else
2180
0
    xsltStylePreCompPtr comp;
2181
0
#endif
2182
2183
0
    if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
2184
0
  return;
2185
2186
#ifdef XSLT_REFACTORED
2187
    /*
2188
    * Note that xsltStylePreCompute() will be called from
2189
    * xslt.c only.
2190
    */
2191
    comp = (xsltStyleItemParamPtr) cur->psvi;
2192
#else
2193
0
    xsltStylePreCompute(style, cur);
2194
0
    comp = (xsltStylePreCompPtr) cur->psvi;
2195
0
#endif
2196
0
    if (comp == NULL) {
2197
0
  xsltTransformError(NULL, style, cur,
2198
0
       "xsl:param : compilation failed\n");
2199
0
  return;
2200
0
    }
2201
2202
0
    if (comp->name == NULL) {
2203
0
  xsltTransformError(NULL, style, cur,
2204
0
      "xsl:param : missing name attribute\n");
2205
0
  return;
2206
0
    }
2207
2208
    /*
2209
    * Parse the content (a sequence constructor) of xsl:param.
2210
    */
2211
0
    if (cur->children != NULL) {
2212
#ifdef XSLT_REFACTORED
2213
        xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children);
2214
#else
2215
0
        xsltParseTemplateContent(style, cur);
2216
0
#endif
2217
0
    }
2218
2219
#ifdef WITH_XSLT_DEBUG_VARIABLE
2220
    xsltGenericDebug(xsltGenericDebugContext,
2221
  "Registering global param %s\n", comp->name);
2222
#endif
2223
2224
0
    xsltRegisterGlobalVariable(style, comp->name, comp->ns,
2225
0
  comp->select, cur->children, (xsltStylePreCompPtr) comp,
2226
0
  NULL);
2227
0
}
2228
2229
/**
2230
 * xsltParseStylesheetVariable:
2231
 * @ctxt:  the XSLT transformation context
2232
 * @inst:  the xsl:variable instruction element
2233
 *
2234
 * Registers a local XSLT 'variable' instruction at transformation time
2235
 * and evaluates its value.
2236
 */
2237
void
2238
xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr inst)
2239
0
{
2240
#ifdef XSLT_REFACTORED
2241
    xsltStyleItemVariablePtr comp;
2242
#else
2243
0
    xsltStylePreCompPtr comp;
2244
0
#endif
2245
2246
0
    if ((inst == NULL) || (ctxt == NULL) || (inst->type != XML_ELEMENT_NODE))
2247
0
  return;
2248
2249
0
    comp = inst->psvi;
2250
0
    if (comp == NULL) {
2251
0
        xsltTransformError(ctxt, NULL, inst,
2252
0
      "Internal error in xsltParseStylesheetVariable(): "
2253
0
      "The XSLT 'variable' instruction was not compiled.\n");
2254
0
        return;
2255
0
    }
2256
0
    if (comp->name == NULL) {
2257
0
  xsltTransformError(ctxt, NULL, inst,
2258
0
      "Internal error in xsltParseStylesheetVariable(): "
2259
0
      "The attribute 'name' was not compiled.\n");
2260
0
  return;
2261
0
    }
2262
2263
#ifdef WITH_XSLT_DEBUG_VARIABLE
2264
    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2265
  "Registering variable '%s'\n", comp->name));
2266
#endif
2267
2268
0
    xsltRegisterVariable(ctxt, (xsltStylePreCompPtr) comp, inst->children, 0);
2269
0
}
2270
2271
/**
2272
 * xsltParseStylesheetParam:
2273
 * @ctxt:  the XSLT transformation context
2274
 * @cur:  the XSLT 'param' element
2275
 *
2276
 * Registers a local XSLT 'param' declaration at transformation time and
2277
 * evaluates its value.
2278
 */
2279
void
2280
xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur)
2281
0
{
2282
#ifdef XSLT_REFACTORED
2283
    xsltStyleItemParamPtr comp;
2284
#else
2285
0
    xsltStylePreCompPtr comp;
2286
0
#endif
2287
2288
0
    if ((cur == NULL) || (ctxt == NULL) || (cur->type != XML_ELEMENT_NODE))
2289
0
  return;
2290
2291
0
    comp = cur->psvi;
2292
0
    if ((comp == NULL) || (comp->name == NULL)) {
2293
0
  xsltTransformError(ctxt, NULL, cur,
2294
0
      "Internal error in xsltParseStylesheetParam(): "
2295
0
      "The XSLT 'param' declaration was not compiled correctly.\n");
2296
0
  return;
2297
0
    }
2298
2299
#ifdef WITH_XSLT_DEBUG_VARIABLE
2300
    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2301
  "Registering param %s\n", comp->name));
2302
#endif
2303
2304
0
    xsltRegisterVariable(ctxt, (xsltStylePreCompPtr) comp, cur->children, 1);
2305
0
}
2306
2307
/**
2308
 * xsltFreeGlobalVariables:
2309
 * @ctxt:  the XSLT transformation context
2310
 *
2311
 * Free up the data associated to the global variables
2312
 * its value.
2313
 */
2314
2315
void
2316
0
xsltFreeGlobalVariables(xsltTransformContextPtr ctxt) {
2317
0
    xmlHashFree(ctxt->globalVars, xsltFreeStackElemEntry);
2318
0
}
2319
2320
/**
2321
 * xsltXPathVariableLookup:
2322
 * @ctxt:  a void * but the the XSLT transformation context actually
2323
 * @name:  the variable name
2324
 * @ns_uri:  the variable namespace URI
2325
 *
2326
 * This is the entry point when a varibale is needed by the XPath
2327
 * interpretor.
2328
 *
2329
 * Returns the value or NULL if not found
2330
 */
2331
xmlXPathObjectPtr
2332
xsltXPathVariableLookup(void *ctxt, const xmlChar *name,
2333
0
                  const xmlChar *ns_uri) {
2334
0
    xsltTransformContextPtr tctxt;
2335
0
    xmlXPathObjectPtr valueObj = NULL;
2336
2337
0
    if ((ctxt == NULL) || (name == NULL))
2338
0
  return(NULL);
2339
2340
#ifdef WITH_XSLT_DEBUG_VARIABLE
2341
    XSLT_TRACE(((xsltTransformContextPtr)ctxt),XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2342
      "Lookup variable '%s'\n", name));
2343
#endif
2344
2345
0
    tctxt = (xsltTransformContextPtr) ctxt;
2346
    /*
2347
    * Local variables/params ---------------------------------------------
2348
    *
2349
    * Do the lookup from the top of the stack, but
2350
    * don't use params being computed in a call-param
2351
    * First lookup expects the variable name and URI to
2352
    * come from the disctionnary and hence pointer comparison.
2353
    */
2354
0
    if (tctxt->varsNr != 0) {
2355
0
  int i;
2356
0
  xsltStackElemPtr variable = NULL, cur;
2357
2358
0
  for (i = tctxt->varsNr; i > tctxt->varsBase; i--) {
2359
0
      cur = tctxt->varsTab[i-1];
2360
0
      if ((cur->name == name) && (cur->nameURI == ns_uri)) {
2361
0
    variable = cur;
2362
0
    goto local_variable_found;
2363
0
      }
2364
0
      cur = cur->next;
2365
0
  }
2366
  /*
2367
  * Redo the lookup with interned strings to avoid string comparison.
2368
  *
2369
  * OPTIMIZE TODO: The problem here is, that if we request a
2370
  *  global variable, then this will be also executed.
2371
  */
2372
0
  {
2373
0
      const xmlChar *tmpName = name, *tmpNsName = ns_uri;
2374
2375
0
      name = xmlDictLookup(tctxt->dict, name, -1);
2376
0
      if (ns_uri)
2377
0
    ns_uri = xmlDictLookup(tctxt->dict, ns_uri, -1);
2378
0
      if ((tmpName != name) || (tmpNsName != ns_uri)) {
2379
0
    for (i = tctxt->varsNr; i > tctxt->varsBase; i--) {
2380
0
        cur = tctxt->varsTab[i-1];
2381
0
        if ((cur->name == name) && (cur->nameURI == ns_uri)) {
2382
0
      variable = cur;
2383
0
      goto local_variable_found;
2384
0
        }
2385
0
    }
2386
0
      }
2387
0
  }
2388
2389
0
local_variable_found:
2390
2391
0
  if (variable) {
2392
0
      if (variable->computed == 0) {
2393
2394
#ifdef WITH_XSLT_DEBUG_VARIABLE
2395
    XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2396
        "uncomputed variable '%s'\n", name));
2397
#endif
2398
0
    variable->value = xsltEvalVariable(tctxt, variable, NULL);
2399
0
    variable->computed = 1;
2400
0
      }
2401
0
      if (variable->value != NULL) {
2402
0
    valueObj = xmlXPathObjectCopy(variable->value);
2403
0
      }
2404
0
      return(valueObj);
2405
0
  }
2406
0
    }
2407
    /*
2408
    * Global variables/params --------------------------------------------
2409
    */
2410
0
    if (tctxt->globalVars) {
2411
0
  valueObj = xsltGlobalVariableLookup(tctxt, name, ns_uri);
2412
0
    }
2413
2414
0
    if (valueObj == NULL) {
2415
2416
#ifdef WITH_XSLT_DEBUG_VARIABLE
2417
    XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2418
         "variable not found '%s'\n", name));
2419
#endif
2420
2421
0
  if (ns_uri) {
2422
0
      xsltTransformError(tctxt, NULL, tctxt->inst,
2423
0
    "Variable '{%s}%s' has not been declared.\n", ns_uri, name);
2424
0
  } else {
2425
0
      xsltTransformError(tctxt, NULL, tctxt->inst,
2426
0
    "Variable '%s' has not been declared.\n", name);
2427
0
  }
2428
0
    } else {
2429
2430
#ifdef WITH_XSLT_DEBUG_VARIABLE
2431
  XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2432
      "found variable '%s'\n", name));
2433
#endif
2434
0
    }
2435
2436
0
    return(valueObj);
2437
0
}