Home | History | Annotate | Download | only in libxslt
      1 /*
      2  * extra.c: Implementation of non-standard features
      3  *
      4  * Reference:
      5  *   Michael Kay "XSLT Programmer's Reference" pp 637-643
      6  *   The node-set() extension function
      7  *
      8  * See Copyright for the status of this software.
      9  *
     10  * daniel (at) veillard.com
     11  */
     12 
     13 #define IN_LIBXSLT
     14 #include "libxslt.h"
     15 
     16 #include <string.h>
     17 #ifdef HAVE_TIME_H
     18 #include <time.h>
     19 #endif
     20 #ifdef HAVE_STDLIB_H
     21 #include <stdlib.h>
     22 #endif
     23 
     24 #include <libxml/xmlmemory.h>
     25 #include <libxml/tree.h>
     26 #include <libxml/hash.h>
     27 #include <libxml/xmlerror.h>
     28 #include <libxml/parserInternals.h>
     29 #include "xslt.h"
     30 #include "xsltInternals.h"
     31 #include "xsltutils.h"
     32 #include "extensions.h"
     33 #include "variables.h"
     34 #include "transform.h"
     35 #include "extra.h"
     36 #include "preproc.h"
     37 
     38 #ifdef WITH_XSLT_DEBUG
     39 #define WITH_XSLT_DEBUG_EXTRA
     40 #endif
     41 
     42 /************************************************************************
     43  * 									*
     44  * 		Handling of XSLT debugging				*
     45  * 									*
     46  ************************************************************************/
     47 
     48 /**
     49  * xsltDebug:
     50  * @ctxt:  an XSLT processing context
     51  * @node:  The current node
     52  * @inst:  the instruction in the stylesheet
     53  * @comp:  precomputed informations
     54  *
     55  * Process an debug node
     56  */
     57 void
     58 xsltDebug(xsltTransformContextPtr ctxt, xmlNodePtr node ATTRIBUTE_UNUSED,
     59           xmlNodePtr inst ATTRIBUTE_UNUSED,
     60           xsltStylePreCompPtr comp ATTRIBUTE_UNUSED)
     61 {
     62     int i, j;
     63 
     64     xsltGenericError(xsltGenericErrorContext, "Templates:\n");
     65     for (i = 0, j = ctxt->templNr - 1; ((i < 15) && (j >= 0)); i++, j--) {
     66         xsltGenericError(xsltGenericErrorContext, "#%d ", i);
     67         if (ctxt->templTab[j]->name != NULL)
     68             xsltGenericError(xsltGenericErrorContext, "name %s ",
     69                              ctxt->templTab[j]->name);
     70         if (ctxt->templTab[j]->match != NULL)
     71             xsltGenericError(xsltGenericErrorContext, "name %s ",
     72                              ctxt->templTab[j]->match);
     73         if (ctxt->templTab[j]->mode != NULL)
     74             xsltGenericError(xsltGenericErrorContext, "name %s ",
     75                              ctxt->templTab[j]->mode);
     76         xsltGenericError(xsltGenericErrorContext, "\n");
     77     }
     78     xsltGenericError(xsltGenericErrorContext, "Variables:\n");
     79     for (i = 0, j = ctxt->varsNr - 1; ((i < 15) && (j >= 0)); i++, j--) {
     80         xsltStackElemPtr cur;
     81 
     82         if (ctxt->varsTab[j] == NULL)
     83             continue;
     84         xsltGenericError(xsltGenericErrorContext, "#%d\n", i);
     85         cur = ctxt->varsTab[j];
     86         while (cur != NULL) {
     87             if (cur->comp == NULL) {
     88                 xsltGenericError(xsltGenericErrorContext,
     89                                  "corrupted !!!\n");
     90             } else if (cur->comp->type == XSLT_FUNC_PARAM) {
     91                 xsltGenericError(xsltGenericErrorContext, "param ");
     92             } else if (cur->comp->type == XSLT_FUNC_VARIABLE) {
     93                 xsltGenericError(xsltGenericErrorContext, "var ");
     94             }
     95             if (cur->name != NULL)
     96                 xsltGenericError(xsltGenericErrorContext, "%s ",
     97                                  cur->name);
     98             else
     99                 xsltGenericError(xsltGenericErrorContext, "noname !!!!");
    100 #ifdef LIBXML_DEBUG_ENABLED
    101             if (cur->value != NULL) {
    102                 xmlXPathDebugDumpObject(stdout, cur->value, 1);
    103             } else {
    104                 xsltGenericError(xsltGenericErrorContext, "NULL !!!!");
    105             }
    106 #endif
    107             xsltGenericError(xsltGenericErrorContext, "\n");
    108             cur = cur->next;
    109         }
    110 
    111     }
    112 }
    113 
    114 /************************************************************************
    115  * 									*
    116  * 		Classic extensions as described by M. Kay		*
    117  * 									*
    118  ************************************************************************/
    119 
    120 /**
    121  * xsltFunctionNodeSet:
    122  * @ctxt:  the XPath Parser context
    123  * @nargs:  the number of arguments
    124  *
    125  * Implement the node-set() XSLT function
    126  *   node-set node-set(result-tree)
    127  *
    128  * This function is available in libxslt, saxon or xt namespace.
    129  */
    130 void
    131 xsltFunctionNodeSet(xmlXPathParserContextPtr ctxt, int nargs){
    132     if (nargs != 1) {
    133 	xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
    134 		"node-set() : expects one result-tree arg\n");
    135 	ctxt->error = XPATH_INVALID_ARITY;
    136 	return;
    137     }
    138     if ((ctxt->value == NULL) ||
    139 	((ctxt->value->type != XPATH_XSLT_TREE) &&
    140 	 (ctxt->value->type != XPATH_NODESET))) {
    141 	xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
    142 	    "node-set() invalid arg expecting a result tree\n");
    143 	ctxt->error = XPATH_INVALID_TYPE;
    144 	return;
    145     }
    146     if (ctxt->value->type == XPATH_XSLT_TREE) {
    147 	ctxt->value->type = XPATH_NODESET;
    148     }
    149 }
    150 
    151 
    152 /*
    153  * Okay the following really seems unportable and since it's not
    154  * part of any standard I'm not too ashamed to do this
    155  */
    156 #if defined(linux) || defined(__sun)
    157 #if defined(HAVE_MKTIME) && defined(HAVE_LOCALTIME) && defined(HAVE_ASCTIME)
    158 #define WITH_LOCALTIME
    159 
    160 /**
    161  * xsltFunctionLocalTime:
    162  * @ctxt:  the XPath Parser context
    163  * @nargs:  the number of arguments
    164  *
    165  * Implement the localTime XSLT function used by NORM
    166  *   string localTime(???)
    167  *
    168  * This function is available in Norm's extension namespace
    169  * Code (and comments) contributed by Norm
    170  */
    171 static void
    172 xsltFunctionLocalTime(xmlXPathParserContextPtr ctxt, int nargs) {
    173     xmlXPathObjectPtr obj;
    174     char *str;
    175     char digits[5];
    176     char result[29];
    177     long int field;
    178     time_t gmt, lmt;
    179     struct tm gmt_tm;
    180     struct tm *local_tm;
    181 
    182     if (nargs != 1) {
    183        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
    184                       "localTime() : invalid number of args %d\n", nargs);
    185        ctxt->error = XPATH_INVALID_ARITY;
    186        return;
    187     }
    188 
    189     obj = valuePop(ctxt);
    190 
    191     if (obj->type != XPATH_STRING) {
    192 	obj = xmlXPathConvertString(obj);
    193     }
    194     if (obj == NULL) {
    195 	valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
    196 	return;
    197     }
    198 
    199     str = (char *) obj->stringval;
    200 
    201     /* str = "$Date$" */
    202     memset(digits, 0, sizeof(digits));
    203     strncpy(digits, str+7, 4);
    204     field = strtol(digits, NULL, 10);
    205     gmt_tm.tm_year = field - 1900;
    206 
    207     memset(digits, 0, sizeof(digits));
    208     strncpy(digits, str+12, 2);
    209     field = strtol(digits, NULL, 10);
    210     gmt_tm.tm_mon = field - 1;
    211 
    212     memset(digits, 0, sizeof(digits));
    213     strncpy(digits, str+15, 2);
    214     field = strtol(digits, NULL, 10);
    215     gmt_tm.tm_mday = field;
    216 
    217     memset(digits, 0, sizeof(digits));
    218     strncpy(digits, str+18, 2);
    219     field = strtol(digits, NULL, 10);
    220     gmt_tm.tm_hour = field;
    221 
    222     memset(digits, 0, sizeof(digits));
    223     strncpy(digits, str+21, 2);
    224     field = strtol(digits, NULL, 10);
    225     gmt_tm.tm_min = field;
    226 
    227     memset(digits, 0, sizeof(digits));
    228     strncpy(digits, str+24, 2);
    229     field = strtol(digits, NULL, 10);
    230     gmt_tm.tm_sec = field;
    231 
    232     /* Now turn gmt_tm into a time. */
    233     gmt = mktime(&gmt_tm);
    234 
    235 
    236     /*
    237      * FIXME: it's been too long since I did manual memory management.
    238      * (I swore never to do it again.) Does this introduce a memory leak?
    239      */
    240     local_tm = localtime(&gmt);
    241 
    242     /*
    243      * Calling localtime() has the side-effect of setting timezone.
    244      * After we know the timezone, we can adjust for it
    245      */
    246     lmt = gmt - timezone;
    247 
    248     /*
    249      * FIXME: it's been too long since I did manual memory management.
    250      * (I swore never to do it again.) Does this introduce a memory leak?
    251      */
    252     local_tm = localtime(&lmt);
    253 
    254     /*
    255      * Now convert local_tm back into a string. This doesn't introduce
    256      * a memory leak, so says asctime(3).
    257      */
    258 
    259     str = asctime(local_tm);           /* "Tue Jun 26 05:02:16 2001" */
    260                                        /*  0123456789 123456789 123 */
    261 
    262     memset(result, 0, sizeof(result)); /* "Thu, 26 Jun 2001" */
    263                                        /*  0123456789 12345 */
    264 
    265     strncpy(result, str, 20);
    266     strcpy(result+20, "???");          /* tzname doesn't work, fake it */
    267     strncpy(result+23, str+19, 5);
    268 
    269     /* Ok, now result contains the string I want to send back. */
    270     valuePush(ctxt, xmlXPathNewString((xmlChar *)result));
    271 }
    272 #endif
    273 #endif /* linux or sun */
    274 
    275 
    276 /**
    277  * xsltRegisterExtras:
    278  * @ctxt:  a XSLT process context
    279  *
    280  * Registers the built-in extensions. This function is deprecated, use
    281  * xsltRegisterAllExtras instead.
    282  */
    283 void
    284 xsltRegisterExtras(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED) {
    285     xsltRegisterAllExtras();
    286 }
    287 
    288 /**
    289  * xsltRegisterAllExtras:
    290  *
    291  * Registers the built-in extensions
    292  */
    293 void
    294 xsltRegisterAllExtras (void) {
    295     xsltRegisterExtModuleFunction((const xmlChar *) "node-set",
    296 				  XSLT_LIBXSLT_NAMESPACE,
    297 				  xsltFunctionNodeSet);
    298     xsltRegisterExtModuleFunction((const xmlChar *) "node-set",
    299 				  XSLT_SAXON_NAMESPACE,
    300 				  xsltFunctionNodeSet);
    301     xsltRegisterExtModuleFunction((const xmlChar *) "node-set",
    302 				  XSLT_XT_NAMESPACE,
    303 				  xsltFunctionNodeSet);
    304 #ifdef WITH_LOCALTIME
    305     xsltRegisterExtModuleFunction((const xmlChar *) "localTime",
    306 				  XSLT_NORM_SAXON_NAMESPACE,
    307 				  xsltFunctionLocalTime);
    308 #endif
    309     xsltRegisterExtModuleElement((const xmlChar *) "debug",
    310 				 XSLT_LIBXSLT_NAMESPACE,
    311 				 NULL,
    312 				 (xsltTransformFunction) xsltDebug);
    313     xsltRegisterExtModuleElement((const xmlChar *) "output",
    314 				 XSLT_SAXON_NAMESPACE,
    315 				 xsltDocumentComp,
    316 				 (xsltTransformFunction) xsltDocumentElem);
    317     xsltRegisterExtModuleElement((const xmlChar *) "write",
    318 				 XSLT_XALAN_NAMESPACE,
    319 				 xsltDocumentComp,
    320 				 (xsltTransformFunction) xsltDocumentElem);
    321     xsltRegisterExtModuleElement((const xmlChar *) "document",
    322 				 XSLT_XT_NAMESPACE,
    323 				 xsltDocumentComp,
    324 				 (xsltTransformFunction) xsltDocumentElem);
    325     xsltRegisterExtModuleElement((const xmlChar *) "document",
    326 				 XSLT_NAMESPACE,
    327 				 xsltDocumentComp,
    328 				 (xsltTransformFunction) xsltDocumentElem);
    329 }
    330