preparing 1.0.14 updated rebuilt implemented the IN_LIBXSLT and
[platform/upstream/libxslt.git] / 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 #define IN_LIBXSLT
14 #include "libxslt.h"
15
16 #include <string.h>
17
18 #ifdef HAVE_SYS_TYPES_H
19 #include <sys/types.h>
20 #endif
21 #ifdef HAVE_CTYPE_H
22 #include <ctype.h>
23 #endif
24
25 #include <libxml/xmlmemory.h>
26 #include <libxml/parser.h>
27 #include <libxml/tree.h>
28 #include <libxml/valid.h>
29 #include <libxml/hash.h>
30 #include <libxml/xmlerror.h>
31 #include <libxml/xpath.h>
32 #include <libxml/xpathInternals.h>
33 #include <libxml/parserInternals.h>
34 #include <libxml/uri.h>
35 #include "xslt.h"
36 #include "xsltInternals.h"
37 #include "xsltutils.h"
38 #include "functions.h"
39 #include "extensions.h"
40 #include "numbersInternals.h"
41 #include "keys.h"
42 #include "documents.h"
43
44 #ifdef WITH_XSLT_DEBUG
45 #define WITH_XSLT_DEBUG_FUNCTION
46 #endif
47
48 /*
49  * Some versions of DocBook XSL use the vendor string to detect
50  * supporting chunking, this is a workaround to be considered
51  * in the list of decent XSLT processors <grin/>
52  */
53 #define DOCBOOK_XSL_HACK
54
55 /**
56  * xsltXPathFunctionLookup:
57  * @ctxt:  a void * but the XSLT transformation context actually
58  * @name:  the function name
59  * @ns_uri:  the function namespace URI
60  *
61  * This is the entry point when a function is needed by the XPath
62  * interpretor.
63  *
64  * Returns the callback function or NULL if not found
65  */
66 xmlXPathFunction
67 xsltXPathFunctionLookup (xmlXPathContextPtr ctxt,
68                          const xmlChar *name, const xmlChar *ns_uri) {
69     xmlXPathFunction ret;
70
71     if ((ctxt == NULL) || (name == NULL) || (ns_uri == NULL))
72         return (NULL);
73
74 #ifdef WITH_XSLT_DEBUG_FUNCTION
75     xsltGenericDebug(xsltGenericDebugContext,
76             "Lookup function {%s}%s\n", ns_uri, name);
77 #endif
78
79     /* give priority to context-level functions */
80     ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
81
82     if (ret == NULL)
83         ret = xsltExtModuleFunctionLookup(name, ns_uri);
84
85 #ifdef WITH_XSLT_DEBUG_FUNCTION
86     if (ret != NULL)
87         xsltGenericDebug(xsltGenericDebugContext,
88             "found function %s\n", name);
89 #endif
90     return(ret);
91 }
92
93
94 /************************************************************************
95  *                                                                      *
96  *                      Module interfaces                               *
97  *                                                                      *
98  ************************************************************************/
99
100 /**
101  * xsltDocumentFunction:
102  * @ctxt:  the XPath Parser context
103  * @nargs:  the number of arguments
104  *
105  * Implement the document() XSLT function
106  *   node-set document(object, node-set?)
107  */
108 void
109 xsltDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs){
110     xsltDocumentPtr doc;
111     xmlXPathObjectPtr obj, obj2 = NULL;
112     xmlChar *base = NULL, *URI;
113
114
115     if ((nargs < 1) || (nargs > 2)) {
116         xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
117         xsltGenericError(xsltGenericErrorContext,
118                 "document() : invalid number of args %d\n", nargs);
119         ctxt->error = XPATH_INVALID_ARITY;
120         return;
121     }
122     if (ctxt->value == NULL) {
123         xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
124         xsltGenericError(xsltGenericErrorContext,
125             "document() : invalid arg value\n");
126         ctxt->error = XPATH_INVALID_TYPE;
127         return;
128     }
129
130     if (nargs == 2) {
131         if (ctxt->value->type != XPATH_NODESET) {
132             xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt),
133                                   NULL, NULL);
134             xsltGenericError(xsltGenericErrorContext,
135                 "document() : invalid arg expecting a nodeset\n");
136             ctxt->error = XPATH_INVALID_TYPE;
137             return;
138         }
139
140         obj2 = valuePop(ctxt);
141     }
142
143     if (ctxt->value->type == XPATH_NODESET) {
144         int i;
145         xmlXPathObjectPtr newobj, ret;
146
147         obj = valuePop(ctxt);
148         ret = xmlXPathNewNodeSet(NULL);
149
150         if (obj->nodesetval) {
151             for (i = 0; i < obj->nodesetval->nodeNr; i++) {
152                 valuePush(ctxt,
153                           xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));
154                 xmlXPathStringFunction(ctxt, 1);
155                 if (nargs == 2) {
156                     valuePush(ctxt, xmlXPathObjectCopy(obj2));
157                 } else {
158                     valuePush(ctxt,
159                               xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));
160                 }
161                 xsltDocumentFunction(ctxt, 2);
162                 newobj = valuePop(ctxt);
163                 ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
164                                                        newobj->nodesetval);
165                 xmlXPathFreeObject(newobj);
166             }
167         }
168
169         xmlXPathFreeObject(obj);
170         if (obj2 != NULL)
171             xmlXPathFreeObject(obj2);
172         valuePush(ctxt, ret);
173         return;
174     }
175     /*
176      * Make sure it's converted to a string
177      */
178     xmlXPathStringFunction(ctxt, 1);
179     if (ctxt->value->type != XPATH_STRING) {
180         xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
181         xsltGenericError(xsltGenericErrorContext,
182             "document() : invalid arg expecting a string\n");
183         ctxt->error = XPATH_INVALID_TYPE;
184         if (obj2 != NULL)
185             xmlXPathFreeObject(obj2);
186         return;
187     }
188     obj = valuePop(ctxt);
189     if (obj->stringval == NULL) {
190         valuePush(ctxt, xmlXPathNewNodeSet(NULL));
191     } else {
192         if ((obj2 != NULL) && (obj2->nodesetval != NULL) &&
193             (obj2->nodesetval->nodeNr > 0) &&
194             IS_XSLT_REAL_NODE(obj2->nodesetval->nodeTab[0])) {
195             xmlNodePtr target;
196
197             target = obj2->nodesetval->nodeTab[0];
198             if (target->type == XML_ATTRIBUTE_NODE) {
199                 target = ((xmlAttrPtr) target)->parent;
200             }
201             base = xmlNodeGetBase(target->doc, target);
202         } else {
203             xsltTransformContextPtr tctxt;
204             
205             tctxt = xsltXPathGetTransformContext(ctxt);
206             if ((tctxt != NULL) && (tctxt->inst != NULL)) {
207                 base = xmlNodeGetBase(tctxt->inst->doc, tctxt->inst);
208             } else if ((tctxt != NULL) && (tctxt->style != NULL) &&
209                        (tctxt->style->doc != NULL)) {
210                 base = xmlNodeGetBase(tctxt->style->doc, 
211                                       (xmlNodePtr) tctxt->style->doc);
212             }
213         }
214         URI = xmlBuildURI(obj->stringval, base);
215         if (base != NULL)
216             xmlFree(base);
217         if (URI == NULL) {
218             valuePush(ctxt, xmlXPathNewNodeSet(NULL));
219         } else {
220             xsltTransformContextPtr tctxt;
221
222             tctxt = xsltXPathGetTransformContext(ctxt);
223             if (tctxt == NULL) {
224                 xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt),
225                                       NULL, NULL);
226                 xsltGenericError(xsltGenericErrorContext,
227                         "document() : internal error tctxt == NULL\n");
228                 valuePush(ctxt, xmlXPathNewNodeSet(NULL));
229             } else {
230                 if (xmlStrEqual(tctxt->style->doc->URL, URI)) {
231                     valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr)tctxt->style->doc));
232                 }
233                 else {
234                     doc = xsltLoadDocument(tctxt, URI);
235                     if (doc == NULL)
236                         valuePush(ctxt, xmlXPathNewNodeSet(NULL));
237                     else {
238                         /* TODO: use XPointer of HTML location for fragment ID */
239                         /* pbm #xxx can lead to location sets, not nodesets :-) */
240                         valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr) doc->doc));
241                     }
242                 }
243             }
244             xmlFree(URI);
245         }
246     }
247     xmlXPathFreeObject(obj);
248     if (obj2 != NULL)
249         xmlXPathFreeObject(obj2);
250 }
251
252 /**
253  * xsltKeyFunction:
254  * @ctxt:  the XPath Parser context
255  * @nargs:  the number of arguments
256  *
257  * Implement the key() XSLT function
258  *   node-set key(string, object)
259  */
260 void
261 xsltKeyFunction(xmlXPathParserContextPtr ctxt, int nargs){
262     xmlNodeSetPtr nodelist;
263     xmlXPathObjectPtr obj1, obj2;
264     xmlChar *key = NULL, *value;
265     const xmlChar *keyURI;
266     xsltTransformContextPtr tctxt;
267
268     if (nargs != 2) {
269         xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
270         xsltGenericError(xsltGenericErrorContext,
271                 "key() : expects two arguments\n");
272         ctxt->error = XPATH_INVALID_ARITY;
273         return;
274     }
275
276     obj2 = valuePop(ctxt);
277     if ((obj2 == NULL) ||
278         (ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
279         xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
280         xsltGenericError(xsltGenericErrorContext,
281             "key() : invalid arg expecting a string\n");
282         ctxt->error = XPATH_INVALID_TYPE;
283         xmlXPathFreeObject(obj2);
284
285         return;
286     }
287     obj1 = valuePop(ctxt);
288
289     if (obj2->type == XPATH_NODESET) {
290         int i;
291         xmlXPathObjectPtr newobj, ret;
292
293         ret = xmlXPathNewNodeSet(NULL);
294
295         if (obj2->nodesetval != NULL) {
296             for (i = 0; i < obj2->nodesetval->nodeNr; i++) {
297                 valuePush(ctxt, xmlXPathObjectCopy(obj1));
298                 valuePush(ctxt,
299                           xmlXPathNewNodeSet(obj2->nodesetval->nodeTab[i]));
300                 xmlXPathStringFunction(ctxt, 1);
301                 xsltKeyFunction(ctxt, 2);
302                 newobj = valuePop(ctxt);
303                 ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
304                                                        newobj->nodesetval);
305                 xmlXPathFreeObject(newobj);
306             }
307         }
308         valuePush(ctxt, ret);
309     } else {
310         xmlChar *qname, *prefix;
311
312         /*
313          * Get the associated namespace URI if qualified name
314          */
315         qname = obj1->stringval;
316         key = xmlSplitQName2(qname, &prefix);
317         if (key == NULL) {
318             key = xmlStrdup(obj1->stringval);
319             keyURI = NULL;
320             if (prefix != NULL)
321                 xmlFree(prefix);
322         } else {
323             if (prefix != NULL) {
324                 keyURI = xmlXPathNsLookup(ctxt->context, prefix);
325                 if (keyURI == NULL) {
326                     xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt),
327                                           NULL, NULL);
328                     xsltGenericError(xsltGenericErrorContext,
329                         "key() : prefix %s is not bound\n", prefix);
330                 }
331                 xmlFree(prefix);
332             } else {
333                 keyURI = NULL;
334             }
335         }
336
337         /*
338          * Force conversion of first arg to string
339          */
340         valuePush(ctxt, obj2);
341         xmlXPathStringFunction(ctxt, 1);
342         if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
343             xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt),
344                                   NULL, NULL);
345             xsltGenericError(xsltGenericErrorContext,
346                 "key() : invalid arg expecting a string\n");
347             ctxt->error = XPATH_INVALID_TYPE;
348             xmlXPathFreeObject(obj1);
349
350             return;
351         }
352         obj2 = valuePop(ctxt);
353         value = obj2->stringval;
354
355         tctxt = xsltXPathGetTransformContext(ctxt);
356
357         nodelist = xsltGetKey(tctxt, key, keyURI, value);
358         valuePush(ctxt, xmlXPathWrapNodeSet(
359                         xmlXPathNodeSetMerge(NULL, nodelist)));
360     }
361
362
363     if (obj1 != NULL)
364         xmlXPathFreeObject(obj1);
365     if (obj2 != NULL)
366         xmlXPathFreeObject(obj2);
367     if (key != NULL)
368         xmlFree(key);
369 }
370
371 /**
372  * xsltUnparsedEntityURIFunction:
373  * @ctxt:  the XPath Parser context
374  * @nargs:  the number of arguments
375  *
376  * Implement the unparsed-entity-uri() XSLT function
377  *   string unparsed-entity-uri(string)
378  */
379 void
380 xsltUnparsedEntityURIFunction(xmlXPathParserContextPtr ctxt, int nargs){
381     xmlXPathObjectPtr obj;
382     xmlChar *str;
383
384     if ((nargs != 1) || (ctxt->value == NULL)) {
385         xsltGenericError(xsltGenericErrorContext,
386                 "unparsed-entity-uri() : expects one string arg\n");
387         ctxt->error = XPATH_INVALID_ARITY;
388         return;
389     }
390     obj = valuePop(ctxt);
391     if (obj->type != XPATH_STRING) {
392         obj = xmlXPathConvertString(obj);
393     }
394
395     str = obj->stringval;
396     if (str == NULL) {
397         valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
398     } else {
399         xmlEntityPtr entity;
400
401         entity = xmlGetDocEntity(ctxt->context->doc, str);
402         if (entity == NULL) {
403             valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
404         } else {
405             if (entity->URI != NULL)
406                 valuePush(ctxt, xmlXPathNewString(entity->URI));
407             else
408                 valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
409         }
410     }
411     xmlXPathFreeObject(obj);
412 }
413
414 /**
415  * xsltFormatNumberFunction:
416  * @ctxt:  the XPath Parser context
417  * @nargs:  the number of arguments
418  *
419  * Implement the format-number() XSLT function
420  *   string format-number(number, string, string?)
421  */
422 void
423 xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs)
424 {
425     xmlXPathObjectPtr numberObj = NULL;
426     xmlXPathObjectPtr formatObj = NULL;
427     xmlXPathObjectPtr decimalObj = NULL;
428     xsltStylesheetPtr sheet;
429     xsltDecimalFormatPtr formatValues;
430     xmlChar *result;
431     xsltTransformContextPtr tctxt;
432
433     tctxt = xsltXPathGetTransformContext(ctxt);
434     if (tctxt == NULL)
435         return;
436     sheet = tctxt->style;
437     if (sheet == NULL)
438         return;
439     formatValues = sheet->decimalFormat;
440     
441     switch (nargs) {
442     case 3:
443         CAST_TO_STRING;
444         decimalObj = valuePop(ctxt);
445         formatValues = xsltDecimalFormatGetByName(sheet, decimalObj->stringval);
446         /* Intentional fall-through */
447     case 2:
448         CAST_TO_STRING;
449         formatObj = valuePop(ctxt);
450         CAST_TO_NUMBER;
451         numberObj = valuePop(ctxt);
452         break;
453     default:
454         XP_ERROR(XPATH_INVALID_ARITY);
455     }
456
457     if (xsltFormatNumberConversion(formatValues,
458                                    formatObj->stringval,
459                                    numberObj->floatval,
460                                    &result) == XPATH_EXPRESSION_OK) {
461         valuePush(ctxt, xmlXPathNewString(result));
462         xmlFree(result);
463     }
464     
465     xmlXPathFreeObject(numberObj);
466     xmlXPathFreeObject(formatObj);
467     xmlXPathFreeObject(decimalObj);
468 }
469
470 /**
471  * xsltGenerateIdFunction:
472  * @ctxt:  the XPath Parser context
473  * @nargs:  the number of arguments
474  *
475  * Implement the generate-id() XSLT function
476  *   string generate-id(node-set?)
477  */
478 void
479 xsltGenerateIdFunction(xmlXPathParserContextPtr ctxt, int nargs){
480     xmlNodePtr cur = NULL;
481     unsigned long val;
482     xmlChar str[20];
483
484     if (nargs == 0) {
485         cur = ctxt->context->node;
486     } else if (nargs == 1) {
487         xmlXPathObjectPtr obj;
488         xmlNodeSetPtr nodelist;
489         int i, ret;
490
491         if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) {
492             ctxt->error = XPATH_INVALID_TYPE;
493             xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt),
494                                   NULL, NULL);
495             xsltGenericError(xsltGenericErrorContext,
496                 "generate-id() : invalid arg expecting a node-set\n");
497             return;
498         }
499         obj = valuePop(ctxt);
500         nodelist = obj->nodesetval;
501         if ((nodelist == NULL) || (nodelist->nodeNr <= 0)) {
502             xmlXPathFreeObject(obj);
503             valuePush(ctxt, xmlXPathNewCString(""));
504             return;
505         }
506         cur = nodelist->nodeTab[0];
507         for (i = 1;i < nodelist->nodeNr;i++) {
508             ret = xmlXPathCmpNodes(cur, nodelist->nodeTab[i]);
509             if (ret == -1)
510                 cur = nodelist->nodeTab[i];
511         }
512         xmlXPathFreeObject(obj);
513     } else {
514         xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
515         xsltGenericError(xsltGenericErrorContext,
516                 "generate-id() : invalid number of args %d\n", nargs);
517         ctxt->error = XPATH_INVALID_ARITY;
518         return;
519     }
520     /*
521      * Okay this is ugly but should work, use the NodePtr address
522      * to forge the ID
523      */
524     val = (unsigned long)((char *)cur - (char *)0);
525     val /= sizeof(xmlNode);
526     sprintf((char *)str, "id%ld", val);
527     valuePush(ctxt, xmlXPathNewString(str));
528 }
529
530 /**
531  * xsltSystemPropertyFunction:
532  * @ctxt:  the XPath Parser context
533  * @nargs:  the number of arguments
534  *
535  * Implement the system-property() XSLT function
536  *   object system-property(string)
537  */
538 void
539 xsltSystemPropertyFunction(xmlXPathParserContextPtr ctxt, int nargs){
540     xmlXPathObjectPtr obj;
541     xmlChar *prefix, *name;
542     const xmlChar *nsURI = NULL;
543
544     if (nargs != 1) {
545         xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
546         xsltGenericError(xsltGenericErrorContext,
547                 "system-property() : expects one string arg\n");
548         ctxt->error = XPATH_INVALID_ARITY;
549         return;
550     }
551     if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
552         xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
553         xsltGenericError(xsltGenericErrorContext,
554             "system-property() : invalid arg expecting a string\n");
555         ctxt->error = XPATH_INVALID_TYPE;
556         return;
557     }
558     obj = valuePop(ctxt);
559     if (obj->stringval == NULL) {
560         valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
561     } else {
562         name = xmlSplitQName2(obj->stringval, &prefix);
563         if (name == NULL) {
564             name = xmlStrdup(obj->stringval);
565         } else {
566             nsURI = xmlXPathNsLookup(ctxt->context, prefix);
567             if (nsURI == NULL) {
568                 xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt),
569                                       NULL, NULL);
570                 xsltGenericError(xsltGenericErrorContext,
571                     "system-property() : prefix %s is not bound\n", prefix);
572             }
573         }
574
575         if (xmlStrEqual(nsURI, XSLT_NAMESPACE)) {
576 #ifdef DOCBOOK_XSL_HACK
577             if (xmlStrEqual(name, (const xmlChar *)"vendor")) {
578                 xsltStylesheetPtr sheet;
579                 xsltTransformContextPtr tctxt;
580
581                 tctxt = xsltXPathGetTransformContext(ctxt);
582                 if ((tctxt != NULL) && (tctxt->inst != NULL) &&
583                     (xmlStrEqual(tctxt->inst->name, BAD_CAST "variable")) &&
584                     (tctxt->inst->parent != NULL) &&
585                     (xmlStrEqual(tctxt->inst->parent->name,
586                                  BAD_CAST "template")))
587                     sheet = tctxt->style;
588                 else
589                     sheet = NULL;
590                 if ((sheet != NULL) && (sheet->doc != NULL) &&
591                     (sheet->doc->URL != NULL) &&
592                     (xmlStrstr(sheet->doc->URL,
593                                (const xmlChar *)"chunk") != NULL)) {
594                     valuePush(ctxt, xmlXPathNewString(
595                         (const xmlChar *)"libxslt (SAXON 6.2 compatible)"));
596
597                 } else {
598                     valuePush(ctxt, xmlXPathNewString(
599                         (const xmlChar *)XSLT_DEFAULT_VENDOR));
600                 }
601             } else
602 #else
603             if (xmlStrEqual(name, (const xmlChar *)"vendor")) {
604                 valuePush(ctxt, xmlXPathNewString(
605                           (const xmlChar *)XSLT_DEFAULT_VENDOR));
606             } else
607 #endif
608             if (xmlStrEqual(name, (const xmlChar *)"version")) {
609                 valuePush(ctxt, xmlXPathNewString(
610                     (const xmlChar *)XSLT_DEFAULT_VERSION));
611             } else if (xmlStrEqual(name, (const xmlChar *)"vendor-url")) {
612                 valuePush(ctxt, xmlXPathNewString(
613                     (const xmlChar *)XSLT_DEFAULT_URL));
614             } else {
615                 valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
616             }
617         }
618         if (name != NULL)
619             xmlFree(name);
620         if (prefix != NULL)
621             xmlFree(prefix);
622     }
623     xmlXPathFreeObject(obj);
624 }
625
626 /**
627  * xsltElementAvailableFunction:
628  * @ctxt:  the XPath Parser context
629  * @nargs:  the number of arguments
630  *
631  * Implement the element-available() XSLT function
632  *   boolean element-available(string)
633  */
634 void
635 xsltElementAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){
636     xmlXPathObjectPtr obj;
637     xmlChar *prefix, *name;
638     const xmlChar *nsURI = NULL;
639     xsltTransformContextPtr tctxt;
640
641     if (nargs != 1) {
642         xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
643         xsltGenericError(xsltGenericErrorContext,
644                 "element-available() : expects one string arg\n");
645         ctxt->error = XPATH_INVALID_ARITY;
646         return;
647     }
648     if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
649         xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
650         xsltGenericError(xsltGenericErrorContext,
651             "element-available() : invalid arg expecting a string\n");
652         ctxt->error = XPATH_INVALID_TYPE;
653         return;
654     }
655     obj = valuePop(ctxt);
656     tctxt = xsltXPathGetTransformContext(ctxt);
657     if (tctxt == NULL) {
658         xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
659         xsltGenericError(xsltGenericErrorContext,
660                 "element-available() : internal error tctxt == NULL\n");
661         xmlXPathFreeObject(obj);
662         valuePush(ctxt, xmlXPathNewBoolean(0));
663         return;
664     }
665
666
667     name = xmlSplitQName2(obj->stringval, &prefix);
668     if (name == NULL) {
669         xmlNsPtr ns;
670
671         name = xmlStrdup(obj->stringval);
672         ns = xmlSearchNs(tctxt->inst->doc, tctxt->inst, NULL);
673         nsURI = xmlStrdup(ns->href);
674     } else {
675         nsURI = xmlXPathNsLookup(ctxt->context, prefix);
676         if (nsURI == NULL) {
677             xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt),
678                                   NULL, NULL);
679             xsltGenericError(xsltGenericErrorContext,
680                 "element-available() : prefix %s is not bound\n", prefix);
681         }
682     }
683
684     if (xsltExtElementLookup(tctxt, name, nsURI) != NULL) {
685         valuePush(ctxt, xmlXPathNewBoolean(1));
686     } else {
687         valuePush(ctxt, xmlXPathNewBoolean(0));
688     }
689
690     xmlXPathFreeObject(obj);
691     if (name != NULL)
692         xmlFree(name);
693     if (prefix != NULL)
694         xmlFree(prefix);
695 }
696
697 /**
698  * xsltFunctionAvailableFunction:
699  * @ctxt:  the XPath Parser context
700  * @nargs:  the number of arguments
701  *
702  * Implement the function-available() XSLT function
703  *   boolean function-available(string)
704  */
705 void
706 xsltFunctionAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){
707     xmlXPathObjectPtr obj;
708     xmlChar *prefix, *name;
709     const xmlChar *nsURI = NULL;
710
711     if (nargs != 1) {
712         xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
713         xsltGenericError(xsltGenericErrorContext,
714                 "function-available() : expects one string arg\n");
715         ctxt->error = XPATH_INVALID_ARITY;
716         return;
717     }
718     if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
719         xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
720         xsltGenericError(xsltGenericErrorContext,
721             "function-available() : invalid arg expecting a string\n");
722         ctxt->error = XPATH_INVALID_TYPE;
723         return;
724     }
725     obj = valuePop(ctxt);
726
727     name = xmlSplitQName2(obj->stringval, &prefix);
728     if (name == NULL) {
729         name = xmlStrdup(obj->stringval);
730     } else {
731         nsURI = xmlXPathNsLookup(ctxt->context, prefix);
732         if (nsURI == NULL) {
733             xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt),
734                                   NULL, NULL);
735             xsltGenericError(xsltGenericErrorContext,
736                 "function-available() : prefix %s is not bound\n", prefix);
737         }
738     }
739
740     if (xmlXPathFunctionLookupNS(ctxt->context, name, nsURI) != NULL) {
741         valuePush(ctxt, xmlXPathNewBoolean(1));
742     } else {
743         valuePush(ctxt, xmlXPathNewBoolean(0));
744     }
745
746     xmlXPathFreeObject(obj);
747     if (name != NULL)
748         xmlFree(name);
749     if (prefix != NULL)
750         xmlFree(prefix);
751 }
752
753 /**
754  * xsltCurrentFunction:
755  * @ctxt:  the XPath Parser context
756  * @nargs:  the number of arguments
757  *
758  * Implement the current() XSLT function
759  *   node-set current()
760  */
761 static void
762 xsltCurrentFunction(xmlXPathParserContextPtr ctxt, int nargs){
763     xsltTransformContextPtr tctxt;
764
765     if (nargs != 0) {
766         xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
767         xsltGenericError(xsltGenericErrorContext,
768                 "current() : function uses no argument\n");
769         ctxt->error = XPATH_INVALID_ARITY;
770         return;
771     }
772     tctxt = xsltXPathGetTransformContext(ctxt);
773     if (tctxt == NULL) {
774         xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
775         xsltGenericError(xsltGenericErrorContext,
776                 "current() : internal error tctxt == NULL\n");
777         valuePush(ctxt, xmlXPathNewNodeSet(NULL));
778     } else {
779         valuePush(ctxt, xmlXPathNewNodeSet(tctxt->node)); /* current */
780     }
781 }
782
783 /************************************************************************
784  *                                                                      *
785  *              Registration of XSLT and libxslt functions              *
786  *                                                                      *
787  ************************************************************************/
788
789 /**
790  * xsltRegisterAllFunctions:
791  * @ctxt:  the XPath context
792  *
793  * Registers all default XSLT functions in this context
794  */
795 void
796 xsltRegisterAllFunctions(xmlXPathContextPtr ctxt)
797 {
798     xmlXPathRegisterFunc(ctxt, (const xmlChar *) "current",
799                          xsltCurrentFunction);
800     xmlXPathRegisterFunc(ctxt, (const xmlChar *) "document",
801                          xsltDocumentFunction);
802     xmlXPathRegisterFunc(ctxt, (const xmlChar *) "key", xsltKeyFunction);
803     xmlXPathRegisterFunc(ctxt, (const xmlChar *) "unparsed-entity-uri",
804                          xsltUnparsedEntityURIFunction);
805     xmlXPathRegisterFunc(ctxt, (const xmlChar *) "format-number",
806                          xsltFormatNumberFunction);
807     xmlXPathRegisterFunc(ctxt, (const xmlChar *) "generate-id",
808                          xsltGenerateIdFunction);
809     xmlXPathRegisterFunc(ctxt, (const xmlChar *) "system-property",
810                          xsltSystemPropertyFunction);
811     xmlXPathRegisterFunc(ctxt, (const xmlChar *) "element-available",
812                          xsltElementAvailableFunction);
813     xmlXPathRegisterFunc(ctxt, (const xmlChar *) "function-available",
814                          xsltFunctionAvailableFunction);
815 }