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