Sync with trunk head.
[reactos.git] / dll / 3rdparty / 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 #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 }