1#define IN_LIBEXSLT
2#include "libexslt/libexslt.h"
3
4#if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__)
5#include <win32config.h>
6#else
7#include "config.h"
8#endif
9
10#include <libxml/tree.h>
11#include <libxml/xpath.h>
12#include <libxml/xpathInternals.h>
13#include <libxml/parser.h>
14#include <libxml/encoding.h>
15#include <libxml/uri.h>
16
17#include <libxslt/xsltconfig.h>
18#include <libxslt/xsltutils.h>
19#include <libxslt/xsltInternals.h>
20#include <libxslt/extensions.h>
21
22#include "exslt.h"
23
24/**
25 * exsltStrTokenizeFunction:
26 * @ctxt: an XPath parser context
27 * @nargs: the number of arguments
28 *
29 * Splits up a string on the characters of the delimiter string and returns a
30 * node set of token elements, each containing one token from the string.
31 */
32static void
33exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs)
34{
35    xsltTransformContextPtr tctxt;
36    xmlChar *str, *delimiters, *cur;
37    const xmlChar *token, *delimiter;
38    xmlNodePtr node;
39    xmlDocPtr container;
40    xmlXPathObjectPtr ret = NULL;
41    int clen;
42
43    if ((nargs < 1) || (nargs > 2)) {
44        xmlXPathSetArityError(ctxt);
45        return;
46    }
47
48    if (nargs == 2) {
49        delimiters = xmlXPathPopString(ctxt);
50        if (xmlXPathCheckError(ctxt))
51            return;
52    } else {
53        delimiters = xmlStrdup((const xmlChar *) "\t\r\n ");
54    }
55    if (delimiters == NULL)
56        return;
57
58    str = xmlXPathPopString(ctxt);
59    if (xmlXPathCheckError(ctxt) || (str == NULL)) {
60        xmlFree(delimiters);
61        return;
62    }
63
64    /* Return a result tree fragment */
65    tctxt = xsltXPathGetTransformContext(ctxt);
66    if (tctxt == NULL) {
67        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
68	      "exslt:tokenize : internal error tctxt == NULL\n");
69	goto fail;
70    }
71
72    container = xsltCreateRVT(tctxt);
73    if (container != NULL) {
74        xsltRegisterLocalRVT(tctxt, container);
75        ret = xmlXPathNewNodeSet(NULL);
76        if (ret != NULL) {
77            for (cur = str, token = str; *cur != 0; cur += clen) {
78	        clen = xmlUTF8Size(cur);
79		if (*delimiters == 0) {	/* empty string case */
80		    xmlChar ctmp;
81		    ctmp = *(cur+clen);
82		    *(cur+clen) = 0;
83                    node = xmlNewDocRawNode(container, NULL,
84                                       (const xmlChar *) "token", cur);
85		    xmlAddChild((xmlNodePtr) container, node);
86		    xmlXPathNodeSetAddUnique(ret->nodesetval, node);
87                    *(cur+clen) = ctmp; /* restore the changed byte */
88                    token = cur + clen;
89                } else for (delimiter = delimiters; *delimiter != 0;
90				delimiter += xmlUTF8Size(delimiter)) {
91                    if (!xmlUTF8Charcmp(cur, delimiter)) {
92                        if (cur == token) {
93                            /* discard empty tokens */
94                            token = cur + clen;
95                            break;
96                        }
97                        *cur = 0;	/* terminate the token */
98                        node = xmlNewDocRawNode(container, NULL,
99                                           (const xmlChar *) "token", token);
100			xmlAddChild((xmlNodePtr) container, node);
101			xmlXPathNodeSetAddUnique(ret->nodesetval, node);
102                        *cur = *delimiter; /* restore the changed byte */
103                        token = cur + clen;
104                        break;
105                    }
106                }
107            }
108            if (token != cur) {
109		node = xmlNewDocRawNode(container, NULL,
110				    (const xmlChar *) "token", token);
111                xmlAddChild((xmlNodePtr) container, node);
112	        xmlXPathNodeSetAddUnique(ret->nodesetval, node);
113            }
114	    /*
115	     * Mark it as a function result in order to avoid garbage
116	     * collecting of tree fragments
117	     */
118	    xsltExtensionInstructionResultRegister(tctxt, ret);
119        }
120    }
121
122fail:
123    if (str != NULL)
124        xmlFree(str);
125    if (delimiters != NULL)
126        xmlFree(delimiters);
127    if (ret != NULL)
128        valuePush(ctxt, ret);
129    else
130        valuePush(ctxt, xmlXPathNewNodeSet(NULL));
131}
132
133/**
134 * exsltStrSplitFunction:
135 * @ctxt: an XPath parser context
136 * @nargs: the number of arguments
137 *
138 * Splits up a string on a delimiting string and returns a node set of token
139 * elements, each containing one token from the string.
140 */
141static void
142exsltStrSplitFunction(xmlXPathParserContextPtr ctxt, int nargs) {
143    xsltTransformContextPtr tctxt;
144    xmlChar *str, *delimiter, *cur;
145    const xmlChar *token;
146    xmlNodePtr node;
147    xmlDocPtr container;
148    xmlXPathObjectPtr ret = NULL;
149    int delimiterLength;
150
151    if ((nargs < 1) || (nargs > 2)) {
152        xmlXPathSetArityError(ctxt);
153        return;
154    }
155
156    if (nargs == 2) {
157        delimiter = xmlXPathPopString(ctxt);
158        if (xmlXPathCheckError(ctxt))
159            return;
160    } else {
161        delimiter = xmlStrdup((const xmlChar *) " ");
162    }
163    if (delimiter == NULL)
164        return;
165    delimiterLength = xmlStrlen (delimiter);
166
167    str = xmlXPathPopString(ctxt);
168    if (xmlXPathCheckError(ctxt) || (str == NULL)) {
169        xmlFree(delimiter);
170        return;
171    }
172
173    /* Return a result tree fragment */
174    tctxt = xsltXPathGetTransformContext(ctxt);
175    if (tctxt == NULL) {
176        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
177	      "exslt:tokenize : internal error tctxt == NULL\n");
178	goto fail;
179    }
180
181    /*
182    * OPTIMIZE TODO: We are creating an xmlDoc for every split!
183    */
184    container = xsltCreateRVT(tctxt);
185    if (container != NULL) {
186        xsltRegisterLocalRVT(tctxt, container);
187        ret = xmlXPathNewNodeSet(NULL);
188        if (ret != NULL) {
189            for (cur = str, token = str; *cur != 0; cur++) {
190		if (delimiterLength == 0) {
191		    if (cur != token) {
192			xmlChar tmp = *cur;
193			*cur = 0;
194                        node = xmlNewDocRawNode(container, NULL,
195                                           (const xmlChar *) "token", token);
196			xmlAddChild((xmlNodePtr) container, node);
197			xmlXPathNodeSetAddUnique(ret->nodesetval, node);
198			*cur = tmp;
199			token++;
200		    }
201		}
202		else if (!xmlStrncasecmp(cur, delimiter, delimiterLength)) {
203		    if (cur == token) {
204			/* discard empty tokens */
205			cur = cur + delimiterLength - 1;
206			token = cur + 1;
207			continue;
208		    }
209		    *cur = 0;
210		    node = xmlNewDocRawNode(container, NULL,
211				       (const xmlChar *) "token", token);
212		    xmlAddChild((xmlNodePtr) container, node);
213		    xmlXPathNodeSetAddUnique(ret->nodesetval, node);
214		    *cur = *delimiter;
215		    cur = cur + delimiterLength - 1;
216		    token = cur + 1;
217                }
218            }
219	    if (token != cur) {
220		node = xmlNewDocRawNode(container, NULL,
221				   (const xmlChar *) "token", token);
222		xmlAddChild((xmlNodePtr) container, node);
223		xmlXPathNodeSetAddUnique(ret->nodesetval, node);
224	    }
225	    /*
226	     * Mark it as a function result in order to avoid garbage
227	     * collecting of tree fragments
228	     */
229	    xsltExtensionInstructionResultRegister(tctxt, ret);
230        }
231    }
232
233fail:
234    if (str != NULL)
235        xmlFree(str);
236    if (delimiter != NULL)
237        xmlFree(delimiter);
238    if (ret != NULL)
239        valuePush(ctxt, ret);
240    else
241        valuePush(ctxt, xmlXPathNewNodeSet(NULL));
242}
243
244/**
245 * exsltStrEncodeUriFunction:
246 * @ctxt: an XPath parser context
247 * @nargs: the number of arguments
248 *
249 * URI-Escapes a string
250 */
251static void
252exsltStrEncodeUriFunction (xmlXPathParserContextPtr ctxt, int nargs) {
253    int escape_all = 1, str_len = 0;
254    xmlChar *str = NULL, *ret = NULL, *tmp;
255
256    if ((nargs < 2) || (nargs > 3)) {
257	xmlXPathSetArityError(ctxt);
258	return;
259    }
260
261    if (nargs >= 3) {
262        /* check for UTF-8 if encoding was explicitly given;
263           we don't support anything else yet */
264        tmp = xmlXPathPopString(ctxt);
265        if (xmlUTF8Strlen(tmp) != 5 || xmlStrcmp((const xmlChar *)"UTF-8",tmp)) {
266	    xmlXPathReturnEmptyString(ctxt);
267	    xmlFree(tmp);
268	    return;
269	}
270	xmlFree(tmp);
271    }
272
273    escape_all = xmlXPathPopBoolean(ctxt);
274
275    str = xmlXPathPopString(ctxt);
276    str_len = xmlUTF8Strlen(str);
277
278    if (str_len == 0) {
279	xmlXPathReturnEmptyString(ctxt);
280	xmlFree(str);
281	return;
282    }
283
284    ret = xmlURIEscapeStr(str,(const xmlChar *)(escape_all?"-_.!~*'()":"-_.!~*'();/?:@&=+$,[]"));
285    xmlXPathReturnString(ctxt, ret);
286
287    if (str != NULL)
288	xmlFree(str);
289}
290
291/**
292 * exsltStrDecodeUriFunction:
293 * @ctxt: an XPath parser context
294 * @nargs: the number of arguments
295 *
296 * reverses URI-Escaping of a string
297 */
298static void
299exsltStrDecodeUriFunction (xmlXPathParserContextPtr ctxt, int nargs) {
300    int str_len = 0;
301    xmlChar *str = NULL, *ret = NULL, *tmp;
302
303    if ((nargs < 1) || (nargs > 2)) {
304	xmlXPathSetArityError(ctxt);
305	return;
306    }
307
308    if (nargs >= 2) {
309        /* check for UTF-8 if encoding was explicitly given;
310           we don't support anything else yet */
311        tmp = xmlXPathPopString(ctxt);
312        if (xmlUTF8Strlen(tmp) != 5 || xmlStrcmp((const xmlChar *)"UTF-8",tmp)) {
313	    xmlXPathReturnEmptyString(ctxt);
314	    xmlFree(tmp);
315	    return;
316	}
317	xmlFree(tmp);
318    }
319
320    str = xmlXPathPopString(ctxt);
321    str_len = xmlUTF8Strlen(str);
322
323    if (str_len == 0) {
324	xmlXPathReturnEmptyString(ctxt);
325	xmlFree(str);
326	return;
327    }
328
329    ret = (xmlChar *) xmlURIUnescapeString((const char *)str,0,NULL);
330    if (!xmlCheckUTF8(ret)) {
331	/* FIXME: instead of throwing away the whole URI, we should
332        only discard the invalid sequence(s). How to do that? */
333	xmlXPathReturnEmptyString(ctxt);
334	xmlFree(str);
335	xmlFree(ret);
336	return;
337    }
338
339    xmlXPathReturnString(ctxt, ret);
340
341    if (str != NULL)
342	xmlFree(str);
343}
344
345/**
346 * exsltStrPaddingFunction:
347 * @ctxt: an XPath parser context
348 * @nargs: the number of arguments
349 *
350 * Creates a padding string of a certain length.
351 */
352static void
353exsltStrPaddingFunction (xmlXPathParserContextPtr ctxt, int nargs) {
354    int number, str_len = 0;
355    xmlChar *str = NULL, *ret = NULL, *tmp;
356
357    if ((nargs < 1) || (nargs > 2)) {
358	xmlXPathSetArityError(ctxt);
359	return;
360    }
361
362    if (nargs == 2) {
363	str = xmlXPathPopString(ctxt);
364	str_len = xmlUTF8Strlen(str);
365    }
366    if (str_len == 0) {
367	if (str != NULL) xmlFree(str);
368	str = xmlStrdup((const xmlChar *) " ");
369	str_len = 1;
370    }
371
372    number = (int) xmlXPathPopNumber(ctxt);
373
374    if (number <= 0) {
375	xmlXPathReturnEmptyString(ctxt);
376	xmlFree(str);
377	return;
378    }
379
380    while (number >= str_len) {
381	ret = xmlStrncat(ret, str, str_len);
382	number -= str_len;
383    }
384    tmp = xmlUTF8Strndup (str, number);
385    ret = xmlStrcat(ret, tmp);
386    if (tmp != NULL)
387	xmlFree (tmp);
388
389    xmlXPathReturnString(ctxt, ret);
390
391    if (str != NULL)
392	xmlFree(str);
393}
394
395/**
396 * exsltStrAlignFunction:
397 * @ctxt: an XPath parser context
398 * @nargs: the number of arguments
399 *
400 * Aligns a string within another string.
401 */
402static void
403exsltStrAlignFunction (xmlXPathParserContextPtr ctxt, int nargs) {
404    xmlChar *str, *padding, *alignment, *ret;
405    int str_l, padding_l;
406
407    if ((nargs < 2) || (nargs > 3)) {
408	xmlXPathSetArityError(ctxt);
409	return;
410    }
411
412    if (nargs == 3)
413	alignment = xmlXPathPopString(ctxt);
414    else
415	alignment = NULL;
416
417    padding = xmlXPathPopString(ctxt);
418    str = xmlXPathPopString(ctxt);
419
420    str_l = xmlUTF8Strlen (str);
421    padding_l = xmlUTF8Strlen (padding);
422
423    if (str_l == padding_l) {
424	xmlXPathReturnString (ctxt, str);
425	xmlFree(padding);
426	xmlFree(alignment);
427	return;
428    }
429
430    if (str_l > padding_l) {
431	ret = xmlUTF8Strndup (str, padding_l);
432    } else {
433	if (xmlStrEqual(alignment, (const xmlChar *) "right")) {
434	    ret = xmlUTF8Strndup (padding, padding_l - str_l);
435	    ret = xmlStrcat (ret, str);
436	} else if (xmlStrEqual(alignment, (const xmlChar *) "center")) {
437	    int left = (padding_l - str_l) / 2;
438	    int right_start;
439
440	    ret = xmlUTF8Strndup (padding, left);
441	    ret = xmlStrcat (ret, str);
442
443	    right_start = xmlUTF8Strsize (padding, left + str_l);
444	    ret = xmlStrcat (ret, padding + right_start);
445	} else {
446	    int str_s;
447
448	    str_s = xmlStrlen (str);
449	    ret = xmlStrdup (str);
450	    ret = xmlStrcat (ret, padding + str_s);
451	}
452    }
453
454    xmlXPathReturnString (ctxt, ret);
455
456    xmlFree(str);
457    xmlFree(padding);
458    xmlFree(alignment);
459}
460
461/**
462 * exsltStrConcatFunction:
463 * @ctxt: an XPath parser context
464 * @nargs: the number of arguments
465 *
466 * Takes a node set and returns the concatenation of the string values
467 * of the nodes in that node set.  If the node set is empty, it
468 * returns an empty string.
469 */
470static void
471exsltStrConcatFunction (xmlXPathParserContextPtr ctxt, int nargs) {
472    xmlXPathObjectPtr obj;
473    xmlChar *ret = NULL;
474    int i;
475
476    if (nargs  != 1) {
477	xmlXPathSetArityError(ctxt);
478	return;
479    }
480
481    if (!xmlXPathStackIsNodeSet(ctxt)) {
482	xmlXPathSetTypeError(ctxt);
483	return;
484    }
485
486    obj = valuePop (ctxt);
487
488    if (xmlXPathNodeSetIsEmpty(obj->nodesetval)) {
489	xmlXPathReturnEmptyString(ctxt);
490	return;
491    }
492
493    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
494	xmlChar *tmp;
495	tmp = xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
496
497	ret = xmlStrcat (ret, tmp);
498
499	xmlFree(tmp);
500    }
501
502    xmlXPathFreeObject (obj);
503
504    xmlXPathReturnString(ctxt, ret);
505}
506
507/**
508 * exsltStrReturnString:
509 * @ctxt: an XPath parser context
510 * @str: a string
511 * @len: length of string
512 *
513 * Returns a string as a node set.
514 */
515static int
516exsltStrReturnString(xmlXPathParserContextPtr ctxt, const xmlChar *str,
517                     int len)
518{
519    xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt);
520    xmlDocPtr container;
521    xmlNodePtr text_node;
522    xmlXPathObjectPtr ret;
523
524    container = xsltCreateRVT(tctxt);
525    if (container == NULL) {
526        xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR);
527        return(-1);
528    }
529    xsltRegisterLocalRVT(tctxt, container);
530
531    text_node = xmlNewTextLen(str, len);
532    if (text_node == NULL) {
533        xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR);
534        return(-1);
535    }
536    xmlAddChild((xmlNodePtr) container, text_node);
537
538    ret = xmlXPathNewNodeSet(text_node);
539    if (ret == NULL) {
540        xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR);
541        return(-1);
542    }
543
544    xsltExtensionInstructionResultRegister(tctxt, ret);
545    valuePush(ctxt, ret);
546
547    return(0);
548}
549
550/**
551 * exsltStrReplaceFunction:
552 * @ctxt: an XPath parser context
553 * @nargs: the number of arguments
554 *
555 * Takes a string, and two node sets and returns the string with all strings in
556 * the first node set replaced by all strings in the second node set.
557 */
558static void
559exsltStrReplaceFunction (xmlXPathParserContextPtr ctxt, int nargs) {
560    int i, i_empty, n, slen0, rlen0, *slen, *rlen;
561    void *mem = NULL;
562    const xmlChar *src, *start;
563    xmlChar *string, *search_str = NULL, *replace_str = NULL;
564    xmlChar **search, **replace;
565    xmlNodeSetPtr search_set = NULL, replace_set = NULL;
566    xmlBufferPtr buf;
567
568    if (nargs  != 3) {
569        xmlXPathSetArityError(ctxt);
570        return;
571    }
572
573    /* get replace argument */
574
575    if (!xmlXPathStackIsNodeSet(ctxt))
576        replace_str = xmlXPathPopString(ctxt);
577    else
578        replace_set = xmlXPathPopNodeSet(ctxt);
579
580    if (xmlXPathCheckError(ctxt))
581        goto fail_replace;
582
583    /* get search argument */
584
585    if (!xmlXPathStackIsNodeSet(ctxt)) {
586        search_str = xmlXPathPopString(ctxt);
587        n = 1;
588    }
589    else {
590        search_set = xmlXPathPopNodeSet(ctxt);
591        n = search_set != NULL ? search_set->nodeNr : 0;
592    }
593
594    if (xmlXPathCheckError(ctxt))
595        goto fail_search;
596
597    /* get string argument */
598
599    string = xmlXPathPopString(ctxt);
600    if (xmlXPathCheckError(ctxt))
601        goto fail_string;
602
603    /* check for empty search node list */
604
605    if (n <= 0) {
606        exsltStrReturnString(ctxt, string, xmlStrlen(string));
607        goto done_empty_search;
608    }
609
610    /* allocate memory for string pointer and length arrays */
611
612    if (n == 1) {
613        search = &search_str;
614        replace = &replace_str;
615        slen = &slen0;
616        rlen = &rlen0;
617    }
618    else {
619        mem = xmlMalloc(2 * n * (sizeof(const xmlChar *) + sizeof(int)));
620        if (mem == NULL) {
621            xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR);
622            goto fail_malloc;
623        }
624        search = (xmlChar **) mem;
625        replace = search + n;
626        slen = (int *) (replace + n);
627        rlen = slen + n;
628    }
629
630    /* process arguments */
631
632    i_empty = -1;
633
634    for (i=0; i<n; ++i) {
635        if (search_set != NULL) {
636            search[i] = xmlXPathCastNodeToString(search_set->nodeTab[i]);
637            if (search[i] == NULL) {
638                n = i;
639                goto fail_process_args;
640            }
641        }
642
643        slen[i] = xmlStrlen(search[i]);
644        if (i_empty < 0 && slen[i] == 0)
645            i_empty = i;
646
647        if (replace_set != NULL) {
648            if (i < replace_set->nodeNr) {
649                replace[i] = xmlXPathCastNodeToString(replace_set->nodeTab[i]);
650                if (replace[i] == NULL) {
651                    n = i + 1;
652                    goto fail_process_args;
653                }
654            }
655            else
656                replace[i] = NULL;
657        }
658        else {
659            if (i == 0)
660                replace[i] = replace_str;
661            else
662                replace[i] = NULL;
663        }
664
665        if (replace[i] == NULL)
666            rlen[i] = 0;
667        else
668            rlen[i] = xmlStrlen(replace[i]);
669    }
670
671    if (i_empty >= 0 && rlen[i_empty] == 0)
672        i_empty = -1;
673
674    /* replace operation */
675
676    buf = xmlBufferCreate();
677    if (buf == NULL) {
678        xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR);
679        goto fail_buffer;
680    }
681    src = string;
682    start = string;
683
684    while (*src != 0) {
685        int max_len = 0, i_match = 0;
686
687        for (i=0; i<n; ++i) {
688            if (*src == search[i][0] &&
689                slen[i] > max_len &&
690                xmlStrncmp(src, search[i], slen[i]) == 0)
691            {
692                i_match = i;
693                max_len = slen[i];
694            }
695        }
696
697        if (max_len == 0) {
698            if (i_empty >= 0 && start < src) {
699                if (xmlBufferAdd(buf, start, src - start) ||
700                    xmlBufferAdd(buf, replace[i_empty], rlen[i_empty]))
701                {
702                    xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR);
703                    goto fail_buffer_add;
704                }
705                start = src;
706            }
707
708            src += xmlUTF8Size(src);
709        }
710        else {
711            if ((start < src &&
712                 xmlBufferAdd(buf, start, src - start)) ||
713                (rlen[i_match] &&
714                 xmlBufferAdd(buf, replace[i_match], rlen[i_match])))
715            {
716                xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR);
717                goto fail_buffer_add;
718            }
719
720            src += slen[i_match];
721            start = src;
722        }
723    }
724
725    if (start < src && xmlBufferAdd(buf, start, src - start)) {
726        xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR);
727        goto fail_buffer_add;
728    }
729
730    /* create result node set */
731
732    exsltStrReturnString(ctxt, xmlBufferContent(buf), xmlBufferLength(buf));
733
734    /* clean up */
735
736fail_buffer_add:
737    xmlBufferFree(buf);
738
739fail_buffer:
740fail_process_args:
741    if (search_set != NULL) {
742        for (i=0; i<n; ++i)
743            xmlFree(search[i]);
744    }
745    if (replace_set != NULL) {
746        for (i=0; i<n; ++i) {
747            if (replace[i] != NULL)
748                xmlFree(replace[i]);
749        }
750    }
751
752    if (mem != NULL)
753        xmlFree(mem);
754
755fail_malloc:
756done_empty_search:
757    xmlFree(string);
758
759fail_string:
760    if (search_set != NULL)
761        xmlXPathFreeNodeSet(search_set);
762    else
763        xmlFree(search_str);
764
765fail_search:
766    if (replace_set != NULL)
767        xmlXPathFreeNodeSet(replace_set);
768    else
769        xmlFree(replace_str);
770
771fail_replace:
772    return;
773}
774
775/**
776 * exsltStrRegister:
777 *
778 * Registers the EXSLT - Strings module
779 */
780
781void
782exsltStrRegister (void) {
783    xsltRegisterExtModuleFunction ((const xmlChar *) "tokenize",
784				   EXSLT_STRINGS_NAMESPACE,
785				   exsltStrTokenizeFunction);
786    xsltRegisterExtModuleFunction ((const xmlChar *) "split",
787				   EXSLT_STRINGS_NAMESPACE,
788				   exsltStrSplitFunction);
789    xsltRegisterExtModuleFunction ((const xmlChar *) "encode-uri",
790				   EXSLT_STRINGS_NAMESPACE,
791				   exsltStrEncodeUriFunction);
792    xsltRegisterExtModuleFunction ((const xmlChar *) "decode-uri",
793				   EXSLT_STRINGS_NAMESPACE,
794				   exsltStrDecodeUriFunction);
795    xsltRegisterExtModuleFunction ((const xmlChar *) "padding",
796				   EXSLT_STRINGS_NAMESPACE,
797				   exsltStrPaddingFunction);
798    xsltRegisterExtModuleFunction ((const xmlChar *) "align",
799				   EXSLT_STRINGS_NAMESPACE,
800				   exsltStrAlignFunction);
801    xsltRegisterExtModuleFunction ((const xmlChar *) "concat",
802				   EXSLT_STRINGS_NAMESPACE,
803				   exsltStrConcatFunction);
804    xsltRegisterExtModuleFunction ((const xmlChar *) "replace",
805				   EXSLT_STRINGS_NAMESPACE,
806				   exsltStrReplaceFunction);
807}
808
809/**
810 * exsltStrXpathCtxtRegister:
811 *
812 * Registers the EXSLT - Strings module for use outside XSLT
813 */
814int
815exsltStrXpathCtxtRegister (xmlXPathContextPtr ctxt, const xmlChar *prefix)
816{
817    if (ctxt
818        && prefix
819        && !xmlXPathRegisterNs(ctxt,
820                               prefix,
821                               (const xmlChar *) EXSLT_STRINGS_NAMESPACE)
822        && !xmlXPathRegisterFuncNS(ctxt,
823                                   (const xmlChar *) "encode-uri",
824                                   (const xmlChar *) EXSLT_STRINGS_NAMESPACE,
825                                   exsltStrEncodeUriFunction)
826        && !xmlXPathRegisterFuncNS(ctxt,
827                                   (const xmlChar *) "decode-uri",
828                                   (const xmlChar *) EXSLT_STRINGS_NAMESPACE,
829                                   exsltStrDecodeUriFunction)
830        && !xmlXPathRegisterFuncNS(ctxt,
831                                   (const xmlChar *) "padding",
832                                   (const xmlChar *) EXSLT_STRINGS_NAMESPACE,
833                                   exsltStrPaddingFunction)
834        && !xmlXPathRegisterFuncNS(ctxt,
835                                   (const xmlChar *) "align",
836                                   (const xmlChar *) EXSLT_STRINGS_NAMESPACE,
837                                   exsltStrAlignFunction)
838        && !xmlXPathRegisterFuncNS(ctxt,
839                                   (const xmlChar *) "concat",
840                                   (const xmlChar *) EXSLT_STRINGS_NAMESPACE,
841                                   exsltStrConcatFunction)
842        && !xmlXPathRegisterFuncNS(ctxt,
843                                   (const xmlChar *) "replace",
844                                   (const xmlChar *) EXSLT_STRINGS_NAMESPACE,
845                                   exsltStrReplaceFunction)) {
846        return 0;
847    }
848    return -1;
849}
850