xsltutils.c 67 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515
  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 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 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
  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. * xsltComputeSortResultiInternal:
  873. * @ctxt: a XSLT process context
  874. * @sort: node list
  875. * @xfrm: Transform strings according to locale
  876. *
  877. * reorder the current node list accordingly to the set of sorting
  878. * requirement provided by the array of nodes.
  879. *
  880. * Returns a ordered XPath nodeset or NULL in case of error.
  881. */
  882. static xmlXPathObjectPtr *
  883. xsltComputeSortResultInternal(xsltTransformContextPtr ctxt, xmlNodePtr sort,
  884. int xfrm) {
  885. #ifdef XSLT_REFACTORED
  886. xsltStyleItemSortPtr comp;
  887. #else
  888. xsltStylePreCompPtr comp;
  889. #endif
  890. xmlXPathObjectPtr *results = NULL;
  891. xmlNodeSetPtr list = NULL;
  892. xmlXPathObjectPtr res;
  893. int len = 0;
  894. int i;
  895. xmlNodePtr oldNode;
  896. xmlNodePtr oldInst;
  897. int oldPos, oldSize ;
  898. int oldNsNr;
  899. xmlNsPtr *oldNamespaces;
  900. comp = sort->psvi;
  901. if (comp == NULL) {
  902. xsltGenericError(xsltGenericErrorContext,
  903. "xsl:sort : compilation failed\n");
  904. return(NULL);
  905. }
  906. if ((comp->select == NULL) || (comp->comp == NULL))
  907. return(NULL);
  908. list = ctxt->nodeList;
  909. if ((list == NULL) || (list->nodeNr <= 1))
  910. return(NULL);
  911. len = list->nodeNr;
  912. /* TODO: xsl:sort lang attribute */
  913. /* TODO: xsl:sort case-order attribute */
  914. results = xmlMalloc(len * sizeof(xmlXPathObjectPtr));
  915. if (results == NULL) {
  916. xsltGenericError(xsltGenericErrorContext,
  917. "xsltComputeSortResult: memory allocation failure\n");
  918. return(NULL);
  919. }
  920. oldNode = ctxt->node;
  921. oldInst = ctxt->inst;
  922. oldPos = ctxt->xpathCtxt->proximityPosition;
  923. oldSize = ctxt->xpathCtxt->contextSize;
  924. oldNsNr = ctxt->xpathCtxt->nsNr;
  925. oldNamespaces = ctxt->xpathCtxt->namespaces;
  926. for (i = 0;i < len;i++) {
  927. ctxt->inst = sort;
  928. ctxt->xpathCtxt->contextSize = len;
  929. ctxt->xpathCtxt->proximityPosition = i + 1;
  930. ctxt->node = list->nodeTab[i];
  931. ctxt->xpathCtxt->node = ctxt->node;
  932. #ifdef XSLT_REFACTORED
  933. if (comp->inScopeNs != NULL) {
  934. ctxt->xpathCtxt->namespaces = comp->inScopeNs->list;
  935. ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber;
  936. } else {
  937. ctxt->xpathCtxt->namespaces = NULL;
  938. ctxt->xpathCtxt->nsNr = 0;
  939. }
  940. #else
  941. ctxt->xpathCtxt->namespaces = comp->nsList;
  942. ctxt->xpathCtxt->nsNr = comp->nsNr;
  943. #endif
  944. res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);
  945. if (res != NULL) {
  946. if (res->type != XPATH_STRING)
  947. res = xmlXPathConvertString(res);
  948. if (comp->number)
  949. res = xmlXPathConvertNumber(res);
  950. res->index = i; /* Save original pos for dupl resolv */
  951. if (comp->number) {
  952. if (res->type == XPATH_NUMBER) {
  953. results[i] = res;
  954. } else {
  955. #ifdef WITH_XSLT_DEBUG_PROCESS
  956. xsltGenericDebug(xsltGenericDebugContext,
  957. "xsltComputeSortResult: select didn't evaluate to a number\n");
  958. #endif
  959. results[i] = NULL;
  960. }
  961. } else {
  962. if (res->type == XPATH_STRING) {
  963. if ((xfrm) && (comp->locale != (xsltLocale)0)) {
  964. xmlChar *str = res->stringval;
  965. res->stringval = (xmlChar *) xsltStrxfrm(comp->locale, str);
  966. xmlFree(str);
  967. }
  968. results[i] = res;
  969. } else {
  970. #ifdef WITH_XSLT_DEBUG_PROCESS
  971. xsltGenericDebug(xsltGenericDebugContext,
  972. "xsltComputeSortResult: select didn't evaluate to a string\n");
  973. #endif
  974. results[i] = NULL;
  975. }
  976. }
  977. } else {
  978. ctxt->state = XSLT_STATE_STOPPED;
  979. results[i] = NULL;
  980. }
  981. }
  982. ctxt->node = oldNode;
  983. ctxt->inst = oldInst;
  984. ctxt->xpathCtxt->contextSize = oldSize;
  985. ctxt->xpathCtxt->proximityPosition = oldPos;
  986. ctxt->xpathCtxt->nsNr = oldNsNr;
  987. ctxt->xpathCtxt->namespaces = oldNamespaces;
  988. return(results);
  989. }
  990. /**
  991. * xsltComputeSortResult:
  992. * @ctxt: a XSLT process context
  993. * @sort: node list
  994. *
  995. * reorder the current node list accordingly to the set of sorting
  996. * requirement provided by the array of nodes.
  997. *
  998. * Returns a ordered XPath nodeset or NULL in case of error.
  999. */
  1000. xmlXPathObjectPtr *
  1001. xsltComputeSortResult(xsltTransformContextPtr ctxt, xmlNodePtr sort) {
  1002. return xsltComputeSortResultInternal(ctxt, sort, /* xfrm */ 0);
  1003. }
  1004. /**
  1005. * xsltDefaultSortFunction:
  1006. * @ctxt: a XSLT process context
  1007. * @sorts: array of sort nodes
  1008. * @nbsorts: the number of sorts in the array
  1009. *
  1010. * reorder the current node list accordingly to the set of sorting
  1011. * requirement provided by the arry of nodes.
  1012. */
  1013. void
  1014. xsltDefaultSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts,
  1015. int nbsorts) {
  1016. #ifdef XSLT_REFACTORED
  1017. xsltStyleItemSortPtr comp;
  1018. #else
  1019. xsltStylePreCompPtr comp;
  1020. #endif
  1021. xmlXPathObjectPtr *resultsTab[XSLT_MAX_SORT];
  1022. xmlXPathObjectPtr *results = NULL, *res;
  1023. xmlNodeSetPtr list = NULL;
  1024. int descending, number, desc, numb;
  1025. int len = 0;
  1026. int i, j, incr;
  1027. int tst;
  1028. int depth;
  1029. xmlNodePtr node;
  1030. xmlXPathObjectPtr tmp;
  1031. int tempstype[XSLT_MAX_SORT], temporder[XSLT_MAX_SORT],
  1032. templang[XSLT_MAX_SORT];
  1033. if ((ctxt == NULL) || (sorts == NULL) || (nbsorts <= 0) ||
  1034. (nbsorts >= XSLT_MAX_SORT))
  1035. return;
  1036. if (sorts[0] == NULL)
  1037. return;
  1038. comp = sorts[0]->psvi;
  1039. if (comp == NULL)
  1040. return;
  1041. list = ctxt->nodeList;
  1042. if ((list == NULL) || (list->nodeNr <= 1))
  1043. return; /* nothing to do */
  1044. for (j = 0; j < nbsorts; j++) {
  1045. comp = sorts[j]->psvi;
  1046. tempstype[j] = 0;
  1047. if ((comp->stype == NULL) && (comp->has_stype != 0)) {
  1048. comp->stype =
  1049. xsltEvalAttrValueTemplate(ctxt, sorts[j],
  1050. (const xmlChar *) "data-type",
  1051. NULL);
  1052. if (comp->stype != NULL) {
  1053. tempstype[j] = 1;
  1054. if (xmlStrEqual(comp->stype, (const xmlChar *) "text"))
  1055. comp->number = 0;
  1056. else if (xmlStrEqual(comp->stype, (const xmlChar *) "number"))
  1057. comp->number = 1;
  1058. else {
  1059. xsltTransformError(ctxt, NULL, sorts[j],
  1060. "xsltDoSortFunction: no support for data-type = %s\n",
  1061. comp->stype);
  1062. comp->number = 0; /* use default */
  1063. }
  1064. }
  1065. }
  1066. temporder[j] = 0;
  1067. if ((comp->order == NULL) && (comp->has_order != 0)) {
  1068. comp->order = xsltEvalAttrValueTemplate(ctxt, sorts[j],
  1069. (const xmlChar *) "order",
  1070. NULL);
  1071. if (comp->order != NULL) {
  1072. temporder[j] = 1;
  1073. if (xmlStrEqual(comp->order, (const xmlChar *) "ascending"))
  1074. comp->descending = 0;
  1075. else if (xmlStrEqual(comp->order,
  1076. (const xmlChar *) "descending"))
  1077. comp->descending = 1;
  1078. else {
  1079. xsltTransformError(ctxt, NULL, sorts[j],
  1080. "xsltDoSortFunction: invalid value %s for order\n",
  1081. comp->order);
  1082. comp->descending = 0; /* use default */
  1083. }
  1084. }
  1085. }
  1086. templang[j] = 0;
  1087. if ((comp->lang == NULL) && (comp->has_lang != 0)) {
  1088. xmlChar *lang = xsltEvalAttrValueTemplate(ctxt, sorts[j],
  1089. (xmlChar *) "lang",
  1090. NULL);
  1091. if (lang != NULL) {
  1092. templang[j] = 1;
  1093. comp->locale = xsltNewLocale(lang);
  1094. xmlFree(lang);
  1095. }
  1096. }
  1097. }
  1098. len = list->nodeNr;
  1099. resultsTab[0] = xsltComputeSortResultInternal(ctxt, sorts[0],
  1100. /* xfrm */ 1);
  1101. for (i = 1;i < XSLT_MAX_SORT;i++)
  1102. resultsTab[i] = NULL;
  1103. results = resultsTab[0];
  1104. comp = sorts[0]->psvi;
  1105. descending = comp->descending;
  1106. number = comp->number;
  1107. if (results == NULL)
  1108. goto cleanup;
  1109. /* Shell's sort of node-set */
  1110. for (incr = len / 2; incr > 0; incr /= 2) {
  1111. for (i = incr; i < len; i++) {
  1112. j = i - incr;
  1113. if (results[i] == NULL)
  1114. continue;
  1115. while (j >= 0) {
  1116. if (results[j] == NULL)
  1117. tst = 1;
  1118. else {
  1119. if (number) {
  1120. /* We make NaN smaller than number in accordance
  1121. with XSLT spec */
  1122. if (xmlXPathIsNaN(results[j]->floatval)) {
  1123. if (xmlXPathIsNaN(results[j + incr]->floatval))
  1124. tst = 0;
  1125. else
  1126. tst = -1;
  1127. } else if (xmlXPathIsNaN(results[j + incr]->floatval))
  1128. tst = 1;
  1129. else if (results[j]->floatval ==
  1130. results[j + incr]->floatval)
  1131. tst = 0;
  1132. else if (results[j]->floatval >
  1133. results[j + incr]->floatval)
  1134. tst = 1;
  1135. else tst = -1;
  1136. } else if(comp->locale != (xsltLocale)0) {
  1137. tst = xsltLocaleStrcmp(
  1138. comp->locale,
  1139. (xsltLocaleChar *) results[j]->stringval,
  1140. (xsltLocaleChar *) results[j + incr]->stringval);
  1141. } else {
  1142. tst = xmlStrcmp(results[j]->stringval,
  1143. results[j + incr]->stringval);
  1144. }
  1145. if (descending)
  1146. tst = -tst;
  1147. }
  1148. if (tst == 0) {
  1149. /*
  1150. * Okay we need to use multi level sorts
  1151. */
  1152. depth = 1;
  1153. while (depth < nbsorts) {
  1154. if (sorts[depth] == NULL)
  1155. break;
  1156. comp = sorts[depth]->psvi;
  1157. if (comp == NULL)
  1158. break;
  1159. desc = comp->descending;
  1160. numb = comp->number;
  1161. /*
  1162. * Compute the result of the next level for the
  1163. * full set, this might be optimized ... or not
  1164. */
  1165. if (resultsTab[depth] == NULL)
  1166. resultsTab[depth] =
  1167. xsltComputeSortResultInternal(ctxt,
  1168. sorts[depth],
  1169. /* xfrm */ 1);
  1170. res = resultsTab[depth];
  1171. if (res == NULL)
  1172. break;
  1173. if (res[j] == NULL) {
  1174. if (res[j+incr] != NULL)
  1175. tst = 1;
  1176. } else if (res[j+incr] == NULL) {
  1177. tst = -1;
  1178. } else {
  1179. if (numb) {
  1180. /* We make NaN smaller than number in
  1181. accordance with XSLT spec */
  1182. if (xmlXPathIsNaN(res[j]->floatval)) {
  1183. if (xmlXPathIsNaN(res[j +
  1184. incr]->floatval))
  1185. tst = 0;
  1186. else
  1187. tst = -1;
  1188. } else if (xmlXPathIsNaN(res[j + incr]->
  1189. floatval))
  1190. tst = 1;
  1191. else if (res[j]->floatval == res[j + incr]->
  1192. floatval)
  1193. tst = 0;
  1194. else if (res[j]->floatval >
  1195. res[j + incr]->floatval)
  1196. tst = 1;
  1197. else tst = -1;
  1198. } else if(comp->locale != (xsltLocale)0) {
  1199. tst = xsltLocaleStrcmp(
  1200. comp->locale,
  1201. (xsltLocaleChar *) res[j]->stringval,
  1202. (xsltLocaleChar *) res[j + incr]->stringval);
  1203. } else {
  1204. tst = xmlStrcmp(res[j]->stringval,
  1205. res[j + incr]->stringval);
  1206. }
  1207. if (desc)
  1208. tst = -tst;
  1209. }
  1210. /*
  1211. * if we still can't differenciate at this level
  1212. * try one level deeper.
  1213. */
  1214. if (tst != 0)
  1215. break;
  1216. depth++;
  1217. }
  1218. }
  1219. if (tst == 0) {
  1220. tst = results[j]->index > results[j + incr]->index;
  1221. }
  1222. if (tst > 0) {
  1223. tmp = results[j];
  1224. results[j] = results[j + incr];
  1225. results[j + incr] = tmp;
  1226. node = list->nodeTab[j];
  1227. list->nodeTab[j] = list->nodeTab[j + incr];
  1228. list->nodeTab[j + incr] = node;
  1229. depth = 1;
  1230. while (depth < nbsorts) {
  1231. if (sorts[depth] == NULL)
  1232. break;
  1233. if (resultsTab[depth] == NULL)
  1234. break;
  1235. res = resultsTab[depth];
  1236. tmp = res[j];
  1237. res[j] = res[j + incr];
  1238. res[j + incr] = tmp;
  1239. depth++;
  1240. }
  1241. j -= incr;
  1242. } else
  1243. break;
  1244. }
  1245. }
  1246. }
  1247. cleanup:
  1248. for (j = 0; j < nbsorts; j++) {
  1249. comp = sorts[j]->psvi;
  1250. if (tempstype[j] == 1) {
  1251. /* The data-type needs to be recomputed each time */
  1252. xmlFree((void *)(comp->stype));
  1253. comp->stype = NULL;
  1254. }
  1255. if (temporder[j] == 1) {
  1256. /* The order needs to be recomputed each time */
  1257. xmlFree((void *)(comp->order));
  1258. comp->order = NULL;
  1259. }
  1260. if (templang[j] == 1) {
  1261. xsltFreeLocale(comp->locale);
  1262. comp->locale = (xsltLocale)0;
  1263. }
  1264. if (resultsTab[j] != NULL) {
  1265. for (i = 0;i < len;i++)
  1266. xmlXPathFreeObject(resultsTab[j][i]);
  1267. xmlFree(resultsTab[j]);
  1268. }
  1269. }
  1270. }
  1271. static xsltSortFunc xsltSortFunction = xsltDefaultSortFunction;
  1272. /**
  1273. * xsltDoSortFunction:
  1274. * @ctxt: a XSLT process context
  1275. * @sorts: array of sort nodes
  1276. * @nbsorts: the number of sorts in the array
  1277. *
  1278. * reorder the current node list accordingly to the set of sorting
  1279. * requirement provided by the arry of nodes.
  1280. * This is a wrapper function, the actual function used is specified
  1281. * using xsltSetCtxtSortFunc() to set the context specific sort function,
  1282. * or xsltSetSortFunc() to set the global sort function.
  1283. * If a sort function is set on the context, this will get called.
  1284. * Otherwise the global sort function is called.
  1285. */
  1286. void
  1287. xsltDoSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr * sorts,
  1288. int nbsorts)
  1289. {
  1290. if (ctxt->sortfunc != NULL)
  1291. (ctxt->sortfunc)(ctxt, sorts, nbsorts);
  1292. else if (xsltSortFunction != NULL)
  1293. xsltSortFunction(ctxt, sorts, nbsorts);
  1294. }
  1295. /**
  1296. * xsltSetSortFunc:
  1297. * @handler: the new handler function
  1298. *
  1299. * Function to reset the global handler for XSLT sorting.
  1300. * If the handler is NULL, the default sort function will be used.
  1301. */
  1302. void
  1303. xsltSetSortFunc(xsltSortFunc handler) {
  1304. if (handler != NULL)
  1305. xsltSortFunction = handler;
  1306. else
  1307. xsltSortFunction = xsltDefaultSortFunction;
  1308. }
  1309. /**
  1310. * xsltSetCtxtSortFunc:
  1311. * @ctxt: a XSLT process context
  1312. * @handler: the new handler function
  1313. *
  1314. * Function to set the handler for XSLT sorting
  1315. * for the specified context.
  1316. * If the handler is NULL, then the global
  1317. * sort function will be called
  1318. */
  1319. void
  1320. xsltSetCtxtSortFunc(xsltTransformContextPtr ctxt, xsltSortFunc handler) {
  1321. ctxt->sortfunc = handler;
  1322. }
  1323. /************************************************************************
  1324. * *
  1325. * Parsing options *
  1326. * *
  1327. ************************************************************************/
  1328. /**
  1329. * xsltSetCtxtParseOptions:
  1330. * @ctxt: a XSLT process context
  1331. * @options: a combination of libxml2 xmlParserOption
  1332. *
  1333. * Change the default parser option passed by the XSLT engine to the
  1334. * parser when using document() loading.
  1335. *
  1336. * Returns the previous options or -1 in case of error
  1337. */
  1338. int
  1339. xsltSetCtxtParseOptions(xsltTransformContextPtr ctxt, int options)
  1340. {
  1341. int oldopts;
  1342. if (ctxt == NULL)
  1343. return(-1);
  1344. oldopts = ctxt->parserOptions;
  1345. if (ctxt->xinclude)
  1346. oldopts |= XML_PARSE_XINCLUDE;
  1347. ctxt->parserOptions = options;
  1348. if (options & XML_PARSE_XINCLUDE)
  1349. ctxt->xinclude = 1;
  1350. else
  1351. ctxt->xinclude = 0;
  1352. return(oldopts);
  1353. }
  1354. /************************************************************************
  1355. * *
  1356. * Output *
  1357. * *
  1358. ************************************************************************/
  1359. /**
  1360. * xsltSaveResultTo:
  1361. * @buf: an output buffer
  1362. * @result: the result xmlDocPtr
  1363. * @style: the stylesheet
  1364. *
  1365. * Save the result @result obtained by applying the @style stylesheet
  1366. * to an I/O output channel @buf
  1367. *
  1368. * Returns the number of byte written or -1 in case of failure.
  1369. */
  1370. int
  1371. xsltSaveResultTo(xmlOutputBufferPtr buf, xmlDocPtr result,
  1372. xsltStylesheetPtr style) {
  1373. const xmlChar *encoding;
  1374. int base;
  1375. const xmlChar *method;
  1376. int indent;
  1377. if ((buf == NULL) || (result == NULL) || (style == NULL))
  1378. return(-1);
  1379. if ((result->children == NULL) ||
  1380. ((result->children->type == XML_DTD_NODE) &&
  1381. (result->children->next == NULL)))
  1382. return(0);
  1383. if ((style->methodURI != NULL) &&
  1384. ((style->method == NULL) ||
  1385. (!xmlStrEqual(style->method, (const xmlChar *) "xhtml")))) {
  1386. xsltGenericError(xsltGenericErrorContext,
  1387. "xsltSaveResultTo : unknown output method\n");
  1388. return(-1);
  1389. }
  1390. base = buf->written;
  1391. XSLT_GET_IMPORT_PTR(method, style, method)
  1392. XSLT_GET_IMPORT_PTR(encoding, style, encoding)
  1393. XSLT_GET_IMPORT_INT(indent, style, indent);
  1394. if ((method == NULL) && (result->type == XML_HTML_DOCUMENT_NODE))
  1395. method = (const xmlChar *) "html";
  1396. if ((method != NULL) &&
  1397. (xmlStrEqual(method, (const xmlChar *) "html"))) {
  1398. if (encoding != NULL) {
  1399. htmlSetMetaEncoding(result, (const xmlChar *) encoding);
  1400. } else {
  1401. htmlSetMetaEncoding(result, (const xmlChar *) "UTF-8");
  1402. }
  1403. if (indent == -1)
  1404. indent = 1;
  1405. htmlDocContentDumpFormatOutput(buf, result, (const char *) encoding,
  1406. indent);
  1407. xmlOutputBufferFlush(buf);
  1408. } else if ((method != NULL) &&
  1409. (xmlStrEqual(method, (const xmlChar *) "xhtml"))) {
  1410. if (encoding != NULL) {
  1411. htmlSetMetaEncoding(result, (const xmlChar *) encoding);
  1412. } else {
  1413. htmlSetMetaEncoding(result, (const xmlChar *) "UTF-8");
  1414. }
  1415. htmlDocContentDumpOutput(buf, result, (const char *) encoding);
  1416. xmlOutputBufferFlush(buf);
  1417. } else if ((method != NULL) &&
  1418. (xmlStrEqual(method, (const xmlChar *) "text"))) {
  1419. xmlNodePtr cur;
  1420. cur = result->children;
  1421. while (cur != NULL) {
  1422. if (cur->type == XML_TEXT_NODE)
  1423. xmlOutputBufferWriteString(buf, (const char *) cur->content);
  1424. /*
  1425. * Skip to next node
  1426. */
  1427. if (cur->children != NULL) {
  1428. if ((cur->children->type != XML_ENTITY_DECL) &&
  1429. (cur->children->type != XML_ENTITY_REF_NODE) &&
  1430. (cur->children->type != XML_ENTITY_NODE)) {
  1431. cur = cur->children;
  1432. continue;
  1433. }
  1434. }
  1435. if (cur->next != NULL) {
  1436. cur = cur->next;
  1437. continue;
  1438. }
  1439. do {
  1440. cur = cur->parent;
  1441. if (cur == NULL)
  1442. break;
  1443. if (cur == (xmlNodePtr) style->doc) {
  1444. cur = NULL;
  1445. break;
  1446. }
  1447. if (cur->next != NULL) {
  1448. cur = cur->next;
  1449. break;
  1450. }
  1451. } while (cur != NULL);
  1452. }
  1453. xmlOutputBufferFlush(buf);
  1454. } else {
  1455. int omitXmlDecl;
  1456. int standalone;
  1457. XSLT_GET_IMPORT_INT(omitXmlDecl, style, omitXmlDeclaration);
  1458. XSLT_GET_IMPORT_INT(standalone, style, standalone);
  1459. if (omitXmlDecl != 1) {
  1460. xmlOutputBufferWriteString(buf, "<?xml version=");
  1461. if (result->version != NULL) {
  1462. xmlOutputBufferWriteString(buf, "\"");
  1463. xmlOutputBufferWriteString(buf, (const char *)result->version);
  1464. xmlOutputBufferWriteString(buf, "\"");
  1465. } else
  1466. xmlOutputBufferWriteString(buf, "\"1.0\"");
  1467. if (encoding == NULL) {
  1468. if (result->encoding != NULL)
  1469. encoding = result->encoding;
  1470. else if (result->charset != XML_CHAR_ENCODING_UTF8)
  1471. encoding = (const xmlChar *)
  1472. xmlGetCharEncodingName((xmlCharEncoding)
  1473. result->charset);
  1474. }
  1475. if (encoding != NULL) {
  1476. xmlOutputBufferWriteString(buf, " encoding=");
  1477. xmlOutputBufferWriteString(buf, "\"");
  1478. xmlOutputBufferWriteString(buf, (const char *) encoding);
  1479. xmlOutputBufferWriteString(buf, "\"");
  1480. }
  1481. switch (standalone) {
  1482. case 0:
  1483. xmlOutputBufferWriteString(buf, " standalone=\"no\"");
  1484. break;
  1485. case 1:
  1486. xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
  1487. break;
  1488. default:
  1489. break;
  1490. }
  1491. xmlOutputBufferWriteString(buf, "?>\n");
  1492. }
  1493. if (result->children != NULL) {
  1494. xmlNodePtr children = result->children;
  1495. xmlNodePtr child = children;
  1496. /*
  1497. * Hack to avoid quadratic behavior when scanning
  1498. * result->children in xmlGetIntSubset called by
  1499. * xmlNodeDumpOutput.
  1500. */
  1501. result->children = NULL;
  1502. while (child != NULL) {
  1503. xmlNodeDumpOutput(buf, result, child, 0, (indent == 1),
  1504. (const char *) encoding);
  1505. if (indent && ((child->type == XML_DTD_NODE) ||
  1506. ((child->type == XML_COMMENT_NODE) &&
  1507. (child->next != NULL))))
  1508. xmlOutputBufferWriteString(buf, "\n");
  1509. child = child->next;
  1510. }
  1511. if (indent)
  1512. xmlOutputBufferWriteString(buf, "\n");
  1513. result->children = children;
  1514. }
  1515. xmlOutputBufferFlush(buf);
  1516. }
  1517. return(buf->written - base);
  1518. }
  1519. /**
  1520. * xsltSaveResultToFilename:
  1521. * @URL: a filename or URL
  1522. * @result: the result xmlDocPtr
  1523. * @style: the stylesheet
  1524. * @compression: the compression factor (0 - 9 included)
  1525. *
  1526. * Save the result @result obtained by applying the @style stylesheet
  1527. * to a file or @URL
  1528. *
  1529. * Returns the number of byte written or -1 in case of failure.
  1530. */
  1531. int
  1532. xsltSaveResultToFilename(const char *URL, xmlDocPtr result,
  1533. xsltStylesheetPtr style, int compression) {
  1534. xmlOutputBufferPtr buf;
  1535. const xmlChar *encoding;
  1536. int ret;
  1537. if ((URL == NULL) || (result == NULL) || (style == NULL))
  1538. return(-1);
  1539. if (result->children == NULL)
  1540. return(0);
  1541. XSLT_GET_IMPORT_PTR(encoding, style, encoding)
  1542. if (encoding != NULL) {
  1543. xmlCharEncodingHandlerPtr encoder;
  1544. encoder = xmlFindCharEncodingHandler((char *)encoding);
  1545. if ((encoder != NULL) &&
  1546. (xmlStrEqual((const xmlChar *)encoder->name,
  1547. (const xmlChar *) "UTF-8")))
  1548. encoder = NULL;
  1549. buf = xmlOutputBufferCreateFilename(URL, encoder, compression);
  1550. } else {
  1551. buf = xmlOutputBufferCreateFilename(URL, NULL, compression);
  1552. }
  1553. if (buf == NULL)
  1554. return(-1);
  1555. xsltSaveResultTo(buf, result, style);
  1556. ret = xmlOutputBufferClose(buf);
  1557. return(ret);
  1558. }
  1559. /**
  1560. * xsltSaveResultToFile:
  1561. * @file: a FILE * I/O
  1562. * @result: the result xmlDocPtr
  1563. * @style: the stylesheet
  1564. *
  1565. * Save the result @result obtained by applying the @style stylesheet
  1566. * to an open FILE * I/O.
  1567. * This does not close the FILE @file
  1568. *
  1569. * Returns the number of bytes written or -1 in case of failure.
  1570. */
  1571. int
  1572. xsltSaveResultToFile(FILE *file, xmlDocPtr result, xsltStylesheetPtr style) {
  1573. xmlOutputBufferPtr buf;
  1574. const xmlChar *encoding;
  1575. int ret;
  1576. if ((file == NULL) || (result == NULL) || (style == NULL))
  1577. return(-1);
  1578. if (result->children == NULL)
  1579. return(0);
  1580. XSLT_GET_IMPORT_PTR(encoding, style, encoding)
  1581. if (encoding != NULL) {
  1582. xmlCharEncodingHandlerPtr encoder;
  1583. encoder = xmlFindCharEncodingHandler((char *)encoding);
  1584. if ((encoder != NULL) &&
  1585. (xmlStrEqual((const xmlChar *)encoder->name,
  1586. (const xmlChar *) "UTF-8")))
  1587. encoder = NULL;
  1588. buf = xmlOutputBufferCreateFile(file, encoder);
  1589. } else {
  1590. buf = xmlOutputBufferCreateFile(file, NULL);
  1591. }
  1592. if (buf == NULL)
  1593. return(-1);
  1594. xsltSaveResultTo(buf, result, style);
  1595. ret = xmlOutputBufferClose(buf);
  1596. return(ret);
  1597. }
  1598. /**
  1599. * xsltSaveResultToFd:
  1600. * @fd: a file descriptor
  1601. * @result: the result xmlDocPtr
  1602. * @style: the stylesheet
  1603. *
  1604. * Save the result @result obtained by applying the @style stylesheet
  1605. * to an open file descriptor
  1606. * This does not close the descriptor.
  1607. *
  1608. * Returns the number of bytes written or -1 in case of failure.
  1609. */
  1610. int
  1611. xsltSaveResultToFd(int fd, xmlDocPtr result, xsltStylesheetPtr style) {
  1612. xmlOutputBufferPtr buf;
  1613. const xmlChar *encoding;
  1614. int ret;
  1615. if ((fd < 0) || (result == NULL) || (style == NULL))
  1616. return(-1);
  1617. if (result->children == NULL)
  1618. return(0);
  1619. XSLT_GET_IMPORT_PTR(encoding, style, encoding)
  1620. if (encoding != NULL) {
  1621. xmlCharEncodingHandlerPtr encoder;
  1622. encoder = xmlFindCharEncodingHandler((char *)encoding);
  1623. if ((encoder != NULL) &&
  1624. (xmlStrEqual((const xmlChar *)encoder->name,
  1625. (const xmlChar *) "UTF-8")))
  1626. encoder = NULL;
  1627. buf = xmlOutputBufferCreateFd(fd, encoder);
  1628. } else {
  1629. buf = xmlOutputBufferCreateFd(fd, NULL);
  1630. }
  1631. if (buf == NULL)
  1632. return(-1);
  1633. xsltSaveResultTo(buf, result, style);
  1634. ret = xmlOutputBufferClose(buf);
  1635. return(ret);
  1636. }
  1637. /**
  1638. * xsltSaveResultToString:
  1639. * @doc_txt_ptr: Memory pointer for allocated XML text
  1640. * @doc_txt_len: Length of the generated XML text
  1641. * @result: the result xmlDocPtr
  1642. * @style: the stylesheet
  1643. *
  1644. * Save the result @result obtained by applying the @style stylesheet
  1645. * to a new allocated string.
  1646. *
  1647. * Returns 0 in case of success and -1 in case of error
  1648. */
  1649. int
  1650. xsltSaveResultToString(xmlChar **doc_txt_ptr, int * doc_txt_len,
  1651. xmlDocPtr result, xsltStylesheetPtr style) {
  1652. xmlOutputBufferPtr buf;
  1653. const xmlChar *encoding;
  1654. *doc_txt_ptr = NULL;
  1655. *doc_txt_len = 0;
  1656. if (result->children == NULL)
  1657. return(0);
  1658. XSLT_GET_IMPORT_PTR(encoding, style, encoding)
  1659. if (encoding != NULL) {
  1660. xmlCharEncodingHandlerPtr encoder;
  1661. encoder = xmlFindCharEncodingHandler((char *)encoding);
  1662. if ((encoder != NULL) &&
  1663. (xmlStrEqual((const xmlChar *)encoder->name,
  1664. (const xmlChar *) "UTF-8")))
  1665. encoder = NULL;
  1666. buf = xmlAllocOutputBuffer(encoder);
  1667. } else {
  1668. buf = xmlAllocOutputBuffer(NULL);
  1669. }
  1670. if (buf == NULL)
  1671. return(-1);
  1672. xsltSaveResultTo(buf, result, style);
  1673. #ifdef LIBXML2_NEW_BUFFER
  1674. if (buf->conv != NULL) {
  1675. *doc_txt_len = xmlBufUse(buf->conv);
  1676. *doc_txt_ptr = xmlStrndup(xmlBufContent(buf->conv), *doc_txt_len);
  1677. } else {
  1678. *doc_txt_len = xmlBufUse(buf->buffer);
  1679. *doc_txt_ptr = xmlStrndup(xmlBufContent(buf->buffer), *doc_txt_len);
  1680. }
  1681. #else
  1682. if (buf->conv != NULL) {
  1683. *doc_txt_len = buf->conv->use;
  1684. *doc_txt_ptr = xmlStrndup(buf->conv->content, *doc_txt_len);
  1685. } else {
  1686. *doc_txt_len = buf->buffer->use;
  1687. *doc_txt_ptr = xmlStrndup(buf->buffer->content, *doc_txt_len);
  1688. }
  1689. #endif
  1690. (void)xmlOutputBufferClose(buf);
  1691. return 0;
  1692. }
  1693. #ifdef WITH_PROFILER
  1694. /************************************************************************
  1695. * *
  1696. * Generating profiling information *
  1697. * *
  1698. ************************************************************************/
  1699. static long calibration = -1;
  1700. /**
  1701. * xsltCalibrateTimestamps:
  1702. *
  1703. * Used for to calibrate the xsltTimestamp() function
  1704. * Should work if launched at startup and we don't loose our quantum :-)
  1705. *
  1706. * Returns the number of milliseconds used by xsltTimestamp()
  1707. */
  1708. #if !defined(XSLT_WIN32_PERFORMANCE_COUNTER) && \
  1709. (defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETTIMEOFDAY))
  1710. static long
  1711. xsltCalibrateTimestamps(void) {
  1712. register int i;
  1713. for (i = 0;i < 999;i++)
  1714. xsltTimestamp();
  1715. return(xsltTimestamp() / 1000);
  1716. }
  1717. #endif
  1718. /**
  1719. * xsltCalibrateAdjust:
  1720. * @delta: a negative dealy value found
  1721. *
  1722. * Used for to correct the calibration for xsltTimestamp()
  1723. */
  1724. void
  1725. xsltCalibrateAdjust(long delta) {
  1726. calibration += delta;
  1727. }
  1728. /**
  1729. * xsltTimestamp:
  1730. *
  1731. * Used for gathering profiling data
  1732. *
  1733. * Returns the number of tenth of milliseconds since the beginning of the
  1734. * profiling
  1735. */
  1736. long
  1737. xsltTimestamp(void)
  1738. {
  1739. #ifdef XSLT_WIN32_PERFORMANCE_COUNTER
  1740. BOOL ok;
  1741. LARGE_INTEGER performanceCount;
  1742. LARGE_INTEGER performanceFrequency;
  1743. LONGLONG quadCount;
  1744. double seconds;
  1745. static LONGLONG startupQuadCount = 0;
  1746. static LONGLONG startupQuadFreq = 0;
  1747. ok = QueryPerformanceCounter(&performanceCount);
  1748. if (!ok)
  1749. return 0;
  1750. quadCount = performanceCount.QuadPart;
  1751. if (calibration < 0) {
  1752. calibration = 0;
  1753. ok = QueryPerformanceFrequency(&performanceFrequency);
  1754. if (!ok)
  1755. return 0;
  1756. startupQuadFreq = performanceFrequency.QuadPart;
  1757. startupQuadCount = quadCount;
  1758. return (0);
  1759. }
  1760. if (startupQuadFreq == 0)
  1761. return 0;
  1762. seconds = (quadCount - startupQuadCount) / (double) startupQuadFreq;
  1763. return (long) (seconds * XSLT_TIMESTAMP_TICS_PER_SEC);
  1764. #else /* XSLT_WIN32_PERFORMANCE_COUNTER */
  1765. #ifdef HAVE_CLOCK_GETTIME
  1766. # if defined(CLOCK_MONOTONIC)
  1767. # define XSLT_CLOCK CLOCK_MONOTONIC
  1768. # elif defined(CLOCK_HIGHRES)
  1769. # define XSLT_CLOCK CLOCK_HIGHRES
  1770. # else
  1771. # define XSLT_CLOCK CLOCK_REALTIME
  1772. # endif
  1773. static struct timespec startup;
  1774. struct timespec cur;
  1775. long tics;
  1776. if (calibration < 0) {
  1777. clock_gettime(XSLT_CLOCK, &startup);
  1778. calibration = 0;
  1779. calibration = xsltCalibrateTimestamps();
  1780. clock_gettime(XSLT_CLOCK, &startup);
  1781. return (0);
  1782. }
  1783. clock_gettime(XSLT_CLOCK, &cur);
  1784. tics = (cur.tv_sec - startup.tv_sec) * XSLT_TIMESTAMP_TICS_PER_SEC;
  1785. tics += (cur.tv_nsec - startup.tv_nsec) /
  1786. (1000000000l / XSLT_TIMESTAMP_TICS_PER_SEC);
  1787. tics -= calibration;
  1788. return(tics);
  1789. #elif HAVE_GETTIMEOFDAY
  1790. static struct timeval startup;
  1791. struct timeval cur;
  1792. long tics;
  1793. if (calibration < 0) {
  1794. gettimeofday(&startup, NULL);
  1795. calibration = 0;
  1796. calibration = xsltCalibrateTimestamps();
  1797. gettimeofday(&startup, NULL);
  1798. return (0);
  1799. }
  1800. gettimeofday(&cur, NULL);
  1801. tics = (cur.tv_sec - startup.tv_sec) * XSLT_TIMESTAMP_TICS_PER_SEC;
  1802. tics += (cur.tv_usec - startup.tv_usec) /
  1803. (1000000l / XSLT_TIMESTAMP_TICS_PER_SEC);
  1804. tics -= calibration;
  1805. return(tics);
  1806. #else
  1807. /* Neither gettimeofday() nor Win32 performance counter available */
  1808. return (0);
  1809. #endif /* HAVE_GETTIMEOFDAY */
  1810. #endif /* XSLT_WIN32_PERFORMANCE_COUNTER */
  1811. }
  1812. static char *
  1813. pretty_templ_match(xsltTemplatePtr templ) {
  1814. static char dst[1001];
  1815. char *src = (char *)templ->match;
  1816. int i=0,j;
  1817. /* strip white spaces */
  1818. for (j=0; i<1000 && src[j]; i++,j++) {
  1819. for(;src[j]==' ';j++);
  1820. dst[i]=src[j];
  1821. }
  1822. if(i<998 && templ->mode) {
  1823. /* append [mode] */
  1824. dst[i++]='[';
  1825. src=(char *)templ->mode;
  1826. for (j=0; i<999 && src[j]; i++,j++) {
  1827. dst[i]=src[j];
  1828. }
  1829. dst[i++]=']';
  1830. }
  1831. dst[i]='\0';
  1832. return dst;
  1833. }
  1834. #define MAX_TEMPLATES 10000
  1835. /**
  1836. * xsltSaveProfiling:
  1837. * @ctxt: an XSLT context
  1838. * @output: a FILE * for saving the information
  1839. *
  1840. * Save the profiling information on @output
  1841. */
  1842. void
  1843. xsltSaveProfiling(xsltTransformContextPtr ctxt, FILE *output) {
  1844. int nb, i,j,k,l;
  1845. int max;
  1846. int total;
  1847. unsigned long totalt;
  1848. xsltTemplatePtr *templates;
  1849. xsltStylesheetPtr style;
  1850. xsltTemplatePtr templ1,templ2;
  1851. int *childt;
  1852. if ((output == NULL) || (ctxt == NULL))
  1853. return;
  1854. if (ctxt->profile == 0)
  1855. return;
  1856. nb = 0;
  1857. max = MAX_TEMPLATES;
  1858. templates = xmlMalloc(max * sizeof(xsltTemplatePtr));
  1859. if (templates == NULL)
  1860. return;
  1861. style = ctxt->style;
  1862. while (style != NULL) {
  1863. templ1 = style->templates;
  1864. while (templ1 != NULL) {
  1865. if (nb >= max)
  1866. break;
  1867. if (templ1->nbCalls > 0)
  1868. templates[nb++] = templ1;
  1869. templ1 = templ1->next;
  1870. }
  1871. style = xsltNextImport(style);
  1872. }
  1873. for (i = 0;i < nb -1;i++) {
  1874. for (j = i + 1; j < nb; j++) {
  1875. if ((templates[i]->time <= templates[j]->time) ||
  1876. ((templates[i]->time == templates[j]->time) &&
  1877. (templates[i]->nbCalls <= templates[j]->nbCalls))) {
  1878. templ1 = templates[j];
  1879. templates[j] = templates[i];
  1880. templates[i] = templ1;
  1881. }
  1882. }
  1883. }
  1884. /* print flat profile */
  1885. fprintf(output, "%6s%20s%20s%10s Calls Tot 100us Avg\n\n",
  1886. "number", "match", "name", "mode");
  1887. total = 0;
  1888. totalt = 0;
  1889. for (i = 0;i < nb;i++) {
  1890. templ1 = templates[i];
  1891. fprintf(output, "%5d ", i);
  1892. if (templ1->match != NULL) {
  1893. if (xmlStrlen(templ1->match) > 20)
  1894. fprintf(output, "%s\n%26s", templ1->match, "");
  1895. else
  1896. fprintf(output, "%20s", templ1->match);
  1897. } else {
  1898. fprintf(output, "%20s", "");
  1899. }
  1900. if (templ1->name != NULL) {
  1901. if (xmlStrlen(templ1->name) > 20)
  1902. fprintf(output, "%s\n%46s", templ1->name, "");
  1903. else
  1904. fprintf(output, "%20s", templ1->name);
  1905. } else {
  1906. fprintf(output, "%20s", "");
  1907. }
  1908. if (templ1->mode != NULL) {
  1909. if (xmlStrlen(templ1->mode) > 10)
  1910. fprintf(output, "%s\n%56s", templ1->mode, "");
  1911. else
  1912. fprintf(output, "%10s", templ1->mode);
  1913. } else {
  1914. fprintf(output, "%10s", "");
  1915. }
  1916. fprintf(output, " %6d", templ1->nbCalls);
  1917. fprintf(output, " %6ld %6ld\n", templ1->time,
  1918. templ1->time / templ1->nbCalls);
  1919. total += templ1->nbCalls;
  1920. totalt += templ1->time;
  1921. }
  1922. fprintf(output, "\n%30s%26s %6d %6ld\n", "Total", "", total, totalt);
  1923. /* print call graph */
  1924. childt = xmlMalloc((nb + 1) * sizeof(int));
  1925. if (childt == NULL)
  1926. return;
  1927. /* precalculate children times */
  1928. for (i = 0; i < nb; i++) {
  1929. templ1 = templates[i];
  1930. childt[i] = 0;
  1931. for (k = 0; k < nb; k++) {
  1932. templ2 = templates[k];
  1933. for (l = 0; l < templ2->templNr; l++) {
  1934. if (templ2->templCalledTab[l] == templ1) {
  1935. childt[i] +=templ2->time;
  1936. }
  1937. }
  1938. }
  1939. }
  1940. childt[i] = 0;
  1941. fprintf(output, "\nindex %% time self children called name\n");
  1942. for (i = 0; i < nb; i++) {
  1943. char ix_str[20], timep_str[20], times_str[20], timec_str[20], called_str[20];
  1944. unsigned long t;
  1945. templ1 = templates[i];
  1946. /* callers */
  1947. for (j = 0; j < templ1->templNr; j++) {
  1948. templ2 = templ1->templCalledTab[j];
  1949. for (k = 0; k < nb; k++) {
  1950. if (templates[k] == templ2)
  1951. break;
  1952. }
  1953. t=templ2?templ2->time:totalt;
  1954. snprintf(times_str,sizeof(times_str),"%8.3f",(float)t/XSLT_TIMESTAMP_TICS_PER_SEC);
  1955. snprintf(timec_str,sizeof(timec_str),"%8.3f",(float)childt[k]/XSLT_TIMESTAMP_TICS_PER_SEC);
  1956. snprintf(called_str,sizeof(called_str),"%6d/%d",
  1957. templ1->templCountTab[j], /* number of times caller calls 'this' */
  1958. templ1->nbCalls); /* total number of calls to 'this' */
  1959. fprintf(output, " %-8s %-8s %-12s %s [%d]\n",
  1960. times_str,timec_str,called_str,
  1961. (templ2?(templ2->name?(char *)templ2->name:pretty_templ_match(templ2)):"-"),k);
  1962. }
  1963. /* this */
  1964. snprintf(ix_str,sizeof(ix_str),"[%d]",i);
  1965. snprintf(timep_str,sizeof(timep_str),"%6.2f",(float)templ1->time*100.0/totalt);
  1966. snprintf(times_str,sizeof(times_str),"%8.3f",(float)templ1->time/XSLT_TIMESTAMP_TICS_PER_SEC);
  1967. snprintf(timec_str,sizeof(timec_str),"%8.3f",(float)childt[i]/XSLT_TIMESTAMP_TICS_PER_SEC);
  1968. fprintf(output, "%-5s %-6s %-8s %-8s %6d %s [%d]\n",
  1969. ix_str, timep_str,times_str,timec_str,
  1970. templ1->nbCalls,
  1971. templ1->name?(char *)templ1->name:pretty_templ_match(templ1),i);
  1972. /* callees
  1973. * - go over templates[0..nb] and their templCalledTab[]
  1974. * - print those where we in the the call-stack
  1975. */
  1976. total = 0;
  1977. for (k = 0; k < nb; k++) {
  1978. templ2 = templates[k];
  1979. for (l = 0; l < templ2->templNr; l++) {
  1980. if (templ2->templCalledTab[l] == templ1) {
  1981. total+=templ2->templCountTab[l];
  1982. }
  1983. }
  1984. }
  1985. for (k = 0; k < nb; k++) {
  1986. templ2 = templates[k];
  1987. for (l = 0; l < templ2->templNr; l++) {
  1988. if (templ2->templCalledTab[l] == templ1) {
  1989. snprintf(times_str,sizeof(times_str),"%8.3f",(float)templ2->time/XSLT_TIMESTAMP_TICS_PER_SEC);
  1990. snprintf(timec_str,sizeof(timec_str),"%8.3f",(float)childt[k]/XSLT_TIMESTAMP_TICS_PER_SEC);
  1991. snprintf(called_str,sizeof(called_str),"%6d/%d",
  1992. templ2->templCountTab[l], /* number of times 'this' calls callee */
  1993. total); /* total number of calls from 'this' */
  1994. fprintf(output, " %-8s %-8s %-12s %s [%d]\n",
  1995. times_str,timec_str,called_str,
  1996. templ2->name?(char *)templ2->name:pretty_templ_match(templ2),k);
  1997. }
  1998. }
  1999. }
  2000. fprintf(output, "-----------------------------------------------\n");
  2001. }
  2002. fprintf(output, "\f\nIndex by function name\n");
  2003. for (i = 0; i < nb; i++) {
  2004. templ1 = templates[i];
  2005. fprintf(output, "[%d] %s (%s:%d)\n",
  2006. i, templ1->name?(char *)templ1->name:pretty_templ_match(templ1),
  2007. templ1->style->doc->URL,templ1->elem->line);
  2008. }
  2009. fprintf(output, "\f\n");
  2010. xmlFree(childt);
  2011. xmlFree(templates);
  2012. }
  2013. /************************************************************************
  2014. * *
  2015. * Fetching profiling information *
  2016. * *
  2017. ************************************************************************/
  2018. /**
  2019. * xsltGetProfileInformation:
  2020. * @ctxt: a transformation context
  2021. *
  2022. * This function should be called after the transformation completed
  2023. * to extract template processing profiling information if available.
  2024. * The information is returned as an XML document tree like
  2025. * <?xml version="1.0"?>
  2026. * <profile>
  2027. * <template rank="1" match="*" name=""
  2028. * mode="" calls="6" time="48" average="8"/>
  2029. * <template rank="2" match="item2|item3" name=""
  2030. * mode="" calls="10" time="30" average="3"/>
  2031. * <template rank="3" match="item1" name=""
  2032. * mode="" calls="5" time="17" average="3"/>
  2033. * </profile>
  2034. * The caller will need to free up the returned tree with xmlFreeDoc()
  2035. *
  2036. * Returns the xmlDocPtr corresponding to the result or NULL if not available.
  2037. */
  2038. xmlDocPtr
  2039. xsltGetProfileInformation(xsltTransformContextPtr ctxt)
  2040. {
  2041. xmlDocPtr ret = NULL;
  2042. xmlNodePtr root, child;
  2043. char buf[100];
  2044. xsltStylesheetPtr style;
  2045. xsltTemplatePtr *templates;
  2046. xsltTemplatePtr templ;
  2047. int nb = 0, max = 0, i, j;
  2048. if (!ctxt)
  2049. return NULL;
  2050. if (!ctxt->profile)
  2051. return NULL;
  2052. nb = 0;
  2053. max = 10000;
  2054. templates =
  2055. (xsltTemplatePtr *) xmlMalloc(max * sizeof(xsltTemplatePtr));
  2056. if (templates == NULL)
  2057. return NULL;
  2058. /*
  2059. * collect all the templates in an array
  2060. */
  2061. style = ctxt->style;
  2062. while (style != NULL) {
  2063. templ = style->templates;
  2064. while (templ != NULL) {
  2065. if (nb >= max)
  2066. break;
  2067. if (templ->nbCalls > 0)
  2068. templates[nb++] = templ;
  2069. templ = templ->next;
  2070. }
  2071. style = (xsltStylesheetPtr) xsltNextImport(style);
  2072. }
  2073. /*
  2074. * Sort the array by time spent
  2075. */
  2076. for (i = 0; i < nb - 1; i++) {
  2077. for (j = i + 1; j < nb; j++) {
  2078. if ((templates[i]->time <= templates[j]->time) ||
  2079. ((templates[i]->time == templates[j]->time) &&
  2080. (templates[i]->nbCalls <= templates[j]->nbCalls))) {
  2081. templ = templates[j];
  2082. templates[j] = templates[i];
  2083. templates[i] = templ;
  2084. }
  2085. }
  2086. }
  2087. /*
  2088. * Generate a document corresponding to the results.
  2089. */
  2090. ret = xmlNewDoc(BAD_CAST "1.0");
  2091. root = xmlNewDocNode(ret, NULL, BAD_CAST "profile", NULL);
  2092. xmlDocSetRootElement(ret, root);
  2093. for (i = 0; i < nb; i++) {
  2094. child = xmlNewChild(root, NULL, BAD_CAST "template", NULL);
  2095. snprintf(buf, sizeof(buf), "%d", i + 1);
  2096. xmlSetProp(child, BAD_CAST "rank", BAD_CAST buf);
  2097. xmlSetProp(child, BAD_CAST "match", BAD_CAST templates[i]->match);
  2098. xmlSetProp(child, BAD_CAST "name", BAD_CAST templates[i]->name);
  2099. xmlSetProp(child, BAD_CAST "mode", BAD_CAST templates[i]->mode);
  2100. snprintf(buf, sizeof(buf), "%d", templates[i]->nbCalls);
  2101. xmlSetProp(child, BAD_CAST "calls", BAD_CAST buf);
  2102. snprintf(buf, sizeof(buf), "%ld", templates[i]->time);
  2103. xmlSetProp(child, BAD_CAST "time", BAD_CAST buf);
  2104. snprintf(buf, sizeof(buf), "%ld", templates[i]->time / templates[i]->nbCalls);
  2105. xmlSetProp(child, BAD_CAST "average", BAD_CAST buf);
  2106. };
  2107. xmlFree(templates);
  2108. return ret;
  2109. }
  2110. #endif /* WITH_PROFILER */
  2111. /************************************************************************
  2112. * *
  2113. * Hooks for libxml2 XPath *
  2114. * *
  2115. ************************************************************************/
  2116. /**
  2117. * xsltXPathCompileFlags:
  2118. * @style: the stylesheet
  2119. * @str: the XPath expression
  2120. * @flags: extra compilation flags to pass down to libxml2 XPath
  2121. *
  2122. * Compile an XPath expression
  2123. *
  2124. * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
  2125. * the caller has to free the object.
  2126. */
  2127. xmlXPathCompExprPtr
  2128. xsltXPathCompileFlags(xsltStylesheetPtr style, const xmlChar *str, int flags) {
  2129. xmlXPathContextPtr xpathCtxt;
  2130. xmlXPathCompExprPtr ret;
  2131. if (style != NULL) {
  2132. xpathCtxt = style->principal->xpathCtxt;
  2133. if (xpathCtxt == NULL)
  2134. return NULL;
  2135. xpathCtxt->dict = style->dict;
  2136. } else {
  2137. xpathCtxt = xmlXPathNewContext(NULL);
  2138. if (xpathCtxt == NULL)
  2139. return NULL;
  2140. }
  2141. xpathCtxt->flags = flags;
  2142. /*
  2143. * Compile the expression.
  2144. */
  2145. ret = xmlXPathCtxtCompile(xpathCtxt, str);
  2146. if (style == NULL) {
  2147. xmlXPathFreeContext(xpathCtxt);
  2148. }
  2149. /*
  2150. * TODO: there is a lot of optimizations which should be possible
  2151. * like variable slot precomputations, function precomputations, etc.
  2152. */
  2153. return(ret);
  2154. }
  2155. /**
  2156. * xsltXPathCompile:
  2157. * @style: the stylesheet
  2158. * @str: the XPath expression
  2159. *
  2160. * Compile an XPath expression
  2161. *
  2162. * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
  2163. * the caller has to free the object.
  2164. */
  2165. xmlXPathCompExprPtr
  2166. xsltXPathCompile(xsltStylesheetPtr style, const xmlChar *str) {
  2167. return(xsltXPathCompileFlags(style, str, 0));
  2168. }
  2169. /************************************************************************
  2170. * *
  2171. * Hooks for the debugger *
  2172. * *
  2173. ************************************************************************/
  2174. int xslDebugStatus;
  2175. /**
  2176. * xsltGetDebuggerStatus:
  2177. *
  2178. * Get xslDebugStatus.
  2179. *
  2180. * Returns the value of xslDebugStatus.
  2181. */
  2182. int
  2183. xsltGetDebuggerStatus(void)
  2184. {
  2185. return(xslDebugStatus);
  2186. }
  2187. #ifdef WITH_DEBUGGER
  2188. /*
  2189. * There is currently only 3 debugging callback defined
  2190. * Debugger callbacks are disabled by default
  2191. */
  2192. #define XSLT_CALLBACK_NUMBER 3
  2193. typedef struct _xsltDebuggerCallbacks xsltDebuggerCallbacks;
  2194. typedef xsltDebuggerCallbacks *xsltDebuggerCallbacksPtr;
  2195. struct _xsltDebuggerCallbacks {
  2196. xsltHandleDebuggerCallback handler;
  2197. xsltAddCallCallback add;
  2198. xsltDropCallCallback drop;
  2199. };
  2200. static xsltDebuggerCallbacks xsltDebuggerCurrentCallbacks = {
  2201. NULL, /* handler */
  2202. NULL, /* add */
  2203. NULL /* drop */
  2204. };
  2205. /**
  2206. * xsltSetDebuggerStatus:
  2207. * @value : the value to be set
  2208. *
  2209. * This function sets the value of xslDebugStatus.
  2210. */
  2211. void
  2212. xsltSetDebuggerStatus(int value)
  2213. {
  2214. xslDebugStatus = value;
  2215. }
  2216. /**
  2217. * xsltSetDebuggerCallbacks:
  2218. * @no : number of callbacks
  2219. * @block : the block of callbacks
  2220. *
  2221. * This function allow to plug a debugger into the XSLT library
  2222. * @block points to a block of memory containing the address of @no
  2223. * callback routines.
  2224. *
  2225. * Returns 0 in case of success and -1 in case of error
  2226. */
  2227. int
  2228. xsltSetDebuggerCallbacks(int no, void *block)
  2229. {
  2230. xsltDebuggerCallbacksPtr callbacks;
  2231. if ((block == NULL) || (no != XSLT_CALLBACK_NUMBER))
  2232. return(-1);
  2233. callbacks = (xsltDebuggerCallbacksPtr) block;
  2234. xsltDebuggerCurrentCallbacks.handler = callbacks->handler;
  2235. xsltDebuggerCurrentCallbacks.add = callbacks->add;
  2236. xsltDebuggerCurrentCallbacks.drop = callbacks->drop;
  2237. return(0);
  2238. }
  2239. /**
  2240. * xslHandleDebugger:
  2241. * @cur : source node being executed
  2242. * @node : data node being processed
  2243. * @templ : temlate that applies to node
  2244. * @ctxt : the xslt transform context
  2245. *
  2246. * If either cur or node are a breakpoint, or xslDebugStatus in state
  2247. * where debugging must occcur at this time then transfer control
  2248. * to the xslDebugBreak function
  2249. */
  2250. void
  2251. xslHandleDebugger(xmlNodePtr cur, xmlNodePtr node, xsltTemplatePtr templ,
  2252. xsltTransformContextPtr ctxt)
  2253. {
  2254. if (xsltDebuggerCurrentCallbacks.handler != NULL)
  2255. xsltDebuggerCurrentCallbacks.handler(cur, node, templ, ctxt);
  2256. }
  2257. /**
  2258. * xslAddCall:
  2259. * @templ : current template being applied
  2260. * @source : the source node being processed
  2261. *
  2262. * Add template "call" to call stack
  2263. * Returns : 1 on sucess 0 otherwise an error may be printed if
  2264. * WITH_XSLT_DEBUG_BREAKPOINTS is defined
  2265. */
  2266. int
  2267. xslAddCall(xsltTemplatePtr templ, xmlNodePtr source)
  2268. {
  2269. if (xsltDebuggerCurrentCallbacks.add != NULL)
  2270. return(xsltDebuggerCurrentCallbacks.add(templ, source));
  2271. return(0);
  2272. }
  2273. /**
  2274. * xslDropCall:
  2275. *
  2276. * Drop the topmost item off the call stack
  2277. */
  2278. void
  2279. xslDropCall(void)
  2280. {
  2281. if (xsltDebuggerCurrentCallbacks.drop != NULL)
  2282. xsltDebuggerCurrentCallbacks.drop();
  2283. }
  2284. #endif /* WITH_DEBUGGER */