diff options
Diffstat (limited to 'libxslt/extra.c')
-rw-r--r-- | libxslt/extra.c | 332 |
1 files changed, 332 insertions, 0 deletions
diff --git a/libxslt/extra.c b/libxslt/extra.c new file mode 100644 index 0000000..17df4ba --- /dev/null +++ b/libxslt/extra.c @@ -0,0 +1,332 @@ +/* + * extra.c: Implementation of non-standard features + * + * Reference: + * Michael Kay "XSLT Programmer's Reference" pp 637-643 + * The node-set() extension function + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#define IN_LIBXSLT +#include "libxslt.h" + +#include <string.h> +#ifdef HAVE_TIME_H +#include <time.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#include <libxml/xmlmemory.h> +#include <libxml/tree.h> +#include <libxml/hash.h> +#include <libxml/xmlerror.h> +#include <libxml/parserInternals.h> +#include "xslt.h" +#include "xsltInternals.h" +#include "xsltutils.h" +#include "extensions.h" +#include "variables.h" +#include "transform.h" +#include "extra.h" +#include "preproc.h" + +#ifdef WITH_XSLT_DEBUG +#define WITH_XSLT_DEBUG_EXTRA +#endif + +/************************************************************************ + * * + * Handling of XSLT debugging * + * * + ************************************************************************/ + +/** + * xsltDebug: + * @ctxt: an XSLT processing context + * @node: The current node + * @inst: the instruction in the stylesheet + * @comp: precomputed informations + * + * Process an debug node + */ +void +xsltDebug(xsltTransformContextPtr ctxt, xmlNodePtr node ATTRIBUTE_UNUSED, + xmlNodePtr inst ATTRIBUTE_UNUSED, + xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) +{ + int i, j; + + xsltGenericError(xsltGenericErrorContext, "Templates:\n"); + for (i = 0, j = ctxt->templNr - 1; ((i < 15) && (j >= 0)); i++, j--) { + xsltGenericError(xsltGenericErrorContext, "#%d ", i); + if (ctxt->templTab[j]->name != NULL) + xsltGenericError(xsltGenericErrorContext, "name %s ", + ctxt->templTab[j]->name); + if (ctxt->templTab[j]->match != NULL) + xsltGenericError(xsltGenericErrorContext, "name %s ", + ctxt->templTab[j]->match); + if (ctxt->templTab[j]->mode != NULL) + xsltGenericError(xsltGenericErrorContext, "name %s ", + ctxt->templTab[j]->mode); + xsltGenericError(xsltGenericErrorContext, "\n"); + } + xsltGenericError(xsltGenericErrorContext, "Variables:\n"); + for (i = 0, j = ctxt->varsNr - 1; ((i < 15) && (j >= 0)); i++, j--) { + xsltStackElemPtr cur; + + if (ctxt->varsTab[j] == NULL) + continue; + xsltGenericError(xsltGenericErrorContext, "#%d\n", i); + cur = ctxt->varsTab[j]; + while (cur != NULL) { + if (cur->comp == NULL) { + xsltGenericError(xsltGenericErrorContext, + "corrupted !!!\n"); + } else if (cur->comp->type == XSLT_FUNC_PARAM) { + xsltGenericError(xsltGenericErrorContext, "param "); + } else if (cur->comp->type == XSLT_FUNC_VARIABLE) { + xsltGenericError(xsltGenericErrorContext, "var "); + } + if (cur->name != NULL) + xsltGenericError(xsltGenericErrorContext, "%s ", + cur->name); + else + xsltGenericError(xsltGenericErrorContext, "noname !!!!"); +#ifdef LIBXML_DEBUG_ENABLED + if (cur->value != NULL) { + xmlXPathDebugDumpObject(stdout, cur->value, 1); + } else { + xsltGenericError(xsltGenericErrorContext, "NULL !!!!"); + } +#endif + xsltGenericError(xsltGenericErrorContext, "\n"); + cur = cur->next; + } + + } +} + +/************************************************************************ + * * + * Classic extensions as described by M. Kay * + * * + ************************************************************************/ + +/** + * xsltFunctionNodeSet: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the node-set() XSLT function + * node-set node-set(result-tree) + * + * This function is available in libxslt, saxon or xt namespace. + */ +void +xsltFunctionNodeSet(xmlXPathParserContextPtr ctxt, int nargs){ + if (nargs != 1) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "node-set() : expects one result-tree arg\n"); + ctxt->error = XPATH_INVALID_ARITY; + return; + } + if ((ctxt->value == NULL) || + ((ctxt->value->type != XPATH_XSLT_TREE) && + (ctxt->value->type != XPATH_NODESET))) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "node-set() invalid arg expecting a result tree\n"); + ctxt->error = XPATH_INVALID_TYPE; + return; + } + if (ctxt->value->type == XPATH_XSLT_TREE) { + ctxt->value->type = XPATH_NODESET; + } +} + + +/* + * Okay the following really seems unportable and since it's not + * part of any standard I'm not too ashamed to do this + */ +#if defined(linux) || defined(__sun) +#if defined(HAVE_MKTIME) && defined(HAVE_LOCALTIME) && defined(HAVE_ASCTIME) +#define WITH_LOCALTIME + +/** + * xsltFunctionLocalTime: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the localTime XSLT function used by NORM + * string localTime(???) + * + * This function is available in Norm's extension namespace + * Code (and comments) contributed by Norm + */ +static void +xsltFunctionLocalTime(xmlXPathParserContextPtr ctxt, int nargs) { + xmlXPathObjectPtr obj; + char *str; + char digits[5]; + char result[29]; + long int field; + time_t gmt, lmt; + struct tm gmt_tm; + struct tm *local_tm; + + if (nargs != 1) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "localTime() : invalid number of args %d\n", nargs); + ctxt->error = XPATH_INVALID_ARITY; + return; + } + + obj = valuePop(ctxt); + + if (obj->type != XPATH_STRING) { + obj = xmlXPathConvertString(obj); + } + if (obj == NULL) { + valuePush(ctxt, xmlXPathNewString((const xmlChar *)"")); + return; + } + + str = (char *) obj->stringval; + + /* str = "$Date$" */ + memset(digits, 0, sizeof(digits)); + strncpy(digits, str+7, 4); + field = strtol(digits, NULL, 10); + gmt_tm.tm_year = field - 1900; + + memset(digits, 0, sizeof(digits)); + strncpy(digits, str+12, 2); + field = strtol(digits, NULL, 10); + gmt_tm.tm_mon = field - 1; + + memset(digits, 0, sizeof(digits)); + strncpy(digits, str+15, 2); + field = strtol(digits, NULL, 10); + gmt_tm.tm_mday = field; + + memset(digits, 0, sizeof(digits)); + strncpy(digits, str+18, 2); + field = strtol(digits, NULL, 10); + gmt_tm.tm_hour = field; + + memset(digits, 0, sizeof(digits)); + strncpy(digits, str+21, 2); + field = strtol(digits, NULL, 10); + gmt_tm.tm_min = field; + + memset(digits, 0, sizeof(digits)); + strncpy(digits, str+24, 2); + field = strtol(digits, NULL, 10); + gmt_tm.tm_sec = field; + + /* Now turn gmt_tm into a time. */ + gmt = mktime(&gmt_tm); + + + /* + * FIXME: it's been too long since I did manual memory management. + * (I swore never to do it again.) Does this introduce a memory leak? + */ + local_tm = localtime(&gmt); + + /* + * Calling localtime() has the side-effect of setting timezone. + * After we know the timezone, we can adjust for it + */ +#if !defined(__FreeBSD__) + lmt = gmt - timezone; +#else /* FreeBSD DOESN'T have such side-ffect */ + lmt = gmt - local_tm->tm_gmtoff; +#endif + /* + * FIXME: it's been too long since I did manual memory management. + * (I swore never to do it again.) Does this introduce a memory leak? + */ + local_tm = localtime(&lmt); + + /* + * Now convert local_tm back into a string. This doesn't introduce + * a memory leak, so says asctime(3). + */ + + str = asctime(local_tm); /* "Tue Jun 26 05:02:16 2001" */ + /* 0123456789 123456789 123 */ + + memset(result, 0, sizeof(result)); /* "Thu, 26 Jun 2001" */ + /* 0123456789 12345 */ + + strncpy(result, str, 20); + strcpy(result+20, "???"); /* tzname doesn't work, fake it */ + strncpy(result+23, str+19, 5); + + /* Ok, now result contains the string I want to send back. */ + valuePush(ctxt, xmlXPathNewString((xmlChar *)result)); +} +#endif +#endif /* linux or sun */ + + +/** + * xsltRegisterExtras: + * @ctxt: a XSLT process context + * + * Registers the built-in extensions. This function is deprecated, use + * xsltRegisterAllExtras instead. + */ +void +xsltRegisterExtras(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED) { + xsltRegisterAllExtras(); +} + +/** + * xsltRegisterAllExtras: + * + * Registers the built-in extensions + */ +void +xsltRegisterAllExtras (void) { + xsltRegisterExtModuleFunction((const xmlChar *) "node-set", + XSLT_LIBXSLT_NAMESPACE, + xsltFunctionNodeSet); + xsltRegisterExtModuleFunction((const xmlChar *) "node-set", + XSLT_SAXON_NAMESPACE, + xsltFunctionNodeSet); + xsltRegisterExtModuleFunction((const xmlChar *) "node-set", + XSLT_XT_NAMESPACE, + xsltFunctionNodeSet); +#ifdef WITH_LOCALTIME + xsltRegisterExtModuleFunction((const xmlChar *) "localTime", + XSLT_NORM_SAXON_NAMESPACE, + xsltFunctionLocalTime); +#endif + xsltRegisterExtModuleElement((const xmlChar *) "debug", + XSLT_LIBXSLT_NAMESPACE, + NULL, + (xsltTransformFunction) xsltDebug); + xsltRegisterExtModuleElement((const xmlChar *) "output", + XSLT_SAXON_NAMESPACE, + xsltDocumentComp, + (xsltTransformFunction) xsltDocumentElem); + xsltRegisterExtModuleElement((const xmlChar *) "write", + XSLT_XALAN_NAMESPACE, + xsltDocumentComp, + (xsltTransformFunction) xsltDocumentElem); + xsltRegisterExtModuleElement((const xmlChar *) "document", + XSLT_XT_NAMESPACE, + xsltDocumentComp, + (xsltTransformFunction) xsltDocumentElem); + xsltRegisterExtModuleElement((const xmlChar *) "document", + XSLT_NAMESPACE, + xsltDocumentComp, + (xsltTransformFunction) xsltDocumentElem); +} |