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