/* * 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 */ #include "precomp.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); }