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