decb3d98989e36f5c6bde9e26617c94d741b67cf
[reactos.git] / dll / 3rdparty / libxslt / functions.c
1 /*
2 * functions.c: Implementation of the XSLT extra functions
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 * Bjorn Reese <breese@users.sourceforge.net> for number formatting
11 */
12
13 #include "precomp.h"
14
15 #include <libxml/xpointer.h>
16
17 #ifdef WITH_XSLT_DEBUG
18 #define WITH_XSLT_DEBUG_FUNCTION
19 #endif
20
21 /*
22 * Some versions of DocBook XSL use the vendor string to detect
23 * supporting chunking, this is a workaround to be considered
24 * in the list of decent XSLT processors <grin/>
25 */
26 #define DOCBOOK_XSL_HACK
27
28 /**
29 * xsltXPathFunctionLookup:
30 * @ctxt: a void * but the XSLT transformation context actually
31 * @name: the function name
32 * @ns_uri: the function namespace URI
33 *
34 * This is the entry point when a function is needed by the XPath
35 * interpretor.
36 *
37 * Returns the callback function or NULL if not found
38 */
39 xmlXPathFunction
40 xsltXPathFunctionLookup (xmlXPathContextPtr ctxt,
41 const xmlChar *name, const xmlChar *ns_uri) {
42 xmlXPathFunction ret;
43
44 if ((ctxt == NULL) || (name == NULL) || (ns_uri == NULL))
45 return (NULL);
46
47 #ifdef WITH_XSLT_DEBUG_FUNCTION
48 xsltGenericDebug(xsltGenericDebugContext,
49 "Lookup function {%s}%s\n", ns_uri, name);
50 #endif
51
52 /* give priority to context-level functions */
53 /*
54 ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
55 */
56 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
57
58 if (ret == NULL)
59 ret = xsltExtModuleFunctionLookup(name, ns_uri);
60
61 #ifdef WITH_XSLT_DEBUG_FUNCTION
62 if (ret != NULL)
63 xsltGenericDebug(xsltGenericDebugContext,
64 "found function %s\n", name);
65 #endif
66 return(ret);
67 }
68
69
70 /************************************************************************
71 * *
72 * Module interfaces *
73 * *
74 ************************************************************************/
75
76 static void
77 xsltDocumentFunctionLoadDocument(xmlXPathParserContextPtr ctxt, xmlChar* URI)
78 {
79 xsltTransformContextPtr tctxt;
80 xmlURIPtr uri;
81 xmlChar *fragment;
82 xsltDocumentPtr idoc; /* document info */
83 xmlDocPtr doc;
84 xmlXPathContextPtr xptrctxt = NULL;
85 xmlXPathObjectPtr resObj = NULL;
86
87 tctxt = xsltXPathGetTransformContext(ctxt);
88 if (tctxt == NULL) {
89 xsltTransformError(NULL, NULL, NULL,
90 "document() : internal error tctxt == NULL\n");
91 valuePush(ctxt, xmlXPathNewNodeSet(NULL));
92 return;
93 }
94
95 uri = xmlParseURI((const char *) URI);
96 if (uri == NULL) {
97 xsltTransformError(tctxt, NULL, NULL,
98 "document() : failed to parse URI\n");
99 valuePush(ctxt, xmlXPathNewNodeSet(NULL));
100 return;
101 }
102
103 /*
104 * check for and remove fragment identifier
105 */
106 fragment = (xmlChar *)uri->fragment;
107 if (fragment != NULL) {
108 xmlChar *newURI;
109 uri->fragment = NULL;
110 newURI = xmlSaveUri(uri);
111 idoc = xsltLoadDocument(tctxt, newURI);
112 xmlFree(newURI);
113 } else
114 idoc = xsltLoadDocument(tctxt, URI);
115 xmlFreeURI(uri);
116
117 if (idoc == NULL) {
118 if ((URI == NULL) ||
119 (URI[0] == '#') ||
120 ((tctxt->style->doc != NULL) &&
121 (xmlStrEqual(tctxt->style->doc->URL, URI))))
122 {
123 /*
124 * This selects the stylesheet's doc itself.
125 */
126 doc = tctxt->style->doc;
127 } else {
128 valuePush(ctxt, xmlXPathNewNodeSet(NULL));
129
130 if (fragment != NULL)
131 xmlFree(fragment);
132
133 return;
134 }
135 } else
136 doc = idoc->doc;
137
138 if (fragment == NULL) {
139 valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr) doc));
140 return;
141 }
142
143 /* use XPointer of HTML location for fragment ID */
144 #ifdef LIBXML_XPTR_ENABLED
145 xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
146 if (xptrctxt == NULL) {
147 xsltTransformError(tctxt, NULL, NULL,
148 "document() : internal error xptrctxt == NULL\n");
149 goto out_fragment;
150 }
151
152 resObj = xmlXPtrEval(fragment, xptrctxt);
153 xmlXPathFreeContext(xptrctxt);
154 #endif
155
156 if (resObj == NULL)
157 goto out_fragment;
158
159 switch (resObj->type) {
160 case XPATH_NODESET:
161 break;
162 case XPATH_UNDEFINED:
163 case XPATH_BOOLEAN:
164 case XPATH_NUMBER:
165 case XPATH_STRING:
166 case XPATH_POINT:
167 case XPATH_USERS:
168 case XPATH_XSLT_TREE:
169 case XPATH_RANGE:
170 case XPATH_LOCATIONSET:
171 xsltTransformError(tctxt, NULL, NULL,
172 "document() : XPointer does not select a node set: #%s\n",
173 fragment);
174 goto out_object;
175 }
176
177 valuePush(ctxt, resObj);
178 xmlFree(fragment);
179 return;
180
181 out_object:
182 xmlXPathFreeObject(resObj);
183
184 out_fragment:
185 valuePush(ctxt, xmlXPathNewNodeSet(NULL));
186 xmlFree(fragment);
187 }
188
189 /**
190 * xsltDocumentFunction:
191 * @ctxt: the XPath Parser context
192 * @nargs: the number of arguments
193 *
194 * Implement the document() XSLT function
195 * node-set document(object, node-set?)
196 */
197 void
198 xsltDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs)
199 {
200 xmlXPathObjectPtr obj, obj2 = NULL;
201 xmlChar *base = NULL, *URI;
202
203
204 if ((nargs < 1) || (nargs > 2)) {
205 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
206 "document() : invalid number of args %d\n",
207 nargs);
208 ctxt->error = XPATH_INVALID_ARITY;
209 return;
210 }
211 if (ctxt->value == NULL) {
212 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
213 "document() : invalid arg value\n");
214 ctxt->error = XPATH_INVALID_TYPE;
215 return;
216 }
217
218 if (nargs == 2) {
219 if (ctxt->value->type != XPATH_NODESET) {
220 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
221 "document() : invalid arg expecting a nodeset\n");
222 ctxt->error = XPATH_INVALID_TYPE;
223 return;
224 }
225
226 obj2 = valuePop(ctxt);
227 }
228
229 if (ctxt->value->type == XPATH_NODESET) {
230 int i;
231 xmlXPathObjectPtr newobj, ret;
232
233 obj = valuePop(ctxt);
234 ret = xmlXPathNewNodeSet(NULL);
235
236 if ((obj != NULL) && obj->nodesetval) {
237 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
238 valuePush(ctxt,
239 xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));
240 xmlXPathStringFunction(ctxt, 1);
241 if (nargs == 2) {
242 valuePush(ctxt, xmlXPathObjectCopy(obj2));
243 } else {
244 valuePush(ctxt,
245 xmlXPathNewNodeSet(obj->nodesetval->
246 nodeTab[i]));
247 }
248 xsltDocumentFunction(ctxt, 2);
249 newobj = valuePop(ctxt);
250 ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
251 newobj->nodesetval);
252 xmlXPathFreeObject(newobj);
253 }
254 }
255
256 if (obj != NULL)
257 xmlXPathFreeObject(obj);
258 if (obj2 != NULL)
259 xmlXPathFreeObject(obj2);
260 valuePush(ctxt, ret);
261 return;
262 }
263 /*
264 * Make sure it's converted to a string
265 */
266 xmlXPathStringFunction(ctxt, 1);
267 if (ctxt->value->type != XPATH_STRING) {
268 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
269 "document() : invalid arg expecting a string\n");
270 ctxt->error = XPATH_INVALID_TYPE;
271 if (obj2 != NULL)
272 xmlXPathFreeObject(obj2);
273 return;
274 }
275 obj = valuePop(ctxt);
276 if (obj->stringval == NULL) {
277 valuePush(ctxt, xmlXPathNewNodeSet(NULL));
278 } else {
279 xsltTransformContextPtr tctxt;
280 tctxt = xsltXPathGetTransformContext(ctxt);
281 if ((obj2 != NULL) && (obj2->nodesetval != NULL) &&
282 (obj2->nodesetval->nodeNr > 0) &&
283 IS_XSLT_REAL_NODE(obj2->nodesetval->nodeTab[0])) {
284 xmlNodePtr target;
285
286 target = obj2->nodesetval->nodeTab[0];
287 if ((target->type == XML_ATTRIBUTE_NODE) ||
288 (target->type == XML_PI_NODE)) {
289 target = ((xmlAttrPtr) target)->parent;
290 }
291 base = xmlNodeGetBase(target->doc, target);
292 } else {
293 if ((tctxt != NULL) && (tctxt->inst != NULL)) {
294 base = xmlNodeGetBase(tctxt->inst->doc, tctxt->inst);
295 } else if ((tctxt != NULL) && (tctxt->style != NULL) &&
296 (tctxt->style->doc != NULL)) {
297 base = xmlNodeGetBase(tctxt->style->doc,
298 (xmlNodePtr) tctxt->style->doc);
299 }
300 }
301 URI = xmlBuildURI(obj->stringval, base);
302 if (base != NULL)
303 xmlFree(base);
304 if (URI == NULL) {
305 if ((tctxt != NULL) && (tctxt->style != NULL) &&
306 (tctxt->style->doc != NULL) &&
307 (xmlStrEqual(URI, tctxt->style->doc->URL))) {
308 /* This selects the stylesheet's doc itself. */
309 valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr) tctxt->style->doc));
310 } else {
311 valuePush(ctxt, xmlXPathNewNodeSet(NULL));
312 }
313 } else {
314 xsltDocumentFunctionLoadDocument( ctxt, URI );
315 xmlFree(URI);
316 }
317 }
318 xmlXPathFreeObject(obj);
319 if (obj2 != NULL)
320 xmlXPathFreeObject(obj2);
321 }
322
323 /**
324 * xsltKeyFunction:
325 * @ctxt: the XPath Parser context
326 * @nargs: the number of arguments
327 *
328 * Implement the key() XSLT function
329 * node-set key(string, object)
330 */
331 void
332 xsltKeyFunction(xmlXPathParserContextPtr ctxt, int nargs){
333 xmlXPathObjectPtr obj1, obj2;
334
335 if (nargs != 2) {
336 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
337 "key() : expects two arguments\n");
338 ctxt->error = XPATH_INVALID_ARITY;
339 return;
340 }
341
342 /*
343 * Get the key's value.
344 */
345 obj2 = valuePop(ctxt);
346 xmlXPathStringFunction(ctxt, 1);
347 if ((obj2 == NULL) ||
348 (ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
349 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
350 "key() : invalid arg expecting a string\n");
351 ctxt->error = XPATH_INVALID_TYPE;
352 xmlXPathFreeObject(obj2);
353
354 return;
355 }
356 /*
357 * Get the key's name.
358 */
359 obj1 = valuePop(ctxt);
360
361 if ((obj2->type == XPATH_NODESET) || (obj2->type == XPATH_XSLT_TREE)) {
362 int i;
363 xmlXPathObjectPtr newobj, ret;
364
365 ret = xmlXPathNewNodeSet(NULL);
366
367 if (obj2->nodesetval != NULL) {
368 for (i = 0; i < obj2->nodesetval->nodeNr; i++) {
369 valuePush(ctxt, xmlXPathObjectCopy(obj1));
370 valuePush(ctxt,
371 xmlXPathNewNodeSet(obj2->nodesetval->nodeTab[i]));
372 xmlXPathStringFunction(ctxt, 1);
373 xsltKeyFunction(ctxt, 2);
374 newobj = valuePop(ctxt);
375 ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
376 newobj->nodesetval);
377 xmlXPathFreeObject(newobj);
378 }
379 }
380 valuePush(ctxt, ret);
381 } else {
382 xmlNodeSetPtr nodelist = NULL;
383 xmlChar *key = NULL, *value;
384 const xmlChar *keyURI;
385 xsltTransformContextPtr tctxt;
386 xmlChar *qname, *prefix;
387 xmlXPathContextPtr xpctxt = ctxt->context;
388 xmlNodePtr tmpNode = NULL;
389 xsltDocumentPtr oldDocInfo;
390
391 tctxt = xsltXPathGetTransformContext(ctxt);
392
393 oldDocInfo = tctxt->document;
394
395 if (xpctxt->node == NULL) {
396 xsltTransformError(tctxt, NULL, tctxt->inst,
397 "Internal error in xsltKeyFunction(): "
398 "The context node is not set on the XPath context.\n");
399 tctxt->state = XSLT_STATE_STOPPED;
400 goto error;
401 }
402 /*
403 * Get the associated namespace URI if qualified name
404 */
405 qname = obj1->stringval;
406 key = xmlSplitQName2(qname, &prefix);
407 if (key == NULL) {
408 key = xmlStrdup(obj1->stringval);
409 keyURI = NULL;
410 if (prefix != NULL)
411 xmlFree(prefix);
412 } else {
413 if (prefix != NULL) {
414 keyURI = xmlXPathNsLookup(xpctxt, prefix);
415 if (keyURI == NULL) {
416 xsltTransformError(tctxt, NULL, tctxt->inst,
417 "key() : prefix %s is not bound\n", prefix);
418 /*
419 * TODO: Shouldn't we stop here?
420 */
421 }
422 xmlFree(prefix);
423 } else {
424 keyURI = NULL;
425 }
426 }
427
428 /*
429 * Force conversion of first arg to string
430 */
431 valuePush(ctxt, obj2);
432 xmlXPathStringFunction(ctxt, 1);
433 if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
434 xsltTransformError(tctxt, NULL, tctxt->inst,
435 "key() : invalid arg expecting a string\n");
436 ctxt->error = XPATH_INVALID_TYPE;
437 goto error;
438 }
439 obj2 = valuePop(ctxt);
440 value = obj2->stringval;
441
442 /*
443 * We need to ensure that ctxt->document is available for
444 * xsltGetKey().
445 * First find the relevant doc, which is the context node's
446 * owner doc; using context->doc is not safe, since
447 * the doc could have been acquired via the document() function,
448 * or the doc might be a Result Tree Fragment.
449 * FUTURE INFO: In XSLT 2.0 the key() function takes an additional
450 * argument indicating the doc to use.
451 */
452 if (xpctxt->node->type == XML_NAMESPACE_DECL) {
453 /*
454 * REVISIT: This is a libxml hack! Check xpath.c for details.
455 * The XPath module sets the owner element of a ns-node on
456 * the ns->next field.
457 */
458 if ((((xmlNsPtr) xpctxt->node)->next != NULL) &&
459 (((xmlNsPtr) xpctxt->node)->next->type == XML_ELEMENT_NODE))
460 {
461 tmpNode = (xmlNodePtr) ((xmlNsPtr) xpctxt->node)->next;
462 }
463 } else
464 tmpNode = xpctxt->node;
465
466 if ((tmpNode == NULL) || (tmpNode->doc == NULL)) {
467 xsltTransformError(tctxt, NULL, tctxt->inst,
468 "Internal error in xsltKeyFunction(): "
469 "Couldn't get the doc of the XPath context node.\n");
470 goto error;
471 }
472
473 if ((tctxt->document == NULL) ||
474 (tctxt->document->doc != tmpNode->doc))
475 {
476 if (tmpNode->doc->name && (tmpNode->doc->name[0] == ' ')) {
477 /*
478 * This is a Result Tree Fragment.
479 */
480 if (tmpNode->doc->_private == NULL) {
481 tmpNode->doc->_private = xsltNewDocument(tctxt, tmpNode->doc);
482 if (tmpNode->doc->_private == NULL)
483 goto error;
484 }
485 tctxt->document = (xsltDocumentPtr) tmpNode->doc->_private;
486 } else {
487 /*
488 * May be the initial source doc or a doc acquired via the
489 * document() function.
490 */
491 tctxt->document = xsltFindDocument(tctxt, tmpNode->doc);
492 }
493 if (tctxt->document == NULL) {
494 xsltTransformError(tctxt, NULL, tctxt->inst,
495 "Internal error in xsltKeyFunction(): "
496 "Could not get the document info of a context doc.\n");
497 tctxt->state = XSLT_STATE_STOPPED;
498 goto error;
499 }
500 }
501 /*
502 * Get/compute the key value.
503 */
504 nodelist = xsltGetKey(tctxt, key, keyURI, value);
505
506 error:
507 tctxt->document = oldDocInfo;
508 valuePush(ctxt, xmlXPathWrapNodeSet(
509 xmlXPathNodeSetMerge(NULL, nodelist)));
510 if (key != NULL)
511 xmlFree(key);
512 }
513
514 if (obj1 != NULL)
515 xmlXPathFreeObject(obj1);
516 if (obj2 != NULL)
517 xmlXPathFreeObject(obj2);
518 }
519
520 /**
521 * xsltUnparsedEntityURIFunction:
522 * @ctxt: the XPath Parser context
523 * @nargs: the number of arguments
524 *
525 * Implement the unparsed-entity-uri() XSLT function
526 * string unparsed-entity-uri(string)
527 */
528 void
529 xsltUnparsedEntityURIFunction(xmlXPathParserContextPtr ctxt, int nargs){
530 xmlXPathObjectPtr obj;
531 xmlChar *str;
532
533 if ((nargs != 1) || (ctxt->value == NULL)) {
534 xsltGenericError(xsltGenericErrorContext,
535 "unparsed-entity-uri() : expects one string arg\n");
536 ctxt->error = XPATH_INVALID_ARITY;
537 return;
538 }
539 obj = valuePop(ctxt);
540 if (obj->type != XPATH_STRING) {
541 obj = xmlXPathConvertString(obj);
542 }
543
544 str = obj->stringval;
545 if (str == NULL) {
546 valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
547 } else {
548 xmlEntityPtr entity;
549
550 entity = xmlGetDocEntity(ctxt->context->doc, str);
551 if (entity == NULL) {
552 valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
553 } else {
554 if (entity->URI != NULL)
555 valuePush(ctxt, xmlXPathNewString(entity->URI));
556 else
557 valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
558 }
559 }
560 xmlXPathFreeObject(obj);
561 }
562
563 /**
564 * xsltFormatNumberFunction:
565 * @ctxt: the XPath Parser context
566 * @nargs: the number of arguments
567 *
568 * Implement the format-number() XSLT function
569 * string format-number(number, string, string?)
570 */
571 void
572 xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs)
573 {
574 xmlXPathObjectPtr numberObj = NULL;
575 xmlXPathObjectPtr formatObj = NULL;
576 xmlXPathObjectPtr decimalObj = NULL;
577 xsltStylesheetPtr sheet;
578 xsltDecimalFormatPtr formatValues = NULL;
579 xmlChar *result;
580 const xmlChar *ncname;
581 const xmlChar *prefix = NULL;
582 const xmlChar *nsUri = NULL;
583 xsltTransformContextPtr tctxt;
584
585 tctxt = xsltXPathGetTransformContext(ctxt);
586 if ((tctxt == NULL) || (tctxt->inst == NULL))
587 return;
588 sheet = tctxt->style;
589 if (sheet == NULL)
590 return;
591 formatValues = sheet->decimalFormat;
592
593 switch (nargs) {
594 case 3:
595 CAST_TO_STRING;
596 decimalObj = valuePop(ctxt);
597 ncname = xsltSplitQName(sheet->dict, decimalObj->stringval, &prefix);
598 if (prefix != NULL) {
599 xmlNsPtr ns = xmlSearchNs(tctxt->inst->doc, tctxt->inst, prefix);
600 if (ns == NULL) {
601 xsltTransformError(tctxt, NULL, NULL,
602 "format-number : No namespace found for QName '%s:%s'\n",
603 prefix, ncname);
604 sheet->errors++;
605 ncname = NULL;
606 }
607 else {
608 nsUri = ns->href;
609 }
610 }
611 if (ncname != NULL) {
612 formatValues = xsltDecimalFormatGetByQName(sheet, nsUri, ncname);
613 }
614 if (formatValues == NULL) {
615 xsltTransformError(tctxt, NULL, NULL,
616 "format-number() : undeclared decimal format '%s'\n",
617 decimalObj->stringval);
618 }
619 /* Intentional fall-through */
620 case 2:
621 CAST_TO_STRING;
622 formatObj = valuePop(ctxt);
623 CAST_TO_NUMBER;
624 numberObj = valuePop(ctxt);
625 break;
626 default:
627 XP_ERROR(XPATH_INVALID_ARITY);
628 }
629
630 if (formatValues != NULL) {
631 if (xsltFormatNumberConversion(formatValues,
632 formatObj->stringval,
633 numberObj->floatval,
634 &result) == XPATH_EXPRESSION_OK) {
635 valuePush(ctxt, xmlXPathNewString(result));
636 xmlFree(result);
637 }
638 }
639
640 xmlXPathFreeObject(numberObj);
641 xmlXPathFreeObject(formatObj);
642 xmlXPathFreeObject(decimalObj);
643 }
644
645 /**
646 * xsltGenerateIdFunction:
647 * @ctxt: the XPath Parser context
648 * @nargs: the number of arguments
649 *
650 * Implement the generate-id() XSLT function
651 * string generate-id(node-set?)
652 */
653 void
654 xsltGenerateIdFunction(xmlXPathParserContextPtr ctxt, int nargs){
655 static char base_address;
656 xmlNodePtr cur = NULL;
657 xmlXPathObjectPtr obj = NULL;
658 long val;
659 xmlChar str[30];
660
661 if (nargs == 0) {
662 cur = ctxt->context->node;
663 } else if (nargs == 1) {
664 xmlNodeSetPtr nodelist;
665 int i, ret;
666
667 if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) {
668 ctxt->error = XPATH_INVALID_TYPE;
669 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
670 "generate-id() : invalid arg expecting a node-set\n");
671 return;
672 }
673 obj = valuePop(ctxt);
674 nodelist = obj->nodesetval;
675 if ((nodelist == NULL) || (nodelist->nodeNr <= 0)) {
676 xmlXPathFreeObject(obj);
677 valuePush(ctxt, xmlXPathNewCString(""));
678 return;
679 }
680 cur = nodelist->nodeTab[0];
681 for (i = 1;i < nodelist->nodeNr;i++) {
682 ret = xmlXPathCmpNodes(cur, nodelist->nodeTab[i]);
683 if (ret == -1)
684 cur = nodelist->nodeTab[i];
685 }
686 } else {
687 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
688 "generate-id() : invalid number of args %d\n", nargs);
689 ctxt->error = XPATH_INVALID_ARITY;
690 return;
691 }
692
693 if (obj)
694 xmlXPathFreeObject(obj);
695
696 val = (long)((char *)cur - (char *)&base_address);
697 if (val >= 0) {
698 snprintf((char *)str, sizeof(str), "idp%ld", val);
699 } else {
700 snprintf((char *)str, sizeof(str), "idm%ld", -val);
701 }
702 valuePush(ctxt, xmlXPathNewString(str));
703 }
704
705 /**
706 * xsltSystemPropertyFunction:
707 * @ctxt: the XPath Parser context
708 * @nargs: the number of arguments
709 *
710 * Implement the system-property() XSLT function
711 * object system-property(string)
712 */
713 void
714 xsltSystemPropertyFunction(xmlXPathParserContextPtr ctxt, int nargs){
715 xmlXPathObjectPtr obj;
716 xmlChar *prefix, *name;
717 const xmlChar *nsURI = NULL;
718
719 if (nargs != 1) {
720 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
721 "system-property() : expects one string arg\n");
722 ctxt->error = XPATH_INVALID_ARITY;
723 return;
724 }
725 if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
726 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
727 "system-property() : invalid arg expecting a string\n");
728 ctxt->error = XPATH_INVALID_TYPE;
729 return;
730 }
731 obj = valuePop(ctxt);
732 if (obj->stringval == NULL) {
733 valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
734 } else {
735 name = xmlSplitQName2(obj->stringval, &prefix);
736 if (name == NULL) {
737 name = xmlStrdup(obj->stringval);
738 } else {
739 nsURI = xmlXPathNsLookup(ctxt->context, prefix);
740 if (nsURI == NULL) {
741 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
742 "system-property() : prefix %s is not bound\n", prefix);
743 }
744 }
745
746 if (xmlStrEqual(nsURI, XSLT_NAMESPACE)) {
747 #ifdef DOCBOOK_XSL_HACK
748 if (xmlStrEqual(name, (const xmlChar *)"vendor")) {
749 xsltStylesheetPtr sheet;
750 xsltTransformContextPtr tctxt;
751
752 tctxt = xsltXPathGetTransformContext(ctxt);
753 if ((tctxt != NULL) && (tctxt->inst != NULL) &&
754 (xmlStrEqual(tctxt->inst->name, BAD_CAST "variable")) &&
755 (tctxt->inst->parent != NULL) &&
756 (xmlStrEqual(tctxt->inst->parent->name,
757 BAD_CAST "template")))
758 sheet = tctxt->style;
759 else
760 sheet = NULL;
761 if ((sheet != NULL) && (sheet->doc != NULL) &&
762 (sheet->doc->URL != NULL) &&
763 (xmlStrstr(sheet->doc->URL,
764 (const xmlChar *)"chunk") != NULL)) {
765 valuePush(ctxt, xmlXPathNewString(
766 (const xmlChar *)"libxslt (SAXON 6.2 compatible)"));
767
768 } else {
769 valuePush(ctxt, xmlXPathNewString(
770 (const xmlChar *)XSLT_DEFAULT_VENDOR));
771 }
772 } else
773 #else
774 if (xmlStrEqual(name, (const xmlChar *)"vendor")) {
775 valuePush(ctxt, xmlXPathNewString(
776 (const xmlChar *)XSLT_DEFAULT_VENDOR));
777 } else
778 #endif
779 if (xmlStrEqual(name, (const xmlChar *)"version")) {
780 valuePush(ctxt, xmlXPathNewString(
781 (const xmlChar *)XSLT_DEFAULT_VERSION));
782 } else if (xmlStrEqual(name, (const xmlChar *)"vendor-url")) {
783 valuePush(ctxt, xmlXPathNewString(
784 (const xmlChar *)XSLT_DEFAULT_URL));
785 } else {
786 valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
787 }
788 } else {
789 valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
790 }
791 if (name != NULL)
792 xmlFree(name);
793 if (prefix != NULL)
794 xmlFree(prefix);
795 }
796 xmlXPathFreeObject(obj);
797 }
798
799 /**
800 * xsltElementAvailableFunction:
801 * @ctxt: the XPath Parser context
802 * @nargs: the number of arguments
803 *
804 * Implement the element-available() XSLT function
805 * boolean element-available(string)
806 */
807 void
808 xsltElementAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){
809 xmlXPathObjectPtr obj;
810 xmlChar *prefix, *name;
811 const xmlChar *nsURI = NULL;
812 xsltTransformContextPtr tctxt;
813
814 if (nargs != 1) {
815 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
816 "element-available() : expects one string arg\n");
817 ctxt->error = XPATH_INVALID_ARITY;
818 return;
819 }
820 xmlXPathStringFunction(ctxt, 1);
821 if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
822 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
823 "element-available() : invalid arg expecting a string\n");
824 ctxt->error = XPATH_INVALID_TYPE;
825 return;
826 }
827 obj = valuePop(ctxt);
828 tctxt = xsltXPathGetTransformContext(ctxt);
829 if ((tctxt == NULL) || (tctxt->inst == NULL)) {
830 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
831 "element-available() : internal error tctxt == NULL\n");
832 xmlXPathFreeObject(obj);
833 valuePush(ctxt, xmlXPathNewBoolean(0));
834 return;
835 }
836
837
838 name = xmlSplitQName2(obj->stringval, &prefix);
839 if (name == NULL) {
840 xmlNsPtr ns;
841
842 name = xmlStrdup(obj->stringval);
843 ns = xmlSearchNs(tctxt->inst->doc, tctxt->inst, NULL);
844 if (ns != NULL) nsURI = ns->href;
845 } else {
846 nsURI = xmlXPathNsLookup(ctxt->context, prefix);
847 if (nsURI == NULL) {
848 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
849 "element-available() : prefix %s is not bound\n", prefix);
850 }
851 }
852
853 if (xsltExtElementLookup(tctxt, name, nsURI) != NULL) {
854 valuePush(ctxt, xmlXPathNewBoolean(1));
855 } else {
856 valuePush(ctxt, xmlXPathNewBoolean(0));
857 }
858
859 xmlXPathFreeObject(obj);
860 if (name != NULL)
861 xmlFree(name);
862 if (prefix != NULL)
863 xmlFree(prefix);
864 }
865
866 /**
867 * xsltFunctionAvailableFunction:
868 * @ctxt: the XPath Parser context
869 * @nargs: the number of arguments
870 *
871 * Implement the function-available() XSLT function
872 * boolean function-available(string)
873 */
874 void
875 xsltFunctionAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){
876 xmlXPathObjectPtr obj;
877 xmlChar *prefix, *name;
878 const xmlChar *nsURI = NULL;
879
880 if (nargs != 1) {
881 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
882 "function-available() : expects one string arg\n");
883 ctxt->error = XPATH_INVALID_ARITY;
884 return;
885 }
886 xmlXPathStringFunction(ctxt, 1);
887 if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
888 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
889 "function-available() : invalid arg expecting a string\n");
890 ctxt->error = XPATH_INVALID_TYPE;
891 return;
892 }
893 obj = valuePop(ctxt);
894
895 name = xmlSplitQName2(obj->stringval, &prefix);
896 if (name == NULL) {
897 name = xmlStrdup(obj->stringval);
898 } else {
899 nsURI = xmlXPathNsLookup(ctxt->context, prefix);
900 if (nsURI == NULL) {
901 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
902 "function-available() : prefix %s is not bound\n", prefix);
903 }
904 }
905
906 if (xmlXPathFunctionLookupNS(ctxt->context, name, nsURI) != NULL) {
907 valuePush(ctxt, xmlXPathNewBoolean(1));
908 } else {
909 valuePush(ctxt, xmlXPathNewBoolean(0));
910 }
911
912 xmlXPathFreeObject(obj);
913 if (name != NULL)
914 xmlFree(name);
915 if (prefix != NULL)
916 xmlFree(prefix);
917 }
918
919 /**
920 * xsltCurrentFunction:
921 * @ctxt: the XPath Parser context
922 * @nargs: the number of arguments
923 *
924 * Implement the current() XSLT function
925 * node-set current()
926 */
927 static void
928 xsltCurrentFunction(xmlXPathParserContextPtr ctxt, int nargs){
929 xsltTransformContextPtr tctxt;
930
931 if (nargs != 0) {
932 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
933 "current() : function uses no argument\n");
934 ctxt->error = XPATH_INVALID_ARITY;
935 return;
936 }
937 tctxt = xsltXPathGetTransformContext(ctxt);
938 if (tctxt == NULL) {
939 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
940 "current() : internal error tctxt == NULL\n");
941 valuePush(ctxt, xmlXPathNewNodeSet(NULL));
942 } else {
943 valuePush(ctxt, xmlXPathNewNodeSet(tctxt->node)); /* current */
944 }
945 }
946
947 /************************************************************************
948 * *
949 * Registration of XSLT and libxslt functions *
950 * *
951 ************************************************************************/
952
953 /**
954 * xsltRegisterAllFunctions:
955 * @ctxt: the XPath context
956 *
957 * Registers all default XSLT functions in this context
958 */
959 void
960 xsltRegisterAllFunctions(xmlXPathContextPtr ctxt)
961 {
962 xmlXPathRegisterFunc(ctxt, (const xmlChar *) "current",
963 xsltCurrentFunction);
964 xmlXPathRegisterFunc(ctxt, (const xmlChar *) "document",
965 xsltDocumentFunction);
966 xmlXPathRegisterFunc(ctxt, (const xmlChar *) "key", xsltKeyFunction);
967 xmlXPathRegisterFunc(ctxt, (const xmlChar *) "unparsed-entity-uri",
968 xsltUnparsedEntityURIFunction);
969 xmlXPathRegisterFunc(ctxt, (const xmlChar *) "format-number",
970 xsltFormatNumberFunction);
971 xmlXPathRegisterFunc(ctxt, (const xmlChar *) "generate-id",
972 xsltGenerateIdFunction);
973 xmlXPathRegisterFunc(ctxt, (const xmlChar *) "system-property",
974 xsltSystemPropertyFunction);
975 xmlXPathRegisterFunc(ctxt, (const xmlChar *) "element-available",
976 xsltElementAvailableFunction);
977 xmlXPathRegisterFunc(ctxt, (const xmlChar *) "function-available",
978 xsltFunctionAvailableFunction);
979 }