eae261d06a3137586df14ec830345f1aedbc4345
[platform/upstream/libxslt.git] / libxslt / extra.c
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@veillard.com
11  */
12
13 #include "libxslt.h"
14
15 #include <string.h>
16 #ifdef HAVE_TIME_H
17 #define __USE_XOPEN
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         xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
134         xsltGenericError(xsltGenericErrorContext,
135                 "node-set() : expects one result-tree arg\n");
136         ctxt->error = XPATH_INVALID_ARITY;
137         return;
138     }
139     if ((ctxt->value == NULL) ||
140         ((ctxt->value->type != XPATH_XSLT_TREE) &&
141          (ctxt->value->type != XPATH_NODESET))) {
142         xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
143         xsltGenericError(xsltGenericErrorContext,
144             "node-set() invalid arg expecting a result tree\n");
145         ctxt->error = XPATH_INVALID_TYPE;
146         return;
147     }
148     if (ctxt->value->type == XPATH_XSLT_TREE) {
149         ctxt->value->type = XPATH_NODESET;
150     }
151 }
152
153
154 /*
155  * Okay the following really seems unportable and since it's not
156  * part of any standard I'm not too ashamed to do this
157  */
158 #if defined(linux) || defined(__sun)
159 #if defined(HAVE_MKTIME) && defined(HAVE_LOCALTIME) && defined(HAVE_ASCTIME)
160 #define WITH_LOCALTIME
161
162 /**
163  * xsltFunctionLocalTime:
164  * @ctxt:  the XPath Parser context
165  * @nargs:  the number of arguments
166  *
167  * Implement the localTime XSLT function used by NORM
168  *   string localTime(???)
169  *
170  * This function is available in Norm's extension namespace
171  * Code (and comments) contributed by Norm
172  */
173 static void
174 xsltFunctionLocalTime(xmlXPathParserContextPtr ctxt, int nargs) {
175     xmlXPathObjectPtr obj;
176     char *str;
177     char digits[5];
178     char result[29];
179     long int field;
180     time_t gmt, lmt;
181     struct tm gmt_tm;
182     struct tm *local_tm;
183  
184     if (nargs != 1) {
185        xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
186        xsltGenericError(xsltGenericErrorContext,
187                       "localTime() : invalid number of args %d\n", nargs);
188        ctxt->error = XPATH_INVALID_ARITY;
189        return;
190     }
191  
192     obj = valuePop(ctxt);
193
194     if (obj->type != XPATH_STRING) {
195         obj = xmlXPathConvertString(obj);
196     }
197     if (obj == NULL) {
198         valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
199         return;
200     }
201     
202     str = (char *) obj->stringval;
203
204     /* str = "$Date$" */
205     memset(digits, 0, sizeof(digits));
206     strncpy(digits, str+7, 4);
207     field = strtol(digits, NULL, 10);
208     gmt_tm.tm_year = field - 1900;
209
210     memset(digits, 0, sizeof(digits));
211     strncpy(digits, str+12, 2);
212     field = strtol(digits, NULL, 10);
213     gmt_tm.tm_mon = field - 1;
214
215     memset(digits, 0, sizeof(digits));
216     strncpy(digits, str+15, 2);
217     field = strtol(digits, NULL, 10);
218     gmt_tm.tm_mday = field;
219
220     memset(digits, 0, sizeof(digits));
221     strncpy(digits, str+18, 2);
222     field = strtol(digits, NULL, 10);
223     gmt_tm.tm_hour = field;
224
225     memset(digits, 0, sizeof(digits));
226     strncpy(digits, str+21, 2);
227     field = strtol(digits, NULL, 10);
228     gmt_tm.tm_min = field;
229
230     memset(digits, 0, sizeof(digits));
231     strncpy(digits, str+24, 2);
232     field = strtol(digits, NULL, 10);
233     gmt_tm.tm_sec = field;
234
235     /* Now turn gmt_tm into a time. */
236     gmt = mktime(&gmt_tm);
237
238
239     /*
240      * FIXME: it's been too long since I did manual memory management.
241      * (I swore never to do it again.) Does this introduce a memory leak?
242      */
243     local_tm = localtime(&gmt);
244
245     /*
246      * Calling localtime() has the side-effect of setting timezone.
247      * After we know the timezone, we can adjust for it
248      */
249     lmt = gmt - timezone;
250
251     /*
252      * FIXME: it's been too long since I did manual memory management.
253      * (I swore never to do it again.) Does this introduce a memory leak?
254      */
255     local_tm = localtime(&lmt);
256
257     /*
258      * Now convert local_tm back into a string. This doesn't introduce
259      * a memory leak, so says asctime(3).
260      */
261
262     str = asctime(local_tm);           /* "Tue Jun 26 05:02:16 2001" */
263                                        /*  0123456789 123456789 123 */
264
265     memset(result, 0, sizeof(result)); /* "Thu, 26 Jun 2001" */
266                                        /*  0123456789 12345 */
267
268     strncpy(result, str, 20);
269     strcpy(result+20, "???");          /* tzname doesn't work, fake it */
270     strncpy(result+23, str+19, 5);
271
272     /* Ok, now result contains the string I want to send back. */
273     valuePush(ctxt, xmlXPathNewString((xmlChar *)result));
274 }
275 #endif
276 #endif /* linux or sun */
277
278
279 /**
280  * xsltRegisterExtras:
281  * @ctxt:  a XSLT process context
282  *
283  * Registers the built-in extensions. This function is deprecated, use
284  * xsltRegisterAllExtras instead.
285  */
286 void
287 xsltRegisterExtras(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED) {
288     xsltRegisterAllExtras();
289 }
290
291 /**
292  * xsltRegisterAllExtras:
293  *
294  * Registers the built-in extensions
295  */
296 void
297 xsltRegisterAllExtras (void) {
298     xsltRegisterExtModuleFunction((const xmlChar *) "node-set",
299                                   XSLT_LIBXSLT_NAMESPACE,
300                                   xsltFunctionNodeSet);
301     xsltRegisterExtModuleFunction((const xmlChar *) "node-set",
302                                   XSLT_SAXON_NAMESPACE,
303                                   xsltFunctionNodeSet);
304     xsltRegisterExtModuleFunction((const xmlChar *) "node-set",
305                                   XSLT_XT_NAMESPACE,
306                                   xsltFunctionNodeSet);
307 #ifdef WITH_LOCALTIME
308     xsltRegisterExtModuleFunction((const xmlChar *) "localTime",
309                                   XSLT_NORM_SAXON_NAMESPACE,
310                                   xsltFunctionLocalTime);
311 #endif
312     xsltRegisterExtModuleElement((const xmlChar *) "debug",
313                                  XSLT_LIBXSLT_NAMESPACE,
314                                  NULL,
315                                  (xsltTransformFunction) xsltDebug);
316     xsltRegisterExtModuleElement((const xmlChar *) "output",
317                                  XSLT_SAXON_NAMESPACE,
318                                  xsltDocumentComp,
319                                  (xsltTransformFunction) xsltDocumentElem);
320     xsltRegisterExtModuleElement((const xmlChar *) "write",
321                                  XSLT_XALAN_NAMESPACE,
322                                  xsltDocumentComp,
323                                  (xsltTransformFunction) xsltDocumentElem);
324     xsltRegisterExtModuleElement((const xmlChar *) "document",
325                                  XSLT_XT_NAMESPACE,
326                                  xsltDocumentComp,
327                                  (xsltTransformFunction) xsltDocumentElem);
328     xsltRegisterExtModuleElement((const xmlChar *) "document",
329                                  XSLT_NAMESPACE,
330                                  xsltDocumentComp,
331                                  (xsltTransformFunction) xsltDocumentElem);
332 }