xsltutils.c 66 KB

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