Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(64)

Side by Side Diff: third_party/libxslt/libxslt/xsltutils.c

Issue 2865973002: Check in the libxslt roll script. (Closed)
Patch Set: Consistent quotes. Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/libxslt/libxslt/xsltutils.h ('k') | third_party/libxslt/libxslt/xsltwin32config.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * xsltutils.c: Utilities for the XSL Transformation 1.0 engine
3 *
4 * Reference:
5 * http://www.w3.org/TR/1999/REC-xslt-19991116
6 *
7 * See Copyright for the status of this software.
8 *
9 * daniel@veillard.com
10 */
11
12 #define IN_LIBXSLT
13 #include "libxslt.h"
14
15 #ifndef XSLT_NEED_TRIO
16 #include <stdio.h>
17 #else
18 #include <trio.h>
19 #endif
20
21 #include <string.h>
22 #include <time.h>
23 #ifdef HAVE_SYS_TIME_H
24 #include <sys/time.h>
25 #endif
26 #ifdef HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29 #ifdef HAVE_STDLIB_H
30 #include <stdlib.h>
31 #endif
32 #include <stdarg.h>
33
34 #include <libxml/xmlmemory.h>
35 #include <libxml/tree.h>
36 #include <libxml/HTMLtree.h>
37 #include <libxml/xmlerror.h>
38 #include <libxml/xmlIO.h>
39 #include "xsltutils.h"
40 #include "templates.h"
41 #include "xsltInternals.h"
42 #include "imports.h"
43 #include "transform.h"
44
45 /* gettimeofday on Windows ??? */
46 #if defined(WIN32) && !defined(__CYGWIN__)
47 #ifdef _MSC_VER
48 #include <winsock2.h>
49 #pragma comment(lib, "ws2_32.lib")
50 #define gettimeofday(p1,p2)
51 #define HAVE_GETTIMEOFDAY
52 #define XSLT_WIN32_PERFORMANCE_COUNTER
53 #endif /* _MS_VER */
54 #endif /* WIN32 */
55
56 /************************************************************************
57 * *
58 * Convenience function *
59 * *
60 ************************************************************************/
61
62 /**
63 * xsltGetCNsProp:
64 * @style: the stylesheet
65 * @node: the node
66 * @name: the attribute name
67 * @nameSpace: the URI of the namespace
68 *
69 * Similar to xmlGetNsProp() but with a slightly different semantic
70 *
71 * Search and get the value of an attribute associated to a node
72 * This attribute has to be anchored in the namespace specified,
73 * or has no namespace and the element is in that namespace.
74 *
75 * This does the entity substitution.
76 * This function looks in DTD attribute declaration for #FIXED or
77 * default declaration values unless DTD use has been turned off.
78 *
79 * Returns the attribute value or NULL if not found. The string is allocated
80 * in the stylesheet dictionary.
81 */
82 const xmlChar *
83 xsltGetCNsProp(xsltStylesheetPtr style, xmlNodePtr node,
84 const xmlChar *name, const xmlChar *nameSpace) {
85 xmlAttrPtr prop;
86 xmlDocPtr doc;
87 xmlNsPtr ns;
88 xmlChar *tmp;
89 const xmlChar *ret;
90
91 if ((node == NULL) || (style == NULL) || (style->dict == NULL))
92 return(NULL);
93
94 if (nameSpace == NULL)
95 return xmlGetProp(node, name);
96
97 if (node->type == XML_NAMESPACE_DECL)
98 return(NULL);
99 if (node->type == XML_ELEMENT_NODE)
100 prop = node->properties;
101 else
102 prop = NULL;
103 while (prop != NULL) {
104 /*
105 * One need to have
106 * - same attribute names
107 * - and the attribute carrying that namespace
108 */
109 if ((xmlStrEqual(prop->name, name)) &&
110 (((prop->ns == NULL) && (node->ns != NULL) &&
111 (xmlStrEqual(node->ns->href, nameSpace))) ||
112 ((prop->ns != NULL) &&
113 (xmlStrEqual(prop->ns->href, nameSpace))))) {
114
115 tmp = xmlNodeListGetString(node->doc, prop->children, 1);
116 if (tmp == NULL)
117 ret = xmlDictLookup(style->dict, BAD_CAST "", 0);
118 else {
119 ret = xmlDictLookup(style->dict, tmp, -1);
120 xmlFree(tmp);
121 }
122 return ret;
123 }
124 prop = prop->next;
125 }
126 tmp = NULL;
127 /*
128 * Check if there is a default declaration in the internal
129 * or external subsets
130 */
131 doc = node->doc;
132 if (doc != NULL) {
133 if (doc->intSubset != NULL) {
134 xmlAttributePtr attrDecl;
135
136 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
137 if ((attrDecl == NULL) && (doc->extSubset != NULL))
138 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
139
140 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
141 /*
142 * The DTD declaration only allows a prefix search
143 */
144 ns = xmlSearchNs(doc, node, attrDecl->prefix);
145 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
146 return(xmlDictLookup(style->dict,
147 attrDecl->defaultValue, -1));
148 }
149 }
150 }
151 return(NULL);
152 }
153 /**
154 * xsltGetNsProp:
155 * @node: the node
156 * @name: the attribute name
157 * @nameSpace: the URI of the namespace
158 *
159 * Similar to xmlGetNsProp() but with a slightly different semantic
160 *
161 * Search and get the value of an attribute associated to a node
162 * This attribute has to be anchored in the namespace specified,
163 * or has no namespace and the element is in that namespace.
164 *
165 * This does the entity substitution.
166 * This function looks in DTD attribute declaration for #FIXED or
167 * default declaration values unless DTD use has been turned off.
168 *
169 * Returns the attribute value or NULL if not found.
170 * It's up to the caller to free the memory.
171 */
172 xmlChar *
173 xsltGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
174 xmlAttrPtr prop;
175 xmlDocPtr doc;
176 xmlNsPtr ns;
177
178 if (node == NULL)
179 return(NULL);
180
181 if (nameSpace == NULL)
182 return xmlGetProp(node, name);
183
184 if (node->type == XML_NAMESPACE_DECL)
185 return(NULL);
186 if (node->type == XML_ELEMENT_NODE)
187 prop = node->properties;
188 else
189 prop = NULL;
190 /*
191 * TODO: Substitute xmlGetProp() for xmlGetNsProp(), since the former
192 * is not namespace-aware and will return an attribute with equal
193 * name regardless of its namespace.
194 * Example:
195 * <xsl:element foo:name="myName"/>
196 * So this would return "myName" even if an attribute @name
197 * in the XSLT was requested.
198 */
199 while (prop != NULL) {
200 /*
201 * One need to have
202 * - same attribute names
203 * - and the attribute carrying that namespace
204 */
205 if ((xmlStrEqual(prop->name, name)) &&
206 (((prop->ns == NULL) && (node->ns != NULL) &&
207 (xmlStrEqual(node->ns->href, nameSpace))) ||
208 ((prop->ns != NULL) &&
209 (xmlStrEqual(prop->ns->href, nameSpace))))) {
210 xmlChar *ret;
211
212 ret = xmlNodeListGetString(node->doc, prop->children, 1);
213 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
214 return(ret);
215 }
216 prop = prop->next;
217 }
218
219 /*
220 * Check if there is a default declaration in the internal
221 * or external subsets
222 */
223 doc = node->doc;
224 if (doc != NULL) {
225 if (doc->intSubset != NULL) {
226 xmlAttributePtr attrDecl;
227
228 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
229 if ((attrDecl == NULL) && (doc->extSubset != NULL))
230 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
231
232 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
233 /*
234 * The DTD declaration only allows a prefix search
235 */
236 ns = xmlSearchNs(doc, node, attrDecl->prefix);
237 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
238 return(xmlStrdup(attrDecl->defaultValue));
239 }
240 }
241 }
242 return(NULL);
243 }
244
245 /**
246 * xsltGetUTF8Char:
247 * @utf: a sequence of UTF-8 encoded bytes
248 * @len: a pointer to @bytes len
249 *
250 * Read one UTF8 Char from @utf
251 * Function copied from libxml2 xmlGetUTF8Char() ... to discard ultimately
252 * and use the original API
253 *
254 * Returns the char value or -1 in case of error and update @len with the
255 * number of bytes used
256 */
257 int
258 xsltGetUTF8Char(const unsigned char *utf, int *len) {
259 unsigned int c;
260
261 if (utf == NULL)
262 goto error;
263 if (len == NULL)
264 goto error;
265 if (*len < 1)
266 goto error;
267
268 c = utf[0];
269 if (c & 0x80) {
270 if (*len < 2)
271 goto error;
272 if ((utf[1] & 0xc0) != 0x80)
273 goto error;
274 if ((c & 0xe0) == 0xe0) {
275 if (*len < 3)
276 goto error;
277 if ((utf[2] & 0xc0) != 0x80)
278 goto error;
279 if ((c & 0xf0) == 0xf0) {
280 if (*len < 4)
281 goto error;
282 if ((c & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
283 goto error;
284 *len = 4;
285 /* 4-byte code */
286 c = (utf[0] & 0x7) << 18;
287 c |= (utf[1] & 0x3f) << 12;
288 c |= (utf[2] & 0x3f) << 6;
289 c |= utf[3] & 0x3f;
290 } else {
291 /* 3-byte code */
292 *len = 3;
293 c = (utf[0] & 0xf) << 12;
294 c |= (utf[1] & 0x3f) << 6;
295 c |= utf[2] & 0x3f;
296 }
297 } else {
298 /* 2-byte code */
299 *len = 2;
300 c = (utf[0] & 0x1f) << 6;
301 c |= utf[1] & 0x3f;
302 }
303 } else {
304 /* 1-byte code */
305 *len = 1;
306 }
307 return(c);
308
309 error:
310 if (len != NULL)
311 *len = 0;
312 return(-1);
313 }
314
315 #ifdef XSLT_REFACTORED
316
317 /**
318 * xsltPointerListAddSize:
319 * @list: the pointer list structure
320 * @item: the item to be stored
321 * @initialSize: the initial size of the list
322 *
323 * Adds an item to the list.
324 *
325 * Returns the position of the added item in the list or
326 * -1 in case of an error.
327 */
328 int
329 xsltPointerListAddSize(xsltPointerListPtr list,
330 void *item,
331 int initialSize)
332 {
333 if (list->items == NULL) {
334 if (initialSize <= 0)
335 initialSize = 1;
336 list->items = (void **) xmlMalloc(
337 initialSize * sizeof(void *));
338 if (list->items == NULL) {
339 xsltGenericError(xsltGenericErrorContext,
340 "xsltPointerListAddSize: memory allocation failure.\n");
341 return(-1);
342 }
343 list->number = 0;
344 list->size = initialSize;
345 } else if (list->size <= list->number) {
346 list->size *= 2;
347 list->items = (void **) xmlRealloc(list->items,
348 list->size * sizeof(void *));
349 if (list->items == NULL) {
350 xsltGenericError(xsltGenericErrorContext,
351 "xsltPointerListAddSize: memory re-allocation failure.\n");
352 list->size = 0;
353 return(-1);
354 }
355 }
356 list->items[list->number++] = item;
357 return(0);
358 }
359
360 /**
361 * xsltPointerListCreate:
362 * @initialSize: the initial size for the list
363 *
364 * Creates an xsltPointerList structure.
365 *
366 * Returns a xsltPointerList structure or NULL in case of an error.
367 */
368 xsltPointerListPtr
369 xsltPointerListCreate(int initialSize)
370 {
371 xsltPointerListPtr ret;
372
373 ret = xmlMalloc(sizeof(xsltPointerList));
374 if (ret == NULL) {
375 xsltGenericError(xsltGenericErrorContext,
376 "xsltPointerListCreate: memory allocation failure.\n");
377 return (NULL);
378 }
379 memset(ret, 0, sizeof(xsltPointerList));
380 if (initialSize > 0) {
381 xsltPointerListAddSize(ret, NULL, initialSize);
382 ret->number = 0;
383 }
384 return (ret);
385 }
386
387 /**
388 * xsltPointerListFree:
389 * @list: pointer to the list to be freed
390 *
391 * Frees the xsltPointerList structure. This does not free
392 * the content of the list.
393 */
394 void
395 xsltPointerListFree(xsltPointerListPtr list)
396 {
397 if (list == NULL)
398 return;
399 if (list->items != NULL)
400 xmlFree(list->items);
401 xmlFree(list);
402 }
403
404 /**
405 * xsltPointerListClear:
406 * @list: pointer to the list to be cleared
407 *
408 * Resets the list, but does not free the allocated array
409 * and does not free the content of the list.
410 */
411 void
412 xsltPointerListClear(xsltPointerListPtr list)
413 {
414 if (list->items != NULL) {
415 xmlFree(list->items);
416 list->items = NULL;
417 }
418 list->number = 0;
419 list->size = 0;
420 }
421
422 #endif /* XSLT_REFACTORED */
423
424 /************************************************************************
425 * *
426 * Handling of XSLT stylesheets messages *
427 * *
428 ************************************************************************/
429
430 /**
431 * xsltMessage:
432 * @ctxt: an XSLT processing context
433 * @node: The current node
434 * @inst: The node containing the message instruction
435 *
436 * Process and xsl:message construct
437 */
438 void
439 xsltMessage(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst) {
440 xmlGenericErrorFunc error = xsltGenericError;
441 void *errctx = xsltGenericErrorContext;
442 xmlChar *prop, *message;
443 int terminate = 0;
444
445 if ((ctxt == NULL) || (inst == NULL))
446 return;
447
448 if (ctxt->error != NULL) {
449 error = ctxt->error;
450 errctx = ctxt->errctx;
451 }
452
453 prop = xmlGetNsProp(inst, (const xmlChar *)"terminate", NULL);
454 if (prop != NULL) {
455 if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
456 terminate = 1;
457 } else if (xmlStrEqual(prop, (const xmlChar *)"no")) {
458 terminate = 0;
459 } else {
460 xsltTransformError(ctxt, NULL, inst,
461 "xsl:message : terminate expecting 'yes' or 'no'\n");
462 }
463 xmlFree(prop);
464 }
465 message = xsltEvalTemplateString(ctxt, node, inst);
466 if (message != NULL) {
467 int len = xmlStrlen(message);
468
469 error(errctx, "%s", (const char *)message);
470 if ((len > 0) && (message[len - 1] != '\n'))
471 error(errctx, "\n");
472 xmlFree(message);
473 }
474 if (terminate)
475 ctxt->state = XSLT_STATE_STOPPED;
476 }
477
478 /************************************************************************
479 * *
480 * Handling of out of context errors *
481 * *
482 ************************************************************************/
483
484 #define XSLT_GET_VAR_STR(msg, str) { \
485 int size; \
486 int chars; \
487 char *larger; \
488 va_list ap; \
489 \
490 str = (char *) xmlMalloc(150); \
491 if (str == NULL) \
492 return; \
493 \
494 size = 150; \
495 \
496 while (size < 64000) { \
497 va_start(ap, msg); \
498 chars = vsnprintf(str, size, msg, ap); \
499 va_end(ap); \
500 if ((chars > -1) && (chars < size)) \
501 break; \
502 if (chars > -1) \
503 size += chars + 1; \
504 else \
505 size += 100; \
506 if ((larger = (char *) xmlRealloc(str, size)) == NULL) {\
507 xmlFree(str); \
508 return; \
509 } \
510 str = larger; \
511 } \
512 }
513 /**
514 * xsltGenericErrorDefaultFunc:
515 * @ctx: an error context
516 * @msg: the message to display/transmit
517 * @...: extra parameters for the message display
518 *
519 * Default handler for out of context error messages.
520 */
521 static void LIBXSLT_ATTR_FORMAT(2,3)
522 xsltGenericErrorDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
523 va_list args;
524
525 if (xsltGenericErrorContext == NULL)
526 xsltGenericErrorContext = (void *) stderr;
527
528 va_start(args, msg);
529 vfprintf((FILE *)xsltGenericErrorContext, msg, args);
530 va_end(args);
531 }
532
533 xmlGenericErrorFunc xsltGenericError = xsltGenericErrorDefaultFunc;
534 void *xsltGenericErrorContext = NULL;
535
536
537 /**
538 * xsltSetGenericErrorFunc:
539 * @ctx: the new error handling context
540 * @handler: the new handler function
541 *
542 * Function to reset the handler and the error context for out of
543 * context error messages.
544 * This simply means that @handler will be called for subsequent
545 * error messages while not parsing nor validating. And @ctx will
546 * be passed as first argument to @handler
547 * One can simply force messages to be emitted to another FILE * than
548 * stderr by setting @ctx to this file handle and @handler to NULL.
549 */
550 void
551 xsltSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) {
552 xsltGenericErrorContext = ctx;
553 if (handler != NULL)
554 xsltGenericError = handler;
555 else
556 xsltGenericError = xsltGenericErrorDefaultFunc;
557 }
558
559 /**
560 * xsltGenericDebugDefaultFunc:
561 * @ctx: an error context
562 * @msg: the message to display/transmit
563 * @...: extra parameters for the message display
564 *
565 * Default handler for out of context error messages.
566 */
567 static void LIBXSLT_ATTR_FORMAT(2,3)
568 xsltGenericDebugDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
569 va_list args;
570
571 if (xsltGenericDebugContext == NULL)
572 return;
573
574 va_start(args, msg);
575 vfprintf((FILE *)xsltGenericDebugContext, msg, args);
576 va_end(args);
577 }
578
579 xmlGenericErrorFunc xsltGenericDebug = xsltGenericDebugDefaultFunc;
580 void *xsltGenericDebugContext = NULL;
581
582
583 /**
584 * xsltSetGenericDebugFunc:
585 * @ctx: the new error handling context
586 * @handler: the new handler function
587 *
588 * Function to reset the handler and the error context for out of
589 * context error messages.
590 * This simply means that @handler will be called for subsequent
591 * error messages while not parsing or validating. And @ctx will
592 * be passed as first argument to @handler
593 * One can simply force messages to be emitted to another FILE * than
594 * stderr by setting @ctx to this file handle and @handler to NULL.
595 */
596 void
597 xsltSetGenericDebugFunc(void *ctx, xmlGenericErrorFunc handler) {
598 xsltGenericDebugContext = ctx;
599 if (handler != NULL)
600 xsltGenericDebug = handler;
601 else
602 xsltGenericDebug = xsltGenericDebugDefaultFunc;
603 }
604
605 /**
606 * xsltPrintErrorContext:
607 * @ctxt: the transformation context
608 * @style: the stylesheet
609 * @node: the current node being processed
610 *
611 * Display the context of an error.
612 */
613 void
614 xsltPrintErrorContext(xsltTransformContextPtr ctxt,
615 xsltStylesheetPtr style, xmlNodePtr node) {
616 int line = 0;
617 const xmlChar *file = NULL;
618 const xmlChar *name = NULL;
619 const char *type = "error";
620 xmlGenericErrorFunc error = xsltGenericError;
621 void *errctx = xsltGenericErrorContext;
622
623 if (ctxt != NULL) {
624 if (ctxt->state == XSLT_STATE_OK)
625 ctxt->state = XSLT_STATE_ERROR;
626 if (ctxt->error != NULL) {
627 error = ctxt->error;
628 errctx = ctxt->errctx;
629 }
630 }
631 if ((node == NULL) && (ctxt != NULL))
632 node = ctxt->inst;
633
634 if (node != NULL) {
635 if ((node->type == XML_DOCUMENT_NODE) ||
636 (node->type == XML_HTML_DOCUMENT_NODE)) {
637 xmlDocPtr doc = (xmlDocPtr) node;
638
639 file = doc->URL;
640 } else {
641 line = xmlGetLineNo(node);
642 if ((node->doc != NULL) && (node->doc->URL != NULL))
643 file = node->doc->URL;
644 if (node->name != NULL)
645 name = node->name;
646 }
647 }
648
649 if (ctxt != NULL)
650 type = "runtime error";
651 else if (style != NULL) {
652 #ifdef XSLT_REFACTORED
653 if (XSLT_CCTXT(style)->errSeverity == XSLT_ERROR_SEVERITY_WARNING)
654 type = "compilation warning";
655 else
656 type = "compilation error";
657 #else
658 type = "compilation error";
659 #endif
660 }
661
662 if ((file != NULL) && (line != 0) && (name != NULL))
663 error(errctx, "%s: file %s line %d element %s\n",
664 type, file, line, name);
665 else if ((file != NULL) && (name != NULL))
666 error(errctx, "%s: file %s element %s\n", type, file, name);
667 else if ((file != NULL) && (line != 0))
668 error(errctx, "%s: file %s line %d\n", type, file, line);
669 else if (file != NULL)
670 error(errctx, "%s: file %s\n", type, file);
671 else if (name != NULL)
672 error(errctx, "%s: element %s\n", type, name);
673 else
674 error(errctx, "%s\n", type);
675 }
676
677 /**
678 * xsltSetTransformErrorFunc:
679 * @ctxt: the XSLT transformation context
680 * @ctx: the new error handling context
681 * @handler: the new handler function
682 *
683 * Function to reset the handler and the error context for out of
684 * context error messages specific to a given XSLT transromation.
685 *
686 * This simply means that @handler will be called for subsequent
687 * error messages while running the transformation.
688 */
689 void
690 xsltSetTransformErrorFunc(xsltTransformContextPtr ctxt,
691 void *ctx, xmlGenericErrorFunc handler)
692 {
693 ctxt->error = handler;
694 ctxt->errctx = ctx;
695 }
696
697 /**
698 * xsltTransformError:
699 * @ctxt: an XSLT transformation context
700 * @style: the XSLT stylesheet used
701 * @node: the current node in the stylesheet
702 * @msg: the message to display/transmit
703 * @...: extra parameters for the message display
704 *
705 * Display and format an error messages, gives file, line, position and
706 * extra parameters, will use the specific transformation context if available
707 */
708 void
709 xsltTransformError(xsltTransformContextPtr ctxt,
710 xsltStylesheetPtr style,
711 xmlNodePtr node,
712 const char *msg, ...) {
713 xmlGenericErrorFunc error = xsltGenericError;
714 void *errctx = xsltGenericErrorContext;
715 char * str;
716
717 if (ctxt != NULL) {
718 if (ctxt->state == XSLT_STATE_OK)
719 ctxt->state = XSLT_STATE_ERROR;
720 if (ctxt->error != NULL) {
721 error = ctxt->error;
722 errctx = ctxt->errctx;
723 }
724 }
725 if ((node == NULL) && (ctxt != NULL))
726 node = ctxt->inst;
727 xsltPrintErrorContext(ctxt, style, node);
728 XSLT_GET_VAR_STR(msg, str);
729 error(errctx, "%s", str);
730 if (str != NULL)
731 xmlFree(str);
732 }
733
734 /************************************************************************
735 * *
736 * QNames *
737 * *
738 ************************************************************************/
739
740 /**
741 * xsltSplitQName:
742 * @dict: a dictionary
743 * @name: the full QName
744 * @prefix: the return value
745 *
746 * Split QNames into prefix and local names, both allocated from a dictionary.
747 *
748 * Returns: the localname or NULL in case of error.
749 */
750 const xmlChar *
751 xsltSplitQName(xmlDictPtr dict, const xmlChar *name, const xmlChar **prefix) {
752 int len = 0;
753 const xmlChar *ret = NULL;
754
755 *prefix = NULL;
756 if ((name == NULL) || (dict == NULL)) return(NULL);
757 if (name[0] == ':')
758 return(xmlDictLookup(dict, name, -1));
759 while ((name[len] != 0) && (name[len] != ':')) len++;
760 if (name[len] == 0) return(xmlDictLookup(dict, name, -1));
761 *prefix = xmlDictLookup(dict, name, len);
762 ret = xmlDictLookup(dict, &name[len + 1], -1);
763 return(ret);
764 }
765
766 /**
767 * xsltGetQNameURI:
768 * @node: the node holding the QName
769 * @name: pointer to the initial QName value
770 *
771 * This function analyzes @name, if the name contains a prefix,
772 * the function seaches the associated namespace in scope for it.
773 * It will also replace @name value with the NCName, the old value being
774 * freed.
775 * Errors in the prefix lookup are signalled by setting @name to NULL.
776 *
777 * NOTE: the namespace returned is a pointer to the place where it is
778 * defined and hence has the same lifespan as the document holding it.
779 *
780 * Returns the namespace URI if there is a prefix, or NULL if @name is
781 * not prefixed.
782 */
783 const xmlChar *
784 xsltGetQNameURI(xmlNodePtr node, xmlChar ** name)
785 {
786 int len = 0;
787 xmlChar *qname;
788 xmlNsPtr ns;
789
790 if (name == NULL)
791 return(NULL);
792 qname = *name;
793 if ((qname == NULL) || (*qname == 0))
794 return(NULL);
795 if (node == NULL) {
796 xsltGenericError(xsltGenericErrorContext,
797 "QName: no element for namespace lookup %s\n",
798 qname);
799 xmlFree(qname);
800 *name = NULL;
801 return(NULL);
802 }
803
804 /* nasty but valid */
805 if (qname[0] == ':')
806 return(NULL);
807
808 /*
809 * we are not trying to validate but just to cut, and yes it will
810 * work even if this is a set of UTF-8 encoded chars
811 */
812 while ((qname[len] != 0) && (qname[len] != ':'))
813 len++;
814
815 if (qname[len] == 0)
816 return(NULL);
817
818 /*
819 * handle xml: separately, this one is magical
820 */
821 if ((qname[0] == 'x') && (qname[1] == 'm') &&
822 (qname[2] == 'l') && (qname[3] == ':')) {
823 if (qname[4] == 0)
824 return(NULL);
825 *name = xmlStrdup(&qname[4]);
826 xmlFree(qname);
827 return(XML_XML_NAMESPACE);
828 }
829
830 qname[len] = 0;
831 ns = xmlSearchNs(node->doc, node, qname);
832 if (ns == NULL) {
833 xsltGenericError(xsltGenericErrorContext,
834 "%s:%s : no namespace bound to prefix %s\n",
835 qname, &qname[len + 1], qname);
836 *name = NULL;
837 xmlFree(qname);
838 return(NULL);
839 }
840 *name = xmlStrdup(&qname[len + 1]);
841 xmlFree(qname);
842 return(ns->href);
843 }
844
845 /**
846 * xsltGetQNameURI2:
847 * @style: stylesheet pointer
848 * @node: the node holding the QName
849 * @name: pointer to the initial QName value
850 *
851 * This function is similar to xsltGetQNameURI, but is used when
852 * @name is a dictionary entry.
853 *
854 * Returns the namespace URI if there is a prefix, or NULL if @name is
855 * not prefixed.
856 */
857 const xmlChar *
858 xsltGetQNameURI2(xsltStylesheetPtr style, xmlNodePtr node,
859 const xmlChar **name) {
860 int len = 0;
861 xmlChar *qname;
862 xmlNsPtr ns;
863
864 if (name == NULL)
865 return(NULL);
866 qname = (xmlChar *)*name;
867 if ((qname == NULL) || (*qname == 0))
868 return(NULL);
869 if (node == NULL) {
870 xsltGenericError(xsltGenericErrorContext,
871 "QName: no element for namespace lookup %s\n",
872 qname);
873 *name = NULL;
874 return(NULL);
875 }
876
877 /*
878 * we are not trying to validate but just to cut, and yes it will
879 * work even if this is a set of UTF-8 encoded chars
880 */
881 while ((qname[len] != 0) && (qname[len] != ':'))
882 len++;
883
884 if (qname[len] == 0)
885 return(NULL);
886
887 /*
888 * handle xml: separately, this one is magical
889 */
890 if ((qname[0] == 'x') && (qname[1] == 'm') &&
891 (qname[2] == 'l') && (qname[3] == ':')) {
892 if (qname[4] == 0)
893 return(NULL);
894 *name = xmlDictLookup(style->dict, &qname[4], -1);
895 return(XML_XML_NAMESPACE);
896 }
897
898 qname = xmlStrndup(*name, len);
899 ns = xmlSearchNs(node->doc, node, qname);
900 if (ns == NULL) {
901 if (style) {
902 xsltTransformError(NULL, style, node,
903 "No namespace bound to prefix '%s'.\n",
904 qname);
905 style->errors++;
906 } else {
907 xsltGenericError(xsltGenericErrorContext,
908 "%s : no namespace bound to prefix %s\n",
909 *name, qname);
910 }
911 *name = NULL;
912 xmlFree(qname);
913 return(NULL);
914 }
915 *name = xmlDictLookup(style->dict, (*name)+len+1, -1);
916 xmlFree(qname);
917 return(ns->href);
918 }
919
920 /************************************************************************
921 * *
922 * Sorting *
923 * *
924 ************************************************************************/
925
926 /**
927 * xsltDocumentSortFunction:
928 * @list: the node set
929 *
930 * reorder the current node list @list accordingly to the document order
931 * This function is slow, obsolete and should not be used anymore.
932 */
933 void
934 xsltDocumentSortFunction(xmlNodeSetPtr list) {
935 int i, j;
936 int len, tst;
937 xmlNodePtr node;
938
939 if (list == NULL)
940 return;
941 len = list->nodeNr;
942 if (len <= 1)
943 return;
944 /* TODO: sort is really not optimized, does it needs to ? */
945 for (i = 0;i < len -1;i++) {
946 for (j = i + 1; j < len; j++) {
947 tst = xmlXPathCmpNodes(list->nodeTab[i], list->nodeTab[j]);
948 if (tst == -1) {
949 node = list->nodeTab[i];
950 list->nodeTab[i] = list->nodeTab[j];
951 list->nodeTab[j] = node;
952 }
953 }
954 }
955 }
956
957 /**
958 * xsltComputeSortResult:
959 * @ctxt: a XSLT process context
960 * @sort: node list
961 *
962 * reorder the current node list accordingly to the set of sorting
963 * requirement provided by the array of nodes.
964 *
965 * Returns a ordered XPath nodeset or NULL in case of error.
966 */
967 xmlXPathObjectPtr *
968 xsltComputeSortResult(xsltTransformContextPtr ctxt, xmlNodePtr sort) {
969 #ifdef XSLT_REFACTORED
970 xsltStyleItemSortPtr comp;
971 #else
972 xsltStylePreCompPtr comp;
973 #endif
974 xmlXPathObjectPtr *results = NULL;
975 xmlNodeSetPtr list = NULL;
976 xmlXPathObjectPtr res;
977 int len = 0;
978 int i;
979 xmlNodePtr oldNode;
980 xmlNodePtr oldInst;
981 int oldPos, oldSize ;
982 int oldNsNr;
983 xmlNsPtr *oldNamespaces;
984
985 comp = sort->psvi;
986 if (comp == NULL) {
987 xsltGenericError(xsltGenericErrorContext,
988 "xsl:sort : compilation failed\n");
989 return(NULL);
990 }
991
992 if ((comp->select == NULL) || (comp->comp == NULL))
993 return(NULL);
994
995 list = ctxt->nodeList;
996 if ((list == NULL) || (list->nodeNr <= 1))
997 return(NULL);
998
999 len = list->nodeNr;
1000
1001 /* TODO: xsl:sort lang attribute */
1002 /* TODO: xsl:sort case-order attribute */
1003
1004
1005 results = xmlMalloc(len * sizeof(xmlXPathObjectPtr));
1006 if (results == NULL) {
1007 xsltGenericError(xsltGenericErrorContext,
1008 "xsltComputeSortResult: memory allocation failure\n");
1009 return(NULL);
1010 }
1011
1012 oldNode = ctxt->node;
1013 oldInst = ctxt->inst;
1014 oldPos = ctxt->xpathCtxt->proximityPosition;
1015 oldSize = ctxt->xpathCtxt->contextSize;
1016 oldNsNr = ctxt->xpathCtxt->nsNr;
1017 oldNamespaces = ctxt->xpathCtxt->namespaces;
1018 for (i = 0;i < len;i++) {
1019 ctxt->inst = sort;
1020 ctxt->xpathCtxt->contextSize = len;
1021 ctxt->xpathCtxt->proximityPosition = i + 1;
1022 ctxt->node = list->nodeTab[i];
1023 ctxt->xpathCtxt->node = ctxt->node;
1024 #ifdef XSLT_REFACTORED
1025 if (comp->inScopeNs != NULL) {
1026 ctxt->xpathCtxt->namespaces = comp->inScopeNs->list;
1027 ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber;
1028 } else {
1029 ctxt->xpathCtxt->namespaces = NULL;
1030 ctxt->xpathCtxt->nsNr = 0;
1031 }
1032 #else
1033 ctxt->xpathCtxt->namespaces = comp->nsList;
1034 ctxt->xpathCtxt->nsNr = comp->nsNr;
1035 #endif
1036 res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);
1037 if (res != NULL) {
1038 if (res->type != XPATH_STRING)
1039 res = xmlXPathConvertString(res);
1040 if (comp->number)
1041 res = xmlXPathConvertNumber(res);
1042 res->index = i; /* Save original pos for dupl resolv */
1043 if (comp->number) {
1044 if (res->type == XPATH_NUMBER) {
1045 results[i] = res;
1046 } else {
1047 #ifdef WITH_XSLT_DEBUG_PROCESS
1048 xsltGenericDebug(xsltGenericDebugContext,
1049 "xsltComputeSortResult: select didn't evaluate to a numb er\n");
1050 #endif
1051 results[i] = NULL;
1052 }
1053 } else {
1054 if (res->type == XPATH_STRING) {
1055 if (comp->locale != (xsltLocale)0) {
1056 xmlChar *str = res->stringval;
1057 res->stringval = (xmlChar *) xsltStrxfrm(comp->locale, s tr);
1058 xmlFree(str);
1059 }
1060
1061 results[i] = res;
1062 } else {
1063 #ifdef WITH_XSLT_DEBUG_PROCESS
1064 xsltGenericDebug(xsltGenericDebugContext,
1065 "xsltComputeSortResult: select didn't evaluate to a stri ng\n");
1066 #endif
1067 results[i] = NULL;
1068 }
1069 }
1070 } else {
1071 ctxt->state = XSLT_STATE_STOPPED;
1072 results[i] = NULL;
1073 }
1074 }
1075 ctxt->node = oldNode;
1076 ctxt->inst = oldInst;
1077 ctxt->xpathCtxt->contextSize = oldSize;
1078 ctxt->xpathCtxt->proximityPosition = oldPos;
1079 ctxt->xpathCtxt->nsNr = oldNsNr;
1080 ctxt->xpathCtxt->namespaces = oldNamespaces;
1081
1082 return(results);
1083 }
1084
1085 /**
1086 * xsltDefaultSortFunction:
1087 * @ctxt: a XSLT process context
1088 * @sorts: array of sort nodes
1089 * @nbsorts: the number of sorts in the array
1090 *
1091 * reorder the current node list accordingly to the set of sorting
1092 * requirement provided by the arry of nodes.
1093 */
1094 void
1095 xsltDefaultSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts,
1096 int nbsorts) {
1097 #ifdef XSLT_REFACTORED
1098 xsltStyleItemSortPtr comp;
1099 #else
1100 xsltStylePreCompPtr comp;
1101 #endif
1102 xmlXPathObjectPtr *resultsTab[XSLT_MAX_SORT];
1103 xmlXPathObjectPtr *results = NULL, *res;
1104 xmlNodeSetPtr list = NULL;
1105 int descending, number, desc, numb;
1106 int len = 0;
1107 int i, j, incr;
1108 int tst;
1109 int depth;
1110 xmlNodePtr node;
1111 xmlXPathObjectPtr tmp;
1112 int tempstype[XSLT_MAX_SORT], temporder[XSLT_MAX_SORT];
1113
1114 if ((ctxt == NULL) || (sorts == NULL) || (nbsorts <= 0) ||
1115 (nbsorts >= XSLT_MAX_SORT))
1116 return;
1117 if (sorts[0] == NULL)
1118 return;
1119 comp = sorts[0]->psvi;
1120 if (comp == NULL)
1121 return;
1122
1123 list = ctxt->nodeList;
1124 if ((list == NULL) || (list->nodeNr <= 1))
1125 return; /* nothing to do */
1126
1127 for (j = 0; j < nbsorts; j++) {
1128 comp = sorts[j]->psvi;
1129 tempstype[j] = 0;
1130 if ((comp->stype == NULL) && (comp->has_stype != 0)) {
1131 comp->stype =
1132 xsltEvalAttrValueTemplate(ctxt, sorts[j],
1133 (const xmlChar *) "data-type",
1134 XSLT_NAMESPACE);
1135 if (comp->stype != NULL) {
1136 tempstype[j] = 1;
1137 if (xmlStrEqual(comp->stype, (const xmlChar *) "text"))
1138 comp->number = 0;
1139 else if (xmlStrEqual(comp->stype, (const xmlChar *) "number"))
1140 comp->number = 1;
1141 else {
1142 xsltTransformError(ctxt, NULL, sorts[j],
1143 "xsltDoSortFunction: no support for data-type = %s\n",
1144 comp->stype);
1145 comp->number = 0; /* use default */
1146 }
1147 }
1148 }
1149 temporder[j] = 0;
1150 if ((comp->order == NULL) && (comp->has_order != 0)) {
1151 comp->order = xsltEvalAttrValueTemplate(ctxt, sorts[j],
1152 (const xmlChar *) "order",
1153 XSLT_NAMESPACE);
1154 if (comp->order != NULL) {
1155 temporder[j] = 1;
1156 if (xmlStrEqual(comp->order, (const xmlChar *) "ascending"))
1157 comp->descending = 0;
1158 else if (xmlStrEqual(comp->order,
1159 (const xmlChar *) "descending"))
1160 comp->descending = 1;
1161 else {
1162 xsltTransformError(ctxt, NULL, sorts[j],
1163 "xsltDoSortFunction: invalid value %s for order\n",
1164 comp->order);
1165 comp->descending = 0; /* use default */
1166 }
1167 }
1168 }
1169 }
1170
1171 len = list->nodeNr;
1172
1173 resultsTab[0] = xsltComputeSortResult(ctxt, sorts[0]);
1174 for (i = 1;i < XSLT_MAX_SORT;i++)
1175 resultsTab[i] = NULL;
1176
1177 results = resultsTab[0];
1178
1179 comp = sorts[0]->psvi;
1180 descending = comp->descending;
1181 number = comp->number;
1182 if (results == NULL)
1183 return;
1184
1185 /* Shell's sort of node-set */
1186 for (incr = len / 2; incr > 0; incr /= 2) {
1187 for (i = incr; i < len; i++) {
1188 j = i - incr;
1189 if (results[i] == NULL)
1190 continue;
1191
1192 while (j >= 0) {
1193 if (results[j] == NULL)
1194 tst = 1;
1195 else {
1196 if (number) {
1197 /* We make NaN smaller than number in accordance
1198 with XSLT spec */
1199 if (xmlXPathIsNaN(results[j]->floatval)) {
1200 if (xmlXPathIsNaN(results[j + incr]->floatval))
1201 tst = 0;
1202 else
1203 tst = -1;
1204 } else if (xmlXPathIsNaN(results[j + incr]->floatval))
1205 tst = 1;
1206 else if (results[j]->floatval ==
1207 results[j + incr]->floatval)
1208 tst = 0;
1209 else if (results[j]->floatval >
1210 results[j + incr]->floatval)
1211 tst = 1;
1212 else tst = -1;
1213 } else if(comp->locale != (xsltLocale)0) {
1214 tst = xsltLocaleStrcmp(
1215 comp->locale,
1216 (xsltLocaleChar *) results[j]->stringval,
1217 (xsltLocaleChar *) results[j + incr]->stringval);
1218 } else {
1219 tst = xmlStrcmp(results[j]->stringval,
1220 results[j + incr]->stringval);
1221 }
1222 if (descending)
1223 tst = -tst;
1224 }
1225 if (tst == 0) {
1226 /*
1227 * Okay we need to use multi level sorts
1228 */
1229 depth = 1;
1230 while (depth < nbsorts) {
1231 if (sorts[depth] == NULL)
1232 break;
1233 comp = sorts[depth]->psvi;
1234 if (comp == NULL)
1235 break;
1236 desc = comp->descending;
1237 numb = comp->number;
1238
1239 /*
1240 * Compute the result of the next level for the
1241 * full set, this might be optimized ... or not
1242 */
1243 if (resultsTab[depth] == NULL)
1244 resultsTab[depth] = xsltComputeSortResult(ctxt,
1245 sorts[depth]);
1246 res = resultsTab[depth];
1247 if (res == NULL)
1248 break;
1249 if (res[j] == NULL) {
1250 if (res[j+incr] != NULL)
1251 tst = 1;
1252 } else {
1253 if (numb) {
1254 /* We make NaN smaller than number in
1255 accordance with XSLT spec */
1256 if (xmlXPathIsNaN(res[j]->floatval)) {
1257 if (xmlXPathIsNaN(res[j +
1258 incr]->floatval))
1259 tst = 0;
1260 else
1261 tst = -1;
1262 } else if (xmlXPathIsNaN(res[j + incr]->
1263 floatval))
1264 tst = 1;
1265 else if (res[j]->floatval == res[j + incr]->
1266 floatval)
1267 tst = 0;
1268 else if (res[j]->floatval >
1269 res[j + incr]->floatval)
1270 tst = 1;
1271 else tst = -1;
1272 } else if(comp->locale != (xsltLocale)0) {
1273 tst = xsltLocaleStrcmp(
1274 comp->locale,
1275 (xsltLocaleChar *) res[j]->stringval,
1276 (xsltLocaleChar *) res[j + incr]->stringval) ;
1277 } else {
1278 tst = xmlStrcmp(res[j]->stringval,
1279 res[j + incr]->stringval);
1280 }
1281 if (desc)
1282 tst = -tst;
1283 }
1284
1285 /*
1286 * if we still can't differenciate at this level
1287 * try one level deeper.
1288 */
1289 if (tst != 0)
1290 break;
1291 depth++;
1292 }
1293 }
1294 if (tst == 0) {
1295 tst = results[j]->index > results[j + incr]->index;
1296 }
1297 if (tst > 0) {
1298 tmp = results[j];
1299 results[j] = results[j + incr];
1300 results[j + incr] = tmp;
1301 node = list->nodeTab[j];
1302 list->nodeTab[j] = list->nodeTab[j + incr];
1303 list->nodeTab[j + incr] = node;
1304 depth = 1;
1305 while (depth < nbsorts) {
1306 if (sorts[depth] == NULL)
1307 break;
1308 if (resultsTab[depth] == NULL)
1309 break;
1310 res = resultsTab[depth];
1311 tmp = res[j];
1312 res[j] = res[j + incr];
1313 res[j + incr] = tmp;
1314 depth++;
1315 }
1316 j -= incr;
1317 } else
1318 break;
1319 }
1320 }
1321 }
1322
1323 for (j = 0; j < nbsorts; j++) {
1324 comp = sorts[j]->psvi;
1325 if (tempstype[j] == 1) {
1326 /* The data-type needs to be recomputed each time */
1327 xmlFree((void *)(comp->stype));
1328 comp->stype = NULL;
1329 }
1330 if (temporder[j] == 1) {
1331 /* The order needs to be recomputed each time */
1332 xmlFree((void *)(comp->order));
1333 comp->order = NULL;
1334 }
1335 if (resultsTab[j] != NULL) {
1336 for (i = 0;i < len;i++)
1337 xmlXPathFreeObject(resultsTab[j][i]);
1338 xmlFree(resultsTab[j]);
1339 }
1340 }
1341 }
1342
1343
1344 static xsltSortFunc xsltSortFunction = xsltDefaultSortFunction;
1345
1346 /**
1347 * xsltDoSortFunction:
1348 * @ctxt: a XSLT process context
1349 * @sorts: array of sort nodes
1350 * @nbsorts: the number of sorts in the array
1351 *
1352 * reorder the current node list accordingly to the set of sorting
1353 * requirement provided by the arry of nodes.
1354 * This is a wrapper function, the actual function used is specified
1355 * using xsltSetCtxtSortFunc() to set the context specific sort function,
1356 * or xsltSetSortFunc() to set the global sort function.
1357 * If a sort function is set on the context, this will get called.
1358 * Otherwise the global sort function is called.
1359 */
1360 void
1361 xsltDoSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr * sorts,
1362 int nbsorts)
1363 {
1364 if (ctxt->sortfunc != NULL)
1365 (ctxt->sortfunc)(ctxt, sorts, nbsorts);
1366 else if (xsltSortFunction != NULL)
1367 xsltSortFunction(ctxt, sorts, nbsorts);
1368 }
1369
1370 /**
1371 * xsltSetSortFunc:
1372 * @handler: the new handler function
1373 *
1374 * Function to reset the global handler for XSLT sorting.
1375 * If the handler is NULL, the default sort function will be used.
1376 */
1377 void
1378 xsltSetSortFunc(xsltSortFunc handler) {
1379 if (handler != NULL)
1380 xsltSortFunction = handler;
1381 else
1382 xsltSortFunction = xsltDefaultSortFunction;
1383 }
1384
1385 /**
1386 * xsltSetCtxtSortFunc:
1387 * @ctxt: a XSLT process context
1388 * @handler: the new handler function
1389 *
1390 * Function to set the handler for XSLT sorting
1391 * for the specified context.
1392 * If the handler is NULL, then the global
1393 * sort function will be called
1394 */
1395 void
1396 xsltSetCtxtSortFunc(xsltTransformContextPtr ctxt, xsltSortFunc handler) {
1397 ctxt->sortfunc = handler;
1398 }
1399
1400 /************************************************************************
1401 * *
1402 * Parsing options *
1403 * *
1404 ************************************************************************/
1405
1406 /**
1407 * xsltSetCtxtParseOptions:
1408 * @ctxt: a XSLT process context
1409 * @options: a combination of libxml2 xmlParserOption
1410 *
1411 * Change the default parser option passed by the XSLT engine to the
1412 * parser when using document() loading.
1413 *
1414 * Returns the previous options or -1 in case of error
1415 */
1416 int
1417 xsltSetCtxtParseOptions(xsltTransformContextPtr ctxt, int options)
1418 {
1419 int oldopts;
1420
1421 if (ctxt == NULL)
1422 return(-1);
1423 oldopts = ctxt->parserOptions;
1424 if (ctxt->xinclude)
1425 oldopts |= XML_PARSE_XINCLUDE;
1426 ctxt->parserOptions = options;
1427 if (options & XML_PARSE_XINCLUDE)
1428 ctxt->xinclude = 1;
1429 else
1430 ctxt->xinclude = 0;
1431 return(oldopts);
1432 }
1433
1434 /************************************************************************
1435 * *
1436 * Output *
1437 * *
1438 ************************************************************************/
1439
1440 /**
1441 * xsltSaveResultTo:
1442 * @buf: an output buffer
1443 * @result: the result xmlDocPtr
1444 * @style: the stylesheet
1445 *
1446 * Save the result @result obtained by applying the @style stylesheet
1447 * to an I/O output channel @buf
1448 *
1449 * Returns the number of byte written or -1 in case of failure.
1450 */
1451 int
1452 xsltSaveResultTo(xmlOutputBufferPtr buf, xmlDocPtr result,
1453 xsltStylesheetPtr style) {
1454 const xmlChar *encoding;
1455 int base;
1456 const xmlChar *method;
1457 int indent;
1458
1459 if ((buf == NULL) || (result == NULL) || (style == NULL))
1460 return(-1);
1461 if ((result->children == NULL) ||
1462 ((result->children->type == XML_DTD_NODE) &&
1463 (result->children->next == NULL)))
1464 return(0);
1465
1466 if ((style->methodURI != NULL) &&
1467 ((style->method == NULL) ||
1468 (!xmlStrEqual(style->method, (const xmlChar *) "xhtml")))) {
1469 xsltGenericError(xsltGenericErrorContext,
1470 "xsltSaveResultTo : unknown ouput method\n");
1471 return(-1);
1472 }
1473
1474 base = buf->written;
1475
1476 XSLT_GET_IMPORT_PTR(method, style, method)
1477 XSLT_GET_IMPORT_PTR(encoding, style, encoding)
1478 XSLT_GET_IMPORT_INT(indent, style, indent);
1479
1480 if ((method == NULL) && (result->type == XML_HTML_DOCUMENT_NODE))
1481 method = (const xmlChar *) "html";
1482
1483 if ((method != NULL) &&
1484 (xmlStrEqual(method, (const xmlChar *) "html"))) {
1485 if (encoding != NULL) {
1486 htmlSetMetaEncoding(result, (const xmlChar *) encoding);
1487 } else {
1488 htmlSetMetaEncoding(result, (const xmlChar *) "UTF-8");
1489 }
1490 if (indent == -1)
1491 indent = 1;
1492 htmlDocContentDumpFormatOutput(buf, result, (const char *) encoding,
1493 indent);
1494 xmlOutputBufferFlush(buf);
1495 } else if ((method != NULL) &&
1496 (xmlStrEqual(method, (const xmlChar *) "xhtml"))) {
1497 if (encoding != NULL) {
1498 htmlSetMetaEncoding(result, (const xmlChar *) encoding);
1499 } else {
1500 htmlSetMetaEncoding(result, (const xmlChar *) "UTF-8");
1501 }
1502 htmlDocContentDumpOutput(buf, result, (const char *) encoding);
1503 xmlOutputBufferFlush(buf);
1504 } else if ((method != NULL) &&
1505 (xmlStrEqual(method, (const xmlChar *) "text"))) {
1506 xmlNodePtr cur;
1507
1508 cur = result->children;
1509 while (cur != NULL) {
1510 if (cur->type == XML_TEXT_NODE)
1511 xmlOutputBufferWriteString(buf, (const char *) cur->content);
1512
1513 /*
1514 * Skip to next node
1515 */
1516 if (cur->children != NULL) {
1517 if ((cur->children->type != XML_ENTITY_DECL) &&
1518 (cur->children->type != XML_ENTITY_REF_NODE) &&
1519 (cur->children->type != XML_ENTITY_NODE)) {
1520 cur = cur->children;
1521 continue;
1522 }
1523 }
1524 if (cur->next != NULL) {
1525 cur = cur->next;
1526 continue;
1527 }
1528
1529 do {
1530 cur = cur->parent;
1531 if (cur == NULL)
1532 break;
1533 if (cur == (xmlNodePtr) style->doc) {
1534 cur = NULL;
1535 break;
1536 }
1537 if (cur->next != NULL) {
1538 cur = cur->next;
1539 break;
1540 }
1541 } while (cur != NULL);
1542 }
1543 xmlOutputBufferFlush(buf);
1544 } else {
1545 int omitXmlDecl;
1546 int standalone;
1547
1548 XSLT_GET_IMPORT_INT(omitXmlDecl, style, omitXmlDeclaration);
1549 XSLT_GET_IMPORT_INT(standalone, style, standalone);
1550
1551 if (omitXmlDecl != 1) {
1552 xmlOutputBufferWriteString(buf, "<?xml version=");
1553 if (result->version != NULL) {
1554 xmlOutputBufferWriteString(buf, "\"");
1555 xmlOutputBufferWriteString(buf, (const char *)result->version);
1556 xmlOutputBufferWriteString(buf, "\"");
1557 } else
1558 xmlOutputBufferWriteString(buf, "\"1.0\"");
1559 if (encoding == NULL) {
1560 if (result->encoding != NULL)
1561 encoding = result->encoding;
1562 else if (result->charset != XML_CHAR_ENCODING_UTF8)
1563 encoding = (const xmlChar *)
1564 xmlGetCharEncodingName((xmlCharEncoding)
1565 result->charset);
1566 }
1567 if (encoding != NULL) {
1568 xmlOutputBufferWriteString(buf, " encoding=");
1569 xmlOutputBufferWriteString(buf, "\"");
1570 xmlOutputBufferWriteString(buf, (const char *) encoding);
1571 xmlOutputBufferWriteString(buf, "\"");
1572 }
1573 switch (standalone) {
1574 case 0:
1575 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
1576 break;
1577 case 1:
1578 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
1579 break;
1580 default:
1581 break;
1582 }
1583 xmlOutputBufferWriteString(buf, "?>\n");
1584 }
1585 if (result->children != NULL) {
1586 xmlNodePtr child = result->children;
1587
1588 while (child != NULL) {
1589 xmlNodeDumpOutput(buf, result, child, 0, (indent == 1),
1590 (const char *) encoding);
1591 if (indent && ((child->type == XML_DTD_NODE) ||
1592 ((child->type == XML_COMMENT_NODE) &&
1593 (child->next != NULL))))
1594 xmlOutputBufferWriteString(buf, "\n");
1595 child = child->next;
1596 }
1597 if (indent)
1598 xmlOutputBufferWriteString(buf, "\n");
1599 }
1600 xmlOutputBufferFlush(buf);
1601 }
1602 return(buf->written - base);
1603 }
1604
1605 /**
1606 * xsltSaveResultToFilename:
1607 * @URL: a filename or URL
1608 * @result: the result xmlDocPtr
1609 * @style: the stylesheet
1610 * @compression: the compression factor (0 - 9 included)
1611 *
1612 * Save the result @result obtained by applying the @style stylesheet
1613 * to a file or @URL
1614 *
1615 * Returns the number of byte written or -1 in case of failure.
1616 */
1617 int
1618 xsltSaveResultToFilename(const char *URL, xmlDocPtr result,
1619 xsltStylesheetPtr style, int compression) {
1620 xmlOutputBufferPtr buf;
1621 const xmlChar *encoding;
1622 int ret;
1623
1624 if ((URL == NULL) || (result == NULL) || (style == NULL))
1625 return(-1);
1626 if (result->children == NULL)
1627 return(0);
1628
1629 XSLT_GET_IMPORT_PTR(encoding, style, encoding)
1630 if (encoding != NULL) {
1631 xmlCharEncodingHandlerPtr encoder;
1632
1633 encoder = xmlFindCharEncodingHandler((char *)encoding);
1634 if ((encoder != NULL) &&
1635 (xmlStrEqual((const xmlChar *)encoder->name,
1636 (const xmlChar *) "UTF-8")))
1637 encoder = NULL;
1638 buf = xmlOutputBufferCreateFilename(URL, encoder, compression);
1639 } else {
1640 buf = xmlOutputBufferCreateFilename(URL, NULL, compression);
1641 }
1642 if (buf == NULL)
1643 return(-1);
1644 xsltSaveResultTo(buf, result, style);
1645 ret = xmlOutputBufferClose(buf);
1646 return(ret);
1647 }
1648
1649 /**
1650 * xsltSaveResultToFile:
1651 * @file: a FILE * I/O
1652 * @result: the result xmlDocPtr
1653 * @style: the stylesheet
1654 *
1655 * Save the result @result obtained by applying the @style stylesheet
1656 * to an open FILE * I/O.
1657 * This does not close the FILE @file
1658 *
1659 * Returns the number of bytes written or -1 in case of failure.
1660 */
1661 int
1662 xsltSaveResultToFile(FILE *file, xmlDocPtr result, xsltStylesheetPtr style) {
1663 xmlOutputBufferPtr buf;
1664 const xmlChar *encoding;
1665 int ret;
1666
1667 if ((file == NULL) || (result == NULL) || (style == NULL))
1668 return(-1);
1669 if (result->children == NULL)
1670 return(0);
1671
1672 XSLT_GET_IMPORT_PTR(encoding, style, encoding)
1673 if (encoding != NULL) {
1674 xmlCharEncodingHandlerPtr encoder;
1675
1676 encoder = xmlFindCharEncodingHandler((char *)encoding);
1677 if ((encoder != NULL) &&
1678 (xmlStrEqual((const xmlChar *)encoder->name,
1679 (const xmlChar *) "UTF-8")))
1680 encoder = NULL;
1681 buf = xmlOutputBufferCreateFile(file, encoder);
1682 } else {
1683 buf = xmlOutputBufferCreateFile(file, NULL);
1684 }
1685
1686 if (buf == NULL)
1687 return(-1);
1688 xsltSaveResultTo(buf, result, style);
1689 ret = xmlOutputBufferClose(buf);
1690 return(ret);
1691 }
1692
1693 /**
1694 * xsltSaveResultToFd:
1695 * @fd: a file descriptor
1696 * @result: the result xmlDocPtr
1697 * @style: the stylesheet
1698 *
1699 * Save the result @result obtained by applying the @style stylesheet
1700 * to an open file descriptor
1701 * This does not close the descriptor.
1702 *
1703 * Returns the number of bytes written or -1 in case of failure.
1704 */
1705 int
1706 xsltSaveResultToFd(int fd, xmlDocPtr result, xsltStylesheetPtr style) {
1707 xmlOutputBufferPtr buf;
1708 const xmlChar *encoding;
1709 int ret;
1710
1711 if ((fd < 0) || (result == NULL) || (style == NULL))
1712 return(-1);
1713 if (result->children == NULL)
1714 return(0);
1715
1716 XSLT_GET_IMPORT_PTR(encoding, style, encoding)
1717 if (encoding != NULL) {
1718 xmlCharEncodingHandlerPtr encoder;
1719
1720 encoder = xmlFindCharEncodingHandler((char *)encoding);
1721 if ((encoder != NULL) &&
1722 (xmlStrEqual((const xmlChar *)encoder->name,
1723 (const xmlChar *) "UTF-8")))
1724 encoder = NULL;
1725 buf = xmlOutputBufferCreateFd(fd, encoder);
1726 } else {
1727 buf = xmlOutputBufferCreateFd(fd, NULL);
1728 }
1729 if (buf == NULL)
1730 return(-1);
1731 xsltSaveResultTo(buf, result, style);
1732 ret = xmlOutputBufferClose(buf);
1733 return(ret);
1734 }
1735
1736 /**
1737 * xsltSaveResultToString:
1738 * @doc_txt_ptr: Memory pointer for allocated XML text
1739 * @doc_txt_len: Length of the generated XML text
1740 * @result: the result xmlDocPtr
1741 * @style: the stylesheet
1742 *
1743 * Save the result @result obtained by applying the @style stylesheet
1744 * to a new allocated string.
1745 *
1746 * Returns 0 in case of success and -1 in case of error
1747 */
1748 int
1749 xsltSaveResultToString(xmlChar **doc_txt_ptr, int * doc_txt_len,
1750 xmlDocPtr result, xsltStylesheetPtr style) {
1751 xmlOutputBufferPtr buf;
1752 const xmlChar *encoding;
1753
1754 *doc_txt_ptr = NULL;
1755 *doc_txt_len = 0;
1756 if (result->children == NULL)
1757 return(0);
1758
1759 XSLT_GET_IMPORT_PTR(encoding, style, encoding)
1760 if (encoding != NULL) {
1761 xmlCharEncodingHandlerPtr encoder;
1762
1763 encoder = xmlFindCharEncodingHandler((char *)encoding);
1764 if ((encoder != NULL) &&
1765 (xmlStrEqual((const xmlChar *)encoder->name,
1766 (const xmlChar *) "UTF-8")))
1767 encoder = NULL;
1768 buf = xmlAllocOutputBuffer(encoder);
1769 } else {
1770 buf = xmlAllocOutputBuffer(NULL);
1771 }
1772 if (buf == NULL)
1773 return(-1);
1774 xsltSaveResultTo(buf, result, style);
1775 #ifdef LIBXML2_NEW_BUFFER
1776 if (buf->conv != NULL) {
1777 *doc_txt_len = xmlBufUse(buf->conv);
1778 *doc_txt_ptr = xmlStrndup(xmlBufContent(buf->conv), *doc_txt_len);
1779 } else {
1780 *doc_txt_len = xmlBufUse(buf->buffer);
1781 *doc_txt_ptr = xmlStrndup(xmlBufContent(buf->buffer), *doc_txt_len);
1782 }
1783 #else
1784 if (buf->conv != NULL) {
1785 *doc_txt_len = buf->conv->use;
1786 *doc_txt_ptr = xmlStrndup(buf->conv->content, *doc_txt_len);
1787 } else {
1788 *doc_txt_len = buf->buffer->use;
1789 *doc_txt_ptr = xmlStrndup(buf->buffer->content, *doc_txt_len);
1790 }
1791 #endif
1792 (void)xmlOutputBufferClose(buf);
1793 return 0;
1794 }
1795
1796 /************************************************************************
1797 * *
1798 * Generating profiling informations *
1799 * *
1800 ************************************************************************/
1801
1802 static long calibration = -1;
1803
1804 /**
1805 * xsltCalibrateTimestamps:
1806 *
1807 * Used for to calibrate the xsltTimestamp() function
1808 * Should work if launched at startup and we don't loose our quantum :-)
1809 *
1810 * Returns the number of milliseconds used by xsltTimestamp()
1811 */
1812 static long
1813 xsltCalibrateTimestamps(void) {
1814 register int i;
1815
1816 for (i = 0;i < 999;i++)
1817 xsltTimestamp();
1818 return(xsltTimestamp() / 1000);
1819 }
1820
1821 /**
1822 * xsltCalibrateAdjust:
1823 * @delta: a negative dealy value found
1824 *
1825 * Used for to correct the calibration for xsltTimestamp()
1826 */
1827 void
1828 xsltCalibrateAdjust(long delta) {
1829 calibration += delta;
1830 }
1831
1832 /**
1833 * xsltTimestamp:
1834 *
1835 * Used for gathering profiling data
1836 *
1837 * Returns the number of tenth of milliseconds since the beginning of the
1838 * profiling
1839 */
1840 long
1841 xsltTimestamp(void)
1842 {
1843 #ifdef XSLT_WIN32_PERFORMANCE_COUNTER
1844 BOOL ok;
1845 LARGE_INTEGER performanceCount;
1846 LARGE_INTEGER performanceFrequency;
1847 LONGLONG quadCount;
1848 double seconds;
1849 static LONGLONG startupQuadCount = 0;
1850 static LONGLONG startupQuadFreq = 0;
1851
1852 ok = QueryPerformanceCounter(&performanceCount);
1853 if (!ok)
1854 return 0;
1855 quadCount = performanceCount.QuadPart;
1856 if (calibration < 0) {
1857 calibration = 0;
1858 ok = QueryPerformanceFrequency(&performanceFrequency);
1859 if (!ok)
1860 return 0;
1861 startupQuadFreq = performanceFrequency.QuadPart;
1862 startupQuadCount = quadCount;
1863 return (0);
1864 }
1865 if (startupQuadFreq == 0)
1866 return 0;
1867 seconds = (quadCount - startupQuadCount) / (double) startupQuadFreq;
1868 return (long) (seconds * XSLT_TIMESTAMP_TICS_PER_SEC);
1869
1870 #else /* XSLT_WIN32_PERFORMANCE_COUNTER */
1871 #ifdef HAVE_CLOCK_GETTIME
1872 # if defined(CLOCK_MONOTONIC)
1873 # define XSLT_CLOCK CLOCK_MONOTONIC
1874 # elif defined(CLOCK_HIGHRES)
1875 # define XSLT_CLOCK CLOCK_HIGHRES
1876 # else
1877 # define XSLT_CLOCK CLOCK_REALTIME
1878 # endif
1879 static struct timespec startup;
1880 struct timespec cur;
1881 long tics;
1882
1883 if (calibration < 0) {
1884 clock_gettime(XSLT_CLOCK, &startup);
1885 calibration = 0;
1886 calibration = xsltCalibrateTimestamps();
1887 clock_gettime(XSLT_CLOCK, &startup);
1888 return (0);
1889 }
1890
1891 clock_gettime(XSLT_CLOCK, &cur);
1892 tics = (cur.tv_sec - startup.tv_sec) * XSLT_TIMESTAMP_TICS_PER_SEC;
1893 tics += (cur.tv_nsec - startup.tv_nsec) /
1894 (1000000000l / XSLT_TIMESTAMP_TICS_PER_SEC);
1895
1896 tics -= calibration;
1897 return(tics);
1898
1899 #elif HAVE_GETTIMEOFDAY
1900 static struct timeval startup;
1901 struct timeval cur;
1902 long tics;
1903
1904 if (calibration < 0) {
1905 gettimeofday(&startup, NULL);
1906 calibration = 0;
1907 calibration = xsltCalibrateTimestamps();
1908 gettimeofday(&startup, NULL);
1909 return (0);
1910 }
1911
1912 gettimeofday(&cur, NULL);
1913 tics = (cur.tv_sec - startup.tv_sec) * XSLT_TIMESTAMP_TICS_PER_SEC;
1914 tics += (cur.tv_usec - startup.tv_usec) /
1915 (1000000l / XSLT_TIMESTAMP_TICS_PER_SEC);
1916
1917 tics -= calibration;
1918 return(tics);
1919 #else
1920
1921 /* Neither gettimeofday() nor Win32 performance counter available */
1922
1923 return (0);
1924
1925 #endif /* HAVE_GETTIMEOFDAY */
1926 #endif /* XSLT_WIN32_PERFORMANCE_COUNTER */
1927 }
1928
1929 static char *
1930 pretty_templ_match(xsltTemplatePtr templ) {
1931 static char dst[1001];
1932 char *src = (char *)templ->match;
1933 int i=0,j;
1934
1935 /* strip white spaces */
1936 for (j=0; i<1000 && src[j]; i++,j++) {
1937 for(;src[j]==' ';j++);
1938 dst[i]=src[j];
1939 }
1940 if(i<998 && templ->mode) {
1941 /* append [mode] */
1942 dst[i++]='[';
1943 src=(char *)templ->mode;
1944 for (j=0; i<999 && src[j]; i++,j++) {
1945 dst[i]=src[j];
1946 }
1947 dst[i++]=']';
1948 }
1949 dst[i]='\0';
1950 return dst;
1951 }
1952
1953 #define MAX_TEMPLATES 10000
1954
1955 /**
1956 * xsltSaveProfiling:
1957 * @ctxt: an XSLT context
1958 * @output: a FILE * for saving the informations
1959 *
1960 * Save the profiling informations on @output
1961 */
1962 void
1963 xsltSaveProfiling(xsltTransformContextPtr ctxt, FILE *output) {
1964 int nb, i,j,k,l;
1965 int max;
1966 int total;
1967 unsigned long totalt;
1968 xsltTemplatePtr *templates;
1969 xsltStylesheetPtr style;
1970 xsltTemplatePtr templ1,templ2;
1971 int *childt;
1972
1973 if ((output == NULL) || (ctxt == NULL))
1974 return;
1975 if (ctxt->profile == 0)
1976 return;
1977
1978 nb = 0;
1979 max = MAX_TEMPLATES;
1980 templates = xmlMalloc(max * sizeof(xsltTemplatePtr));
1981 if (templates == NULL)
1982 return;
1983
1984 style = ctxt->style;
1985 while (style != NULL) {
1986 templ1 = style->templates;
1987 while (templ1 != NULL) {
1988 if (nb >= max)
1989 break;
1990
1991 if (templ1->nbCalls > 0)
1992 templates[nb++] = templ1;
1993 templ1 = templ1->next;
1994 }
1995
1996 style = xsltNextImport(style);
1997 }
1998
1999 for (i = 0;i < nb -1;i++) {
2000 for (j = i + 1; j < nb; j++) {
2001 if ((templates[i]->time <= templates[j]->time) ||
2002 ((templates[i]->time == templates[j]->time) &&
2003 (templates[i]->nbCalls <= templates[j]->nbCalls))) {
2004 templ1 = templates[j];
2005 templates[j] = templates[i];
2006 templates[i] = templ1;
2007 }
2008 }
2009 }
2010
2011
2012 /* print flat profile */
2013
2014 fprintf(output, "%6s%20s%20s%10s Calls Tot 100us Avg\n\n",
2015 "number", "match", "name", "mode");
2016 total = 0;
2017 totalt = 0;
2018 for (i = 0;i < nb;i++) {
2019 templ1 = templates[i];
2020 fprintf(output, "%5d ", i);
2021 if (templ1->match != NULL) {
2022 if (xmlStrlen(templ1->match) > 20)
2023 fprintf(output, "%s\n%26s", templ1->match, "");
2024 else
2025 fprintf(output, "%20s", templ1->match);
2026 } else {
2027 fprintf(output, "%20s", "");
2028 }
2029 if (templ1->name != NULL) {
2030 if (xmlStrlen(templ1->name) > 20)
2031 fprintf(output, "%s\n%46s", templ1->name, "");
2032 else
2033 fprintf(output, "%20s", templ1->name);
2034 } else {
2035 fprintf(output, "%20s", "");
2036 }
2037 if (templ1->mode != NULL) {
2038 if (xmlStrlen(templ1->mode) > 10)
2039 fprintf(output, "%s\n%56s", templ1->mode, "");
2040 else
2041 fprintf(output, "%10s", templ1->mode);
2042 } else {
2043 fprintf(output, "%10s", "");
2044 }
2045 fprintf(output, " %6d", templ1->nbCalls);
2046 fprintf(output, " %6ld %6ld\n", templ1->time,
2047 templ1->time / templ1->nbCalls);
2048 total += templ1->nbCalls;
2049 totalt += templ1->time;
2050 }
2051 fprintf(output, "\n%30s%26s %6d %6ld\n", "Total", "", total, totalt);
2052
2053
2054 /* print call graph */
2055
2056 childt = xmlMalloc((nb + 1) * sizeof(int));
2057 if (childt == NULL)
2058 return;
2059
2060 /* precalculate children times */
2061 for (i = 0; i < nb; i++) {
2062 templ1 = templates[i];
2063
2064 childt[i] = 0;
2065 for (k = 0; k < nb; k++) {
2066 templ2 = templates[k];
2067 for (l = 0; l < templ2->templNr; l++) {
2068 if (templ2->templCalledTab[l] == templ1) {
2069 childt[i] +=templ2->time;
2070 }
2071 }
2072 }
2073 }
2074 childt[i] = 0;
2075
2076 fprintf(output, "\nindex %% time self children called name\n");
2077
2078 for (i = 0; i < nb; i++) {
2079 char ix_str[20], timep_str[20], times_str[20], timec_str[20], called_str [20];
2080 unsigned long t;
2081
2082 templ1 = templates[i];
2083 /* callers */
2084 for (j = 0; j < templ1->templNr; j++) {
2085 templ2 = templ1->templCalledTab[j];
2086 for (k = 0; k < nb; k++) {
2087 if (templates[k] == templ2)
2088 break;
2089 }
2090 t=templ2?templ2->time:totalt;
2091 snprintf(times_str,sizeof(times_str),"%8.3f",(float)t/XSLT_TIMESTAMP _TICS_PER_SEC);
2092 snprintf(timec_str,sizeof(timec_str),"%8.3f",(float)childt[k]/XSLT_T IMESTAMP_TICS_PER_SEC);
2093 snprintf(called_str,sizeof(called_str),"%6d/%d",
2094 templ1->templCountTab[j], /* number of times caller calls 'this' */
2095 templ1->nbCalls); /* total number of calls to 'this' */
2096
2097 fprintf(output, " %-8s %-8s %-12s %s [%d]\n",
2098 times_str,timec_str,called_str,
2099 (templ2?(templ2->name?(char *)templ2->name:pretty_templ_match(te mpl2)):"-"),k);
2100 }
2101 /* this */
2102 snprintf(ix_str,sizeof(ix_str),"[%d]",i);
2103 snprintf(timep_str,sizeof(timep_str),"%6.2f",(float)templ1->time*100.0/t otalt);
2104 snprintf(times_str,sizeof(times_str),"%8.3f",(float)templ1->time/XSLT_TI MESTAMP_TICS_PER_SEC);
2105 snprintf(timec_str,sizeof(timec_str),"%8.3f",(float)childt[i]/XSLT_TIMES TAMP_TICS_PER_SEC);
2106 fprintf(output, "%-5s %-6s %-8s %-8s %6d %s [%d]\n",
2107 ix_str, timep_str,times_str,timec_str,
2108 templ1->nbCalls,
2109 templ1->name?(char *)templ1->name:pretty_templ_match(templ1),i);
2110 /* callees
2111 * - go over templates[0..nb] and their templCalledTab[]
2112 * - print those where we in the the call-stack
2113 */
2114 total = 0;
2115 for (k = 0; k < nb; k++) {
2116 templ2 = templates[k];
2117 for (l = 0; l < templ2->templNr; l++) {
2118 if (templ2->templCalledTab[l] == templ1) {
2119 total+=templ2->templCountTab[l];
2120 }
2121 }
2122 }
2123 for (k = 0; k < nb; k++) {
2124 templ2 = templates[k];
2125 for (l = 0; l < templ2->templNr; l++) {
2126 if (templ2->templCalledTab[l] == templ1) {
2127 snprintf(times_str,sizeof(times_str),"%8.3f",(float)templ2-> time/XSLT_TIMESTAMP_TICS_PER_SEC);
2128 snprintf(timec_str,sizeof(timec_str),"%8.3f",(float)childt[k ]/XSLT_TIMESTAMP_TICS_PER_SEC);
2129 snprintf(called_str,sizeof(called_str),"%6d/%d",
2130 templ2->templCountTab[l], /* number of times 'this' call s callee */
2131 total); /* total number of calls from 'this' */
2132 fprintf(output, " %-8s %-8s %-12s %s [%d]\n" ,
2133 times_str,timec_str,called_str,
2134 templ2->name?(char *)templ2->name:pretty_templ_match(tem pl2),k);
2135 }
2136 }
2137 }
2138 fprintf(output, "-----------------------------------------------\n");
2139 }
2140
2141 fprintf(output, "\f\nIndex by function name\n");
2142 for (i = 0; i < nb; i++) {
2143 templ1 = templates[i];
2144 fprintf(output, "[%d] %s (%s:%d)\n",
2145 i, templ1->name?(char *)templ1->name:pretty_templ_match(templ1),
2146 templ1->style->doc->URL,templ1->elem->line);
2147 }
2148
2149 fprintf(output, "\f\n");
2150 xmlFree(childt);
2151
2152 xmlFree(templates);
2153 }
2154
2155 /************************************************************************
2156 * *
2157 * Fetching profiling informations *
2158 * *
2159 ************************************************************************/
2160
2161 /**
2162 * xsltGetProfileInformation:
2163 * @ctxt: a transformation context
2164 *
2165 * This function should be called after the transformation completed
2166 * to extract template processing profiling informations if availble.
2167 * The informations are returned as an XML document tree like
2168 * <?xml version="1.0"?>
2169 * <profile>
2170 * <template rank="1" match="*" name=""
2171 * mode="" calls="6" time="48" average="8"/>
2172 * <template rank="2" match="item2|item3" name=""
2173 * mode="" calls="10" time="30" average="3"/>
2174 * <template rank="3" match="item1" name=""
2175 * mode="" calls="5" time="17" average="3"/>
2176 * </profile>
2177 * The caller will need to free up the returned tree with xmlFreeDoc()
2178 *
2179 * Returns the xmlDocPtr corresponding to the result or NULL if not available.
2180 */
2181
2182 xmlDocPtr
2183 xsltGetProfileInformation(xsltTransformContextPtr ctxt)
2184 {
2185 xmlDocPtr ret = NULL;
2186 xmlNodePtr root, child;
2187 char buf[100];
2188
2189 xsltStylesheetPtr style;
2190 xsltTemplatePtr *templates;
2191 xsltTemplatePtr templ;
2192 int nb = 0, max = 0, i, j;
2193
2194 if (!ctxt)
2195 return NULL;
2196
2197 if (!ctxt->profile)
2198 return NULL;
2199
2200 nb = 0;
2201 max = 10000;
2202 templates =
2203 (xsltTemplatePtr *) xmlMalloc(max * sizeof(xsltTemplatePtr));
2204 if (templates == NULL)
2205 return NULL;
2206
2207 /*
2208 * collect all the templates in an array
2209 */
2210 style = ctxt->style;
2211 while (style != NULL) {
2212 templ = style->templates;
2213 while (templ != NULL) {
2214 if (nb >= max)
2215 break;
2216
2217 if (templ->nbCalls > 0)
2218 templates[nb++] = templ;
2219 templ = templ->next;
2220 }
2221
2222 style = (xsltStylesheetPtr) xsltNextImport(style);
2223 }
2224
2225 /*
2226 * Sort the array by time spent
2227 */
2228 for (i = 0; i < nb - 1; i++) {
2229 for (j = i + 1; j < nb; j++) {
2230 if ((templates[i]->time <= templates[j]->time) ||
2231 ((templates[i]->time == templates[j]->time) &&
2232 (templates[i]->nbCalls <= templates[j]->nbCalls))) {
2233 templ = templates[j];
2234 templates[j] = templates[i];
2235 templates[i] = templ;
2236 }
2237 }
2238 }
2239
2240 /*
2241 * Generate a document corresponding to the results.
2242 */
2243 ret = xmlNewDoc(BAD_CAST "1.0");
2244 root = xmlNewDocNode(ret, NULL, BAD_CAST "profile", NULL);
2245 xmlDocSetRootElement(ret, root);
2246
2247 for (i = 0; i < nb; i++) {
2248 child = xmlNewChild(root, NULL, BAD_CAST "template", NULL);
2249 snprintf(buf, sizeof(buf), "%d", i + 1);
2250 xmlSetProp(child, BAD_CAST "rank", BAD_CAST buf);
2251 xmlSetProp(child, BAD_CAST "match", BAD_CAST templates[i]->match);
2252 xmlSetProp(child, BAD_CAST "name", BAD_CAST templates[i]->name);
2253 xmlSetProp(child, BAD_CAST "mode", BAD_CAST templates[i]->mode);
2254
2255 snprintf(buf, sizeof(buf), "%d", templates[i]->nbCalls);
2256 xmlSetProp(child, BAD_CAST "calls", BAD_CAST buf);
2257
2258 snprintf(buf, sizeof(buf), "%ld", templates[i]->time);
2259 xmlSetProp(child, BAD_CAST "time", BAD_CAST buf);
2260
2261 snprintf(buf, sizeof(buf), "%ld", templates[i]->time / templates[i]->nbC alls);
2262 xmlSetProp(child, BAD_CAST "average", BAD_CAST buf);
2263 };
2264
2265 xmlFree(templates);
2266
2267 return ret;
2268 }
2269
2270 /************************************************************************
2271 * *
2272 * Hooks for libxml2 XPath *
2273 * *
2274 ************************************************************************/
2275
2276 /**
2277 * xsltXPathCompileFlags:
2278 * @style: the stylesheet
2279 * @str: the XPath expression
2280 * @flags: extra compilation flags to pass down to libxml2 XPath
2281 *
2282 * Compile an XPath expression
2283 *
2284 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
2285 * the caller has to free the object.
2286 */
2287 xmlXPathCompExprPtr
2288 xsltXPathCompileFlags(xsltStylesheetPtr style, const xmlChar *str, int flags) {
2289 xmlXPathContextPtr xpathCtxt;
2290 xmlXPathCompExprPtr ret;
2291
2292 if (style != NULL) {
2293 #ifdef XSLT_REFACTORED_XPATHCOMP
2294 if (XSLT_CCTXT(style)) {
2295 /*
2296 * Proposed by Jerome Pesenti
2297 * --------------------------
2298 * For better efficiency we'll reuse the compilation
2299 * context's XPath context. For the common stylesheet using
2300 * XPath expressions this will reduce compilation time to
2301 * about 50%.
2302 *
2303 * See http://mail.gnome.org/archives/xslt/2006-April/msg00037.html
2304 */
2305 xpathCtxt = XSLT_CCTXT(style)->xpathCtxt;
2306 xpathCtxt->doc = style->doc;
2307 } else
2308 xpathCtxt = xmlXPathNewContext(style->doc);
2309 #else
2310 xpathCtxt = xmlXPathNewContext(style->doc);
2311 #endif
2312 if (xpathCtxt == NULL)
2313 return NULL;
2314 xpathCtxt->dict = style->dict;
2315 } else {
2316 xpathCtxt = xmlXPathNewContext(NULL);
2317 if (xpathCtxt == NULL)
2318 return NULL;
2319 }
2320 xpathCtxt->flags = flags;
2321
2322 /*
2323 * Compile the expression.
2324 */
2325 ret = xmlXPathCtxtCompile(xpathCtxt, str);
2326
2327 #ifdef XSLT_REFACTORED_XPATHCOMP
2328 if ((style == NULL) || (! XSLT_CCTXT(style))) {
2329 xmlXPathFreeContext(xpathCtxt);
2330 }
2331 #else
2332 xmlXPathFreeContext(xpathCtxt);
2333 #endif
2334 /*
2335 * TODO: there is a lot of optimizations which should be possible
2336 * like variable slot precomputations, function precomputations, etc.
2337 */
2338
2339 return(ret);
2340 }
2341
2342 /**
2343 * xsltXPathCompile:
2344 * @style: the stylesheet
2345 * @str: the XPath expression
2346 *
2347 * Compile an XPath expression
2348 *
2349 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
2350 * the caller has to free the object.
2351 */
2352 xmlXPathCompExprPtr
2353 xsltXPathCompile(xsltStylesheetPtr style, const xmlChar *str) {
2354 return(xsltXPathCompileFlags(style, str, 0));
2355 }
2356
2357 /************************************************************************
2358 * *
2359 * Hooks for the debugger *
2360 * *
2361 ************************************************************************/
2362
2363 /*
2364 * There is currently only 3 debugging callback defined
2365 * Debugger callbacks are disabled by default
2366 */
2367 #define XSLT_CALLBACK_NUMBER 3
2368
2369 typedef struct _xsltDebuggerCallbacks xsltDebuggerCallbacks;
2370 typedef xsltDebuggerCallbacks *xsltDebuggerCallbacksPtr;
2371 struct _xsltDebuggerCallbacks {
2372 xsltHandleDebuggerCallback handler;
2373 xsltAddCallCallback add;
2374 xsltDropCallCallback drop;
2375 };
2376
2377 static xsltDebuggerCallbacks xsltDebuggerCurrentCallbacks = {
2378 NULL, /* handler */
2379 NULL, /* add */
2380 NULL /* drop */
2381 };
2382
2383 int xslDebugStatus;
2384
2385 /**
2386 * xsltSetDebuggerStatus:
2387 * @value : the value to be set
2388 *
2389 * This function sets the value of xslDebugStatus.
2390 */
2391 void
2392 xsltSetDebuggerStatus(int value)
2393 {
2394 xslDebugStatus = value;
2395 }
2396
2397 /**
2398 * xsltGetDebuggerStatus:
2399 *
2400 * Get xslDebugStatus.
2401 *
2402 * Returns the value of xslDebugStatus.
2403 */
2404 int
2405 xsltGetDebuggerStatus(void)
2406 {
2407 return(xslDebugStatus);
2408 }
2409
2410 /**
2411 * xsltSetDebuggerCallbacks:
2412 * @no : number of callbacks
2413 * @block : the block of callbacks
2414 *
2415 * This function allow to plug a debugger into the XSLT library
2416 * @block points to a block of memory containing the address of @no
2417 * callback routines.
2418 *
2419 * Returns 0 in case of success and -1 in case of error
2420 */
2421 int
2422 xsltSetDebuggerCallbacks(int no, void *block)
2423 {
2424 xsltDebuggerCallbacksPtr callbacks;
2425
2426 if ((block == NULL) || (no != XSLT_CALLBACK_NUMBER))
2427 return(-1);
2428
2429 callbacks = (xsltDebuggerCallbacksPtr) block;
2430 xsltDebuggerCurrentCallbacks.handler = callbacks->handler;
2431 xsltDebuggerCurrentCallbacks.add = callbacks->add;
2432 xsltDebuggerCurrentCallbacks.drop = callbacks->drop;
2433 return(0);
2434 }
2435
2436 /**
2437 * xslHandleDebugger:
2438 * @cur : source node being executed
2439 * @node : data node being processed
2440 * @templ : temlate that applies to node
2441 * @ctxt : the xslt transform context
2442 *
2443 * If either cur or node are a breakpoint, or xslDebugStatus in state
2444 * where debugging must occcur at this time then transfer control
2445 * to the xslDebugBreak function
2446 */
2447 void
2448 xslHandleDebugger(xmlNodePtr cur, xmlNodePtr node, xsltTemplatePtr templ,
2449 xsltTransformContextPtr ctxt)
2450 {
2451 if (xsltDebuggerCurrentCallbacks.handler != NULL)
2452 xsltDebuggerCurrentCallbacks.handler(cur, node, templ, ctxt);
2453 }
2454
2455 /**
2456 * xslAddCall:
2457 * @templ : current template being applied
2458 * @source : the source node being processed
2459 *
2460 * Add template "call" to call stack
2461 * Returns : 1 on sucess 0 otherwise an error may be printed if
2462 * WITH_XSLT_DEBUG_BREAKPOINTS is defined
2463 */
2464 int
2465 xslAddCall(xsltTemplatePtr templ, xmlNodePtr source)
2466 {
2467 if (xsltDebuggerCurrentCallbacks.add != NULL)
2468 return(xsltDebuggerCurrentCallbacks.add(templ, source));
2469 return(0);
2470 }
2471
2472 /**
2473 * xslDropCall:
2474 *
2475 * Drop the topmost item off the call stack
2476 */
2477 void
2478 xslDropCall(void)
2479 {
2480 if (xsltDebuggerCurrentCallbacks.drop != NULL)
2481 xsltDebuggerCurrentCallbacks.drop();
2482 }
2483
OLDNEW
« no previous file with comments | « third_party/libxslt/libxslt/xsltutils.h ('k') | third_party/libxslt/libxslt/xsltwin32config.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698