| #define IN_LIBEXSLT |
| #include "libexslt/libexslt.h" |
| |
| #if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__) |
| #include <win32config.h> |
| #else |
| #include "config.h" |
| #endif |
| |
| #include <libxml/tree.h> |
| #include <libxml/xpath.h> |
| #include <libxml/xpathInternals.h> |
| #include <libxml/parser.h> |
| #include <libxml/encoding.h> |
| #include <libxml/uri.h> |
| |
| #include <libxslt/xsltconfig.h> |
| #include <libxslt/xsltutils.h> |
| #include <libxslt/xsltInternals.h> |
| #include <libxslt/extensions.h> |
| |
| #include "exslt.h" |
| |
| /** |
| * exsltStrTokenizeFunction: |
| * @ctxt: an XPath parser context |
| * @nargs: the number of arguments |
| * |
| * Splits up a string on the characters of the delimiter string and returns a |
| * node set of token elements, each containing one token from the string. |
| */ |
| static void |
| exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs) |
| { |
| xsltTransformContextPtr tctxt; |
| xmlChar *str, *delimiters, *cur; |
| const xmlChar *token, *delimiter; |
| xmlNodePtr node; |
| xmlDocPtr container; |
| xmlXPathObjectPtr ret = NULL; |
| int clen; |
| |
| if ((nargs < 1) || (nargs > 2)) { |
| xmlXPathSetArityError(ctxt); |
| return; |
| } |
| |
| if (nargs == 2) { |
| delimiters = xmlXPathPopString(ctxt); |
| if (xmlXPathCheckError(ctxt)) |
| return; |
| } else { |
| delimiters = xmlStrdup((const xmlChar *) "\t\r\n "); |
| } |
| if (delimiters == NULL) |
| return; |
| |
| str = xmlXPathPopString(ctxt); |
| if (xmlXPathCheckError(ctxt) || (str == NULL)) { |
| xmlFree(delimiters); |
| return; |
| } |
| |
| /* Return a result tree fragment */ |
| tctxt = xsltXPathGetTransformContext(ctxt); |
| if (tctxt == NULL) { |
| xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, |
| "exslt:tokenize : internal error tctxt == NULL\n"); |
| goto fail; |
| } |
| |
| container = xsltCreateRVT(tctxt); |
| if (container != NULL) { |
| xsltRegisterLocalRVT(tctxt, container); |
| ret = xmlXPathNewNodeSet(NULL); |
| if (ret != NULL) { |
| for (cur = str, token = str; *cur != 0; cur += clen) { |
| clen = xmlUTF8Size(cur); |
| if (*delimiters == 0) { /* empty string case */ |
| xmlChar ctmp; |
| ctmp = *(cur+clen); |
| *(cur+clen) = 0; |
| node = xmlNewDocRawNode(container, NULL, |
| (const xmlChar *) "token", cur); |
| xmlAddChild((xmlNodePtr) container, node); |
| xmlXPathNodeSetAddUnique(ret->nodesetval, node); |
| *(cur+clen) = ctmp; /* restore the changed byte */ |
| token = cur + clen; |
| } else for (delimiter = delimiters; *delimiter != 0; |
| delimiter += xmlUTF8Size(delimiter)) { |
| if (!xmlUTF8Charcmp(cur, delimiter)) { |
| if (cur == token) { |
| /* discard empty tokens */ |
| token = cur + clen; |
| break; |
| } |
| *cur = 0; /* terminate the token */ |
| node = xmlNewDocRawNode(container, NULL, |
| (const xmlChar *) "token", token); |
| xmlAddChild((xmlNodePtr) container, node); |
| xmlXPathNodeSetAddUnique(ret->nodesetval, node); |
| *cur = *delimiter; /* restore the changed byte */ |
| token = cur + clen; |
| break; |
| } |
| } |
| } |
| if (token != cur) { |
| node = xmlNewDocRawNode(container, NULL, |
| (const xmlChar *) "token", token); |
| xmlAddChild((xmlNodePtr) container, node); |
| xmlXPathNodeSetAddUnique(ret->nodesetval, node); |
| } |
| /* |
| * Mark it as a function result in order to avoid garbage |
| * collecting of tree fragments |
| */ |
| xsltExtensionInstructionResultRegister(tctxt, ret); |
| } |
| } |
| |
| fail: |
| if (str != NULL) |
| xmlFree(str); |
| if (delimiters != NULL) |
| xmlFree(delimiters); |
| if (ret != NULL) |
| valuePush(ctxt, ret); |
| else |
| valuePush(ctxt, xmlXPathNewNodeSet(NULL)); |
| } |
| |
| /** |
| * exsltStrSplitFunction: |
| * @ctxt: an XPath parser context |
| * @nargs: the number of arguments |
| * |
| * Splits up a string on a delimiting string and returns a node set of token |
| * elements, each containing one token from the string. |
| */ |
| static void |
| exsltStrSplitFunction(xmlXPathParserContextPtr ctxt, int nargs) { |
| xsltTransformContextPtr tctxt; |
| xmlChar *str, *delimiter, *cur; |
| const xmlChar *token; |
| xmlNodePtr node; |
| xmlDocPtr container; |
| xmlXPathObjectPtr ret = NULL; |
| int delimiterLength; |
| |
| if ((nargs < 1) || (nargs > 2)) { |
| xmlXPathSetArityError(ctxt); |
| return; |
| } |
| |
| if (nargs == 2) { |
| delimiter = xmlXPathPopString(ctxt); |
| if (xmlXPathCheckError(ctxt)) |
| return; |
| } else { |
| delimiter = xmlStrdup((const xmlChar *) " "); |
| } |
| if (delimiter == NULL) |
| return; |
| delimiterLength = xmlStrlen (delimiter); |
| |
| str = xmlXPathPopString(ctxt); |
| if (xmlXPathCheckError(ctxt) || (str == NULL)) { |
| xmlFree(delimiter); |
| return; |
| } |
| |
| /* Return a result tree fragment */ |
| tctxt = xsltXPathGetTransformContext(ctxt); |
| if (tctxt == NULL) { |
| xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, |
| "exslt:tokenize : internal error tctxt == NULL\n"); |
| goto fail; |
| } |
| |
| /* |
| * OPTIMIZE TODO: We are creating an xmlDoc for every split! |
| */ |
| container = xsltCreateRVT(tctxt); |
| if (container != NULL) { |
| xsltRegisterLocalRVT(tctxt, container); |
| ret = xmlXPathNewNodeSet(NULL); |
| if (ret != NULL) { |
| for (cur = str, token = str; *cur != 0; cur++) { |
| if (delimiterLength == 0) { |
| if (cur != token) { |
| xmlChar tmp = *cur; |
| *cur = 0; |
| node = xmlNewDocRawNode(container, NULL, |
| (const xmlChar *) "token", token); |
| xmlAddChild((xmlNodePtr) container, node); |
| xmlXPathNodeSetAddUnique(ret->nodesetval, node); |
| *cur = tmp; |
| token++; |
| } |
| } |
| else if (!xmlStrncasecmp(cur, delimiter, delimiterLength)) { |
| if (cur == token) { |
| /* discard empty tokens */ |
| cur = cur + delimiterLength - 1; |
| token = cur + 1; |
| continue; |
| } |
| *cur = 0; |
| node = xmlNewDocRawNode(container, NULL, |
| (const xmlChar *) "token", token); |
| xmlAddChild((xmlNodePtr) container, node); |
| xmlXPathNodeSetAddUnique(ret->nodesetval, node); |
| *cur = *delimiter; |
| cur = cur + delimiterLength - 1; |
| token = cur + 1; |
| } |
| } |
| if (token != cur) { |
| node = xmlNewDocRawNode(container, NULL, |
| (const xmlChar *) "token", token); |
| xmlAddChild((xmlNodePtr) container, node); |
| xmlXPathNodeSetAddUnique(ret->nodesetval, node); |
| } |
| /* |
| * Mark it as a function result in order to avoid garbage |
| * collecting of tree fragments |
| */ |
| xsltExtensionInstructionResultRegister(tctxt, ret); |
| } |
| } |
| |
| fail: |
| if (str != NULL) |
| xmlFree(str); |
| if (delimiter != NULL) |
| xmlFree(delimiter); |
| if (ret != NULL) |
| valuePush(ctxt, ret); |
| else |
| valuePush(ctxt, xmlXPathNewNodeSet(NULL)); |
| } |
| |
| /** |
| * exsltStrEncodeUriFunction: |
| * @ctxt: an XPath parser context |
| * @nargs: the number of arguments |
| * |
| * URI-Escapes a string |
| */ |
| static void |
| exsltStrEncodeUriFunction (xmlXPathParserContextPtr ctxt, int nargs) { |
| int escape_all = 1, str_len = 0; |
| xmlChar *str = NULL, *ret = NULL, *tmp; |
| |
| if ((nargs < 2) || (nargs > 3)) { |
| xmlXPathSetArityError(ctxt); |
| return; |
| } |
| |
| if (nargs >= 3) { |
| /* check for UTF-8 if encoding was explicitly given; |
| we don't support anything else yet */ |
| tmp = xmlXPathPopString(ctxt); |
| if (xmlUTF8Strlen(tmp) != 5 || xmlStrcmp((const xmlChar *)"UTF-8",tmp)) { |
| xmlXPathReturnEmptyString(ctxt); |
| xmlFree(tmp); |
| return; |
| } |
| xmlFree(tmp); |
| } |
| |
| escape_all = xmlXPathPopBoolean(ctxt); |
| |
| str = xmlXPathPopString(ctxt); |
| str_len = xmlUTF8Strlen(str); |
| |
| if (str_len == 0) { |
| xmlXPathReturnEmptyString(ctxt); |
| xmlFree(str); |
| return; |
| } |
| |
| ret = xmlURIEscapeStr(str,(const xmlChar *)(escape_all?"-_.!~*'()":"-_.!~*'();/?:@&=+$,[]")); |
| xmlXPathReturnString(ctxt, ret); |
| |
| if (str != NULL) |
| xmlFree(str); |
| } |
| |
| /** |
| * exsltStrDecodeUriFunction: |
| * @ctxt: an XPath parser context |
| * @nargs: the number of arguments |
| * |
| * reverses URI-Escaping of a string |
| */ |
| static void |
| exsltStrDecodeUriFunction (xmlXPathParserContextPtr ctxt, int nargs) { |
| int str_len = 0; |
| xmlChar *str = NULL, *ret = NULL, *tmp; |
| |
| if ((nargs < 1) || (nargs > 2)) { |
| xmlXPathSetArityError(ctxt); |
| return; |
| } |
| |
| if (nargs >= 2) { |
| /* check for UTF-8 if encoding was explicitly given; |
| we don't support anything else yet */ |
| tmp = xmlXPathPopString(ctxt); |
| if (xmlUTF8Strlen(tmp) != 5 || xmlStrcmp((const xmlChar *)"UTF-8",tmp)) { |
| xmlXPathReturnEmptyString(ctxt); |
| xmlFree(tmp); |
| return; |
| } |
| xmlFree(tmp); |
| } |
| |
| str = xmlXPathPopString(ctxt); |
| str_len = xmlUTF8Strlen(str); |
| |
| if (str_len == 0) { |
| xmlXPathReturnEmptyString(ctxt); |
| xmlFree(str); |
| return; |
| } |
| |
| ret = (xmlChar *) xmlURIUnescapeString((const char *)str,0,NULL); |
| if (!xmlCheckUTF8(ret)) { |
| /* FIXME: instead of throwing away the whole URI, we should |
| only discard the invalid sequence(s). How to do that? */ |
| xmlXPathReturnEmptyString(ctxt); |
| xmlFree(str); |
| xmlFree(ret); |
| return; |
| } |
| |
| xmlXPathReturnString(ctxt, ret); |
| |
| if (str != NULL) |
| xmlFree(str); |
| } |
| |
| /** |
| * exsltStrPaddingFunction: |
| * @ctxt: an XPath parser context |
| * @nargs: the number of arguments |
| * |
| * Creates a padding string of a certain length. |
| */ |
| static void |
| exsltStrPaddingFunction (xmlXPathParserContextPtr ctxt, int nargs) { |
| int number, str_len = 0, str_size = 0; |
| xmlChar *str = NULL, *ret = NULL; |
| |
| if ((nargs < 1) || (nargs > 2)) { |
| xmlXPathSetArityError(ctxt); |
| return; |
| } |
| |
| if (nargs == 2) { |
| str = xmlXPathPopString(ctxt); |
| str_len = xmlUTF8Strlen(str); |
| str_size = xmlStrlen(str); |
| } |
| if (str_len == 0) { |
| if (str != NULL) xmlFree(str); |
| str = xmlStrdup((const xmlChar *) " "); |
| str_len = 1; |
| str_size = 1; |
| } |
| |
| number = (int) xmlXPathPopNumber(ctxt); |
| |
| if (number <= 0) { |
| xmlXPathReturnEmptyString(ctxt); |
| xmlFree(str); |
| return; |
| } |
| |
| while (number >= str_len) { |
| ret = xmlStrncat(ret, str, str_size); |
| number -= str_len; |
| } |
| if (number > 0) { |
| str_size = xmlUTF8Strsize(str, number); |
| ret = xmlStrncat(ret, str, str_size); |
| } |
| |
| xmlXPathReturnString(ctxt, ret); |
| |
| if (str != NULL) |
| xmlFree(str); |
| } |
| |
| /** |
| * exsltStrAlignFunction: |
| * @ctxt: an XPath parser context |
| * @nargs: the number of arguments |
| * |
| * Aligns a string within another string. |
| */ |
| static void |
| exsltStrAlignFunction (xmlXPathParserContextPtr ctxt, int nargs) { |
| xmlChar *str, *padding, *alignment, *ret; |
| int str_l, padding_l; |
| |
| if ((nargs < 2) || (nargs > 3)) { |
| xmlXPathSetArityError(ctxt); |
| return; |
| } |
| |
| if (nargs == 3) |
| alignment = xmlXPathPopString(ctxt); |
| else |
| alignment = NULL; |
| |
| padding = xmlXPathPopString(ctxt); |
| str = xmlXPathPopString(ctxt); |
| |
| str_l = xmlUTF8Strlen (str); |
| padding_l = xmlUTF8Strlen (padding); |
| |
| if (str_l == padding_l) { |
| xmlXPathReturnString (ctxt, str); |
| xmlFree(padding); |
| xmlFree(alignment); |
| return; |
| } |
| |
| if (str_l > padding_l) { |
| ret = xmlUTF8Strndup (str, padding_l); |
| } else { |
| if (xmlStrEqual(alignment, (const xmlChar *) "right")) { |
| ret = xmlUTF8Strndup (padding, padding_l - str_l); |
| ret = xmlStrcat (ret, str); |
| } else if (xmlStrEqual(alignment, (const xmlChar *) "center")) { |
| int left = (padding_l - str_l) / 2; |
| int right_start; |
| |
| ret = xmlUTF8Strndup (padding, left); |
| ret = xmlStrcat (ret, str); |
| |
| right_start = xmlUTF8Strsize (padding, left + str_l); |
| ret = xmlStrcat (ret, padding + right_start); |
| } else { |
| int str_s; |
| |
| str_s = xmlUTF8Strsize(padding, str_l); |
| ret = xmlStrdup (str); |
| ret = xmlStrcat (ret, padding + str_s); |
| } |
| } |
| |
| xmlXPathReturnString (ctxt, ret); |
| |
| xmlFree(str); |
| xmlFree(padding); |
| xmlFree(alignment); |
| } |
| |
| /** |
| * exsltStrConcatFunction: |
| * @ctxt: an XPath parser context |
| * @nargs: the number of arguments |
| * |
| * Takes a node set and returns the concatenation of the string values |
| * of the nodes in that node set. If the node set is empty, it |
| * returns an empty string. |
| */ |
| static void |
| exsltStrConcatFunction (xmlXPathParserContextPtr ctxt, int nargs) { |
| xmlXPathObjectPtr obj; |
| xmlChar *ret = NULL; |
| int i; |
| |
| if (nargs != 1) { |
| xmlXPathSetArityError(ctxt); |
| return; |
| } |
| |
| if (!xmlXPathStackIsNodeSet(ctxt)) { |
| xmlXPathSetTypeError(ctxt); |
| return; |
| } |
| |
| obj = valuePop (ctxt); |
| |
| if (xmlXPathNodeSetIsEmpty(obj->nodesetval)) { |
| xmlXPathReturnEmptyString(ctxt); |
| return; |
| } |
| |
| for (i = 0; i < obj->nodesetval->nodeNr; i++) { |
| xmlChar *tmp; |
| tmp = xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]); |
| |
| ret = xmlStrcat (ret, tmp); |
| |
| xmlFree(tmp); |
| } |
| |
| xmlXPathFreeObject (obj); |
| |
| xmlXPathReturnString(ctxt, ret); |
| } |
| |
| /** |
| * exsltStrReturnString: |
| * @ctxt: an XPath parser context |
| * @str: a string |
| * @len: length of string |
| * |
| * Returns a string as a node set. |
| */ |
| static int |
| exsltStrReturnString(xmlXPathParserContextPtr ctxt, const xmlChar *str, |
| int len) |
| { |
| xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt); |
| xmlDocPtr container; |
| xmlNodePtr text_node; |
| xmlXPathObjectPtr ret; |
| |
| container = xsltCreateRVT(tctxt); |
| if (container == NULL) { |
| xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); |
| return(-1); |
| } |
| xsltRegisterLocalRVT(tctxt, container); |
| |
| text_node = xmlNewTextLen(str, len); |
| if (text_node == NULL) { |
| xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); |
| return(-1); |
| } |
| xmlAddChild((xmlNodePtr) container, text_node); |
| |
| ret = xmlXPathNewNodeSet(text_node); |
| if (ret == NULL) { |
| xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); |
| return(-1); |
| } |
| |
| xsltExtensionInstructionResultRegister(tctxt, ret); |
| valuePush(ctxt, ret); |
| |
| return(0); |
| } |
| |
| /** |
| * exsltStrReplaceFunction: |
| * @ctxt: an XPath parser context |
| * @nargs: the number of arguments |
| * |
| * Takes a string, and two node sets and returns the string with all strings in |
| * the first node set replaced by all strings in the second node set. |
| */ |
| static void |
| exsltStrReplaceFunction (xmlXPathParserContextPtr ctxt, int nargs) { |
| int i, i_empty, n, slen0, rlen0, *slen, *rlen; |
| void *mem = NULL; |
| const xmlChar *src, *start; |
| xmlChar *string, *search_str = NULL, *replace_str = NULL; |
| xmlChar **search, **replace; |
| xmlNodeSetPtr search_set = NULL, replace_set = NULL; |
| xmlBufferPtr buf; |
| |
| if (nargs != 3) { |
| xmlXPathSetArityError(ctxt); |
| return; |
| } |
| |
| /* get replace argument */ |
| |
| if (!xmlXPathStackIsNodeSet(ctxt)) |
| replace_str = xmlXPathPopString(ctxt); |
| else |
| replace_set = xmlXPathPopNodeSet(ctxt); |
| |
| if (xmlXPathCheckError(ctxt)) |
| goto fail_replace; |
| |
| /* get search argument */ |
| |
| if (!xmlXPathStackIsNodeSet(ctxt)) { |
| search_str = xmlXPathPopString(ctxt); |
| n = 1; |
| } |
| else { |
| search_set = xmlXPathPopNodeSet(ctxt); |
| n = search_set != NULL ? search_set->nodeNr : 0; |
| } |
| |
| if (xmlXPathCheckError(ctxt)) |
| goto fail_search; |
| |
| /* get string argument */ |
| |
| string = xmlXPathPopString(ctxt); |
| if (xmlXPathCheckError(ctxt)) |
| goto fail_string; |
| |
| /* check for empty search node list */ |
| |
| if (n <= 0) { |
| exsltStrReturnString(ctxt, string, xmlStrlen(string)); |
| goto done_empty_search; |
| } |
| |
| /* allocate memory for string pointer and length arrays */ |
| |
| if (n == 1) { |
| search = &search_str; |
| replace = &replace_str; |
| slen = &slen0; |
| rlen = &rlen0; |
| } |
| else { |
| mem = xmlMalloc(2 * n * (sizeof(const xmlChar *) + sizeof(int))); |
| if (mem == NULL) { |
| xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); |
| goto fail_malloc; |
| } |
| search = (xmlChar **) mem; |
| replace = search + n; |
| slen = (int *) (replace + n); |
| rlen = slen + n; |
| } |
| |
| /* process arguments */ |
| |
| i_empty = -1; |
| |
| for (i=0; i<n; ++i) { |
| if (search_set != NULL) { |
| search[i] = xmlXPathCastNodeToString(search_set->nodeTab[i]); |
| if (search[i] == NULL) { |
| n = i; |
| goto fail_process_args; |
| } |
| } |
| |
| slen[i] = xmlStrlen(search[i]); |
| if (i_empty < 0 && slen[i] == 0) |
| i_empty = i; |
| |
| if (replace_set != NULL) { |
| if (i < replace_set->nodeNr) { |
| replace[i] = xmlXPathCastNodeToString(replace_set->nodeTab[i]); |
| if (replace[i] == NULL) { |
| n = i + 1; |
| goto fail_process_args; |
| } |
| } |
| else |
| replace[i] = NULL; |
| } |
| else { |
| if (i == 0) |
| replace[i] = replace_str; |
| else |
| replace[i] = NULL; |
| } |
| |
| if (replace[i] == NULL) |
| rlen[i] = 0; |
| else |
| rlen[i] = xmlStrlen(replace[i]); |
| } |
| |
| if (i_empty >= 0 && rlen[i_empty] == 0) |
| i_empty = -1; |
| |
| /* replace operation */ |
| |
| buf = xmlBufferCreate(); |
| if (buf == NULL) { |
| xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); |
| goto fail_buffer; |
| } |
| src = string; |
| start = string; |
| |
| while (*src != 0) { |
| int max_len = 0, i_match = 0; |
| |
| for (i=0; i<n; ++i) { |
| if (*src == search[i][0] && |
| slen[i] > max_len && |
| xmlStrncmp(src, search[i], slen[i]) == 0) |
| { |
| i_match = i; |
| max_len = slen[i]; |
| } |
| } |
| |
| if (max_len == 0) { |
| if (i_empty >= 0 && start < src) { |
| if (xmlBufferAdd(buf, start, src - start) || |
| xmlBufferAdd(buf, replace[i_empty], rlen[i_empty])) |
| { |
| xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); |
| goto fail_buffer_add; |
| } |
| start = src; |
| } |
| |
| src += xmlUTF8Size(src); |
| } |
| else { |
| if ((start < src && |
| xmlBufferAdd(buf, start, src - start)) || |
| (rlen[i_match] && |
| xmlBufferAdd(buf, replace[i_match], rlen[i_match]))) |
| { |
| xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); |
| goto fail_buffer_add; |
| } |
| |
| src += slen[i_match]; |
| start = src; |
| } |
| } |
| |
| if (start < src && xmlBufferAdd(buf, start, src - start)) { |
| xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); |
| goto fail_buffer_add; |
| } |
| |
| /* create result node set */ |
| |
| exsltStrReturnString(ctxt, xmlBufferContent(buf), xmlBufferLength(buf)); |
| |
| /* clean up */ |
| |
| fail_buffer_add: |
| xmlBufferFree(buf); |
| |
| fail_buffer: |
| fail_process_args: |
| if (search_set != NULL) { |
| for (i=0; i<n; ++i) |
| xmlFree(search[i]); |
| } |
| if (replace_set != NULL) { |
| for (i=0; i<n; ++i) { |
| if (replace[i] != NULL) |
| xmlFree(replace[i]); |
| } |
| } |
| |
| if (mem != NULL) |
| xmlFree(mem); |
| |
| fail_malloc: |
| done_empty_search: |
| xmlFree(string); |
| |
| fail_string: |
| if (search_set != NULL) |
| xmlXPathFreeNodeSet(search_set); |
| else |
| xmlFree(search_str); |
| |
| fail_search: |
| if (replace_set != NULL) |
| xmlXPathFreeNodeSet(replace_set); |
| else |
| xmlFree(replace_str); |
| |
| fail_replace: |
| return; |
| } |
| |
| /** |
| * exsltStrRegister: |
| * |
| * Registers the EXSLT - Strings module |
| */ |
| |
| void |
| exsltStrRegister (void) { |
| xsltRegisterExtModuleFunction ((const xmlChar *) "tokenize", |
| EXSLT_STRINGS_NAMESPACE, |
| exsltStrTokenizeFunction); |
| xsltRegisterExtModuleFunction ((const xmlChar *) "split", |
| EXSLT_STRINGS_NAMESPACE, |
| exsltStrSplitFunction); |
| xsltRegisterExtModuleFunction ((const xmlChar *) "encode-uri", |
| EXSLT_STRINGS_NAMESPACE, |
| exsltStrEncodeUriFunction); |
| xsltRegisterExtModuleFunction ((const xmlChar *) "decode-uri", |
| EXSLT_STRINGS_NAMESPACE, |
| exsltStrDecodeUriFunction); |
| xsltRegisterExtModuleFunction ((const xmlChar *) "padding", |
| EXSLT_STRINGS_NAMESPACE, |
| exsltStrPaddingFunction); |
| xsltRegisterExtModuleFunction ((const xmlChar *) "align", |
| EXSLT_STRINGS_NAMESPACE, |
| exsltStrAlignFunction); |
| xsltRegisterExtModuleFunction ((const xmlChar *) "concat", |
| EXSLT_STRINGS_NAMESPACE, |
| exsltStrConcatFunction); |
| xsltRegisterExtModuleFunction ((const xmlChar *) "replace", |
| EXSLT_STRINGS_NAMESPACE, |
| exsltStrReplaceFunction); |
| } |
| |
| /** |
| * exsltStrXpathCtxtRegister: |
| * |
| * Registers the EXSLT - Strings module for use outside XSLT |
| */ |
| int |
| exsltStrXpathCtxtRegister (xmlXPathContextPtr ctxt, const xmlChar *prefix) |
| { |
| if (ctxt |
| && prefix |
| && !xmlXPathRegisterNs(ctxt, |
| prefix, |
| (const xmlChar *) EXSLT_STRINGS_NAMESPACE) |
| && !xmlXPathRegisterFuncNS(ctxt, |
| (const xmlChar *) "encode-uri", |
| (const xmlChar *) EXSLT_STRINGS_NAMESPACE, |
| exsltStrEncodeUriFunction) |
| && !xmlXPathRegisterFuncNS(ctxt, |
| (const xmlChar *) "decode-uri", |
| (const xmlChar *) EXSLT_STRINGS_NAMESPACE, |
| exsltStrDecodeUriFunction) |
| && !xmlXPathRegisterFuncNS(ctxt, |
| (const xmlChar *) "padding", |
| (const xmlChar *) EXSLT_STRINGS_NAMESPACE, |
| exsltStrPaddingFunction) |
| && !xmlXPathRegisterFuncNS(ctxt, |
| (const xmlChar *) "align", |
| (const xmlChar *) EXSLT_STRINGS_NAMESPACE, |
| exsltStrAlignFunction) |
| && !xmlXPathRegisterFuncNS(ctxt, |
| (const xmlChar *) "concat", |
| (const xmlChar *) EXSLT_STRINGS_NAMESPACE, |
| exsltStrConcatFunction)) { |
| return 0; |
| } |
| return -1; |
| } |