Index: libexslt/exslt.c --- libexslt/exslt.c.orig 2015-05-10 16:11:29.000000000 +0200 +++ libexslt/exslt.c 2017-09-05 11:43:07.765930000 +0200 @@ -36,5 +36,8 @@ exsltDateRegister(); exsltSaxonRegister(); exsltDynRegister(); +#ifdef EXSLT_REGEXP_ENABLED + exsltRegexpRegister(); +#endif } Index: libexslt/exslt.h --- libexslt/exslt.h.orig 2012-09-04 16:26:23.000000000 +0200 +++ libexslt/exslt.h 2017-09-05 11:43:07.766053000 +0200 @@ -83,6 +83,7 @@ EXSLTPUBFUN void EXSLTCALL exsltDateRegister (void); EXSLTPUBFUN void EXSLTCALL exsltSaxonRegister (void); EXSLTPUBFUN void EXSLTCALL exsltDynRegister(void); +EXSLTPUBFUN void EXSLTCALL exsltRegexpRegister(void); EXSLTPUBFUN void EXSLTCALL exsltRegisterAll (void); Index: libexslt/regexp.c --- libexslt/regexp.c.orig 2017-09-05 11:43:07.766222000 +0200 +++ libexslt/regexp.c 2017-09-05 11:43:07.766208000 +0200 @@ -0,0 +1,376 @@ +/* + * regexp.c: Implementation of the EXSLT Regular Expressions module + * References: http://exslt.org/regexp/index.html + * Authors: Joel W. Reed + */ + +#if 0 /* we are embedded */ +#include +#include +#include + +#define IN_LIBEXSLT + +#include +#include +#include +#include +#include +#endif + +#include +#include "pcre.h" + +/** + * EXSLT_REGEXP_NAMESPACE: + * + * Namespace for EXSLT regexp functions + */ +#undef EXSLT_REGEXP_NAMESPACE +#define EXSLT_REGEXP_NAMESPACE ((const xmlChar *)"http://exslt.org/regular-expressions") + +static void +exsltRegexpFlagsFromString( + const xmlChar* flagstr, + int* global, int* flags) +{ + const xmlChar* i = flagstr; + + /* defaults */ + (*flags) = PCRE_UTF8; + (*global) = 0; + + while (*i != '\0') { + if (*i == 'i') + (*flags) |= PCRE_CASELESS; + else if (*i == 'g') + (*global)= 1; + /* TODO: support other flags? */ + i++; + } +} + +static int +exsltRegexpExecute( + xmlXPathParserContextPtr ctxt, + const xmlChar* haystack, const xmlChar *regexp, + int flags, int ovector[], int ovector_len) +{ + int haystack_len = 0; + pcre *compiled_regexp = NULL; + int rc = 0, erroffset = 0; + const char *error = 0; + + compiled_regexp = pcre_compile( + (const char *)regexp, /* the pattern */ + flags, /* default options */ + &error, /* for error message */ + &erroffset, /* for error offset */ + NULL); /* use default character tables */ + if (compiled_regexp == NULL) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "exslt:regexp failed to compile %s (char: %d). %s", regexp, erroffset, error); + return -1; + } + + haystack_len = xmlUTF8Strlen (haystack); + + rc = pcre_exec( + compiled_regexp, /* result of pcre_compile() */ + NULL, /* we didn't study the pattern */ + (const char *)haystack, /* the subject string */ + haystack_len, /* the length of the subject string */ + 0, /* start at offset 0 in the subject */ + 0, /* default options */ + (int*)ovector, /* vector of integers for substring information */ + ovector_len); /* number of elements in the vector (NOT size in bytes) */ + if (rc < -1) { + xsltTransformError(xsltXPathGetTransformContext (ctxt), NULL, NULL, + "exslt:regexp failed to execute %s for %s", regexp, haystack); + rc = 0; + } + + if (compiled_regexp != NULL) + pcre_free(compiled_regexp); + return rc; +} + +/** + * exsltRegexpMatchFunction: + * @ns: + * + * Returns a node set of string matches + */ +static void +exsltRegexpMatchFunction( + xmlXPathParserContextPtr ctxt, + int nargs) +{ + xsltTransformContextPtr tctxt; + xmlNodePtr node; + xmlDocPtr container; + xmlXPathObjectPtr ret = NULL; + xmlChar *haystack, *regexp, *flagstr, *working, *match; + int rc, flags, global, ovector[3]; + + if ((nargs < 1) || (nargs > 3)) { + xmlXPathSetArityError(ctxt); + return; + } + + flagstr = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt) || (flagstr == NULL)) { + return; + } + + regexp = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt) || (regexp == NULL)) { + xmlFree(flagstr); + return; + } + + haystack = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt) || (haystack == NULL)) { + xmlFree(regexp); + xmlFree(flagstr); + return; + } + + /* Return a result tree fragment */ + tctxt = xsltXPathGetTransformContext(ctxt); + if (tctxt == NULL) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "exslt:regexp : internal error tctxt == NULL\n"); + goto fail; + } + + container = xsltCreateRVT(tctxt); + if (container != NULL) { + xsltRegisterTmpRVT(tctxt, container); + ret = xmlXPathNewNodeSet(NULL); + if (ret != NULL) { + ret->boolval = 0; + + exsltRegexpFlagsFromString(flagstr, &global, &flags); + working = haystack; + rc = exsltRegexpExecute(ctxt, working, regexp, flags, + ovector, sizeof(ovector)/sizeof(int)); + + while (rc > 0) { + match = xmlStrsub(working, ovector[0], ovector[1]-ovector[0]); + if (NULL == match) goto fail; + + node = xmlNewDocRawNode(container, NULL, (const xmlChar *)"match", match); + xmlFree(match); + + xmlAddChild((xmlNodePtr) container, node); + xmlXPathNodeSetAddUnique(ret->nodesetval, node); + + if (!global) break; + + working = working + ovector[1]; + rc = exsltRegexpExecute(ctxt, working, regexp, flags, + ovector, sizeof(ovector)/sizeof(int)); + } + } + } + + fail: + if (flagstr != NULL) + xmlFree(flagstr); + if (regexp != NULL) + xmlFree(regexp); + if (haystack != NULL) + xmlFree(haystack); + + if (ret != NULL) + valuePush(ctxt, ret); + else + valuePush(ctxt, xmlXPathNewNodeSet(NULL)); +} + +/** + * exsltRegexpReplaceFunction: + * @ns: + * + * Returns a node set of string matches + */ + +static void +exsltRegexpReplaceFunction( + xmlXPathParserContextPtr ctxt, + int nargs) +{ + xmlChar *haystack, *regexp, *flagstr, *replace, *tmp; + xmlChar *result = NULL, *working, *end; + int rc, flags, global, ovector[3]; + + if ((nargs < 1) || (nargs > 4)) { + xmlXPathSetArityError(ctxt); + return; + } + + replace = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt) || (replace == NULL)) { + return; + } + + flagstr = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt) || (flagstr == NULL)) { + xmlFree(replace); + return; + } + + regexp = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt) || (regexp == NULL)) { + xmlFree(flagstr); + xmlFree(replace); + return; + } + + haystack = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt) || (haystack == NULL)) { + xmlFree(regexp); + xmlFree(flagstr); + xmlFree(replace); + return; + } + + exsltRegexpFlagsFromString(flagstr, &global, &flags); + + working = haystack; + rc = exsltRegexpExecute( + ctxt, working, regexp, flags, + ovector, sizeof(ovector)/sizeof(int)); + + while (rc > 0 ) { + if (0 == ovector[0]) { + if (NULL==result) + result = xmlStrdup(replace); + else + result = xmlStrcat(result, replace); + } + else { + tmp = xmlStrsub(working, 0, ovector[0]); + if (NULL == result) + result = tmp; + else { + result = xmlStrcat(result, tmp); + xmlFree(tmp); + } + result = xmlStrcat(result, replace); + } + + working = working + ovector[1]; + + if (!global) + break; + rc = exsltRegexpExecute( + ctxt, working, regexp, flags, + ovector, sizeof(ovector)/sizeof(int)); + } + + end = haystack + xmlUTF8Strlen(haystack); + if (working < end ) { + if (NULL == result) + result = xmlStrdup(working); + else + result = xmlStrcat(result, working); + } + + if (replace != NULL) + xmlFree(replace); + if (flagstr != NULL) + xmlFree(flagstr); + if (regexp != NULL) + xmlFree(regexp); + if (haystack != NULL) + xmlFree(haystack); + + xmlXPathReturnString(ctxt, result); +} + +/** + * exsltRegexpTestFunction: + * @ns: + * + * returns true if the string given as the first argument + * matches the regular expression given as the second argument + * + */ + +static void +exsltRegexpTestFunction( + xmlXPathParserContextPtr ctxt, + int nargs) +{ + xmlChar *haystack, *regexp_middle, *regexp, *flagstr; + int rc = 0, flags, global, ovector[3]; + + if ((nargs < 1) || (nargs > 3)) { + xmlXPathSetArityError(ctxt); + return; + } + + flagstr = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt) || (flagstr == NULL)) { + return; + } + + regexp_middle = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt) || (regexp_middle == NULL)) { + xmlFree(flagstr); + return; + } + + haystack = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt) || (haystack == NULL)) { + xmlFree(regexp_middle); + xmlFree(flagstr); + return; + } + + /* build the regexp */ + regexp = xmlStrdup((const xmlChar *)"\\A"); + regexp = xmlStrcat(regexp, regexp_middle); + regexp = xmlStrcat(regexp, (const xmlChar *)"\\Z"); + + exsltRegexpFlagsFromString(flagstr, &global, &flags); + rc = exsltRegexpExecute( + ctxt, haystack, regexp, flags, + ovector, sizeof(ovector)/sizeof(int)); + + if (flagstr != NULL) + xmlFree(flagstr); + if (regexp != NULL) + xmlFree(regexp); + if (regexp_middle != NULL) + xmlFree(regexp_middle); + if (haystack != NULL) + xmlFree(haystack); + + xmlXPathReturnBoolean(ctxt, (rc > 0)); +} + +/** + * exsltRegexpRegister: + * + * Registers the EXSLT - Regexp module + */ +void +EXSLTPUBFUN exsltRegexpRegister (void) +{ + xsltRegisterExtModuleFunction( + (const xmlChar *)"match", + EXSLT_REGEXP_NAMESPACE, + exsltRegexpMatchFunction); + xsltRegisterExtModuleFunction( + (const xmlChar *)"replace", + EXSLT_REGEXP_NAMESPACE, + exsltRegexpReplaceFunction); + xsltRegisterExtModuleFunction( + (const xmlChar *)"test", + EXSLT_REGEXP_NAMESPACE, + exsltRegexpTestFunction); +} + Index: libexslt/strings.c --- libexslt/strings.c.orig 2017-08-29 13:20:04.000000000 +0200 +++ libexslt/strings.c 2017-09-05 11:43:07.766383000 +0200 @@ -889,3 +889,8 @@ } return -1; } + +#ifdef EXSLT_REGEXP_ENABLED +#include "regexp.c" +#endif + Index: libxslt/xsltconfig.h.in --- libxslt/xsltconfig.h.in.orig 2016-04-10 14:01:03.000000000 +0200 +++ libxslt/xsltconfig.h.in 2017-09-05 11:43:07.766733000 +0200 @@ -143,8 +143,10 @@ */ #ifdef __GNUC__ #ifdef HAVE_ANSIDECL_H +#ifndef __FreeBSD__ #include #endif +#endif #ifndef ATTRIBUTE_UNUSED #define ATTRIBUTE_UNUSED __attribute__((unused)) #endif