leptris 1.9.201.0-arm-linux → 1.9.201.2-arm-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1535) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -0
  3. data/Rakefile +52 -12
  4. data/ext/leptris/native/extconf.rb +85 -0
  5. data/ext/leptris/native/native.c +1 -1
  6. data/lib/leptris/version.rb +1 -1
  7. data/lib/leptris/xml/ffi.rb +13 -0
  8. data/lib/leptris/xml/native.so +0 -0
  9. data/vendor-src/libleptris/CHANGELOG.md +8080 -0
  10. data/vendor-src/libleptris/CLAUDE.md +150 -0
  11. data/vendor-src/libleptris/CMakeLists.txt +379 -0
  12. data/vendor-src/libleptris/CMakePresets.json +61 -0
  13. data/vendor-src/libleptris/CODE_OF_CONDUCT.md +132 -0
  14. data/vendor-src/libleptris/CONTEXT.md +49 -0
  15. data/vendor-src/libleptris/LICENSE.md +33 -0
  16. data/vendor-src/libleptris/README.adoc +1197 -0
  17. data/vendor-src/libleptris/TODO.assemble/README.md +16 -0
  18. data/vendor-src/libleptris/TODO.bindings/01-mutation-construction.md +18 -0
  19. data/vendor-src/libleptris/TODO.bindings/02-incremental-iterparse.md +15 -0
  20. data/vendor-src/libleptris/TODO.bindings/03-compiled-xpath.md +15 -0
  21. data/vendor-src/libleptris/TODO.bindings/04-pull-stax-api.md +14 -0
  22. data/vendor-src/libleptris/TODO.bindings/05-per-parse-options.md +17 -0
  23. data/vendor-src/libleptris/TODO.bindings/06-serialize-encoding-guarantees.md +14 -0
  24. data/vendor-src/libleptris/TODO.bindings/README.md +36 -0
  25. data/vendor-src/libleptris/TODO.concurrency/01-thread-safe-errors.md +19 -0
  26. data/vendor-src/libleptris/TODO.concurrency/02-export-surface-gate.md +24 -0
  27. data/vendor-src/libleptris/TODO.concurrency/03-mixed-nodeset-batch.md +14 -0
  28. data/vendor-src/libleptris/TODO.concurrency/04-canonical-status-message.md +13 -0
  29. data/vendor-src/libleptris/TODO.concurrency/05-windows-dll-name.md +10 -0
  30. data/vendor-src/libleptris/TODO.concurrency/06-exslt-pack.md +26 -0
  31. data/vendor-src/libleptris/TODO.concurrency/07-ns-set-pairs.md +11 -0
  32. data/vendor-src/libleptris/TODO.concurrency/08-threading-contract.md +45 -0
  33. data/vendor-src/libleptris/TODO.engine/01-file-sources.md +11 -0
  34. data/vendor-src/libleptris/TODO.engine/02-compiled-contexts.md +10 -0
  35. data/vendor-src/libleptris/TODO.engine/03-rust-publish.md +9 -0
  36. data/vendor-src/libleptris/TODO.engine/04-ruby-release-input.md +8 -0
  37. data/vendor-src/libleptris/TODO.engine/05-todo-md-refresh.md +7 -0
  38. data/vendor-src/libleptris/TODO.engine/README.md +16 -0
  39. data/vendor-src/libleptris/TODO.hygiene/README.md +15 -0
  40. data/vendor-src/libleptris/TODO.max-perf/00-INDEX.md +22 -0
  41. data/vendor-src/libleptris/TODO.max-perf/1-simd-html-scanner.md +15 -0
  42. data/vendor-src/libleptris/TODO.max-perf/10-moxml-plan-followups.md +9 -0
  43. data/vendor-src/libleptris/TODO.max-perf/2-compiled-dispatch-tokenizer.md +8 -0
  44. data/vendor-src/libleptris/TODO.max-perf/3-iterparse-fixed-cost.md +5 -0
  45. data/vendor-src/libleptris/TODO.max-perf/4-compact-node-micro-opts.md +17 -0
  46. data/vendor-src/libleptris/TODO.max-perf/5-xslt-bench-profiling-rounds.md +13 -0
  47. data/vendor-src/libleptris/TODO.max-perf/6-language-tails.md +9 -0
  48. data/vendor-src/libleptris/TODO.max-perf/7-validate-bindings.md +6 -0
  49. data/vendor-src/libleptris/TODO.max-perf/8-native-xml-diff-consumer.md +5 -0
  50. data/vendor-src/libleptris/TODO.max-perf/9-prebuilt-gem-matrix.md +14 -0
  51. data/vendor-src/libleptris/TODO.md +33 -0
  52. data/vendor-src/libleptris/TODO.transform/README.md +39 -0
  53. data/vendor-src/libleptris/TODO.validate/README.md +32 -0
  54. data/vendor-src/libleptris/TODO.xpath2/README.md +91 -0
  55. data/vendor-src/libleptris/TODO.xslt-full/01-xpath-fn-sequences.md +27 -0
  56. data/vendor-src/libleptris/TODO.xslt-full/02-xpath-fn-regex.md +13 -0
  57. data/vendor-src/libleptris/TODO.xslt-full/03-xpath-fn-math.md +10 -0
  58. data/vendor-src/libleptris/TODO.xslt-full/04-xpath-fn-strings-qname-uri.md +97 -0
  59. data/vendor-src/libleptris/TODO.xslt-full/05-xpath-fn-dates.md +30 -0
  60. data/vendor-src/libleptris/TODO.xslt-full/06-xpath-grammar-3x.md +83 -0
  61. data/vendor-src/libleptris/TODO.xslt-full/07-xpath-function-items.md +124 -0
  62. data/vendor-src/libleptris/TODO.xslt-full/08-xpath-maps-arrays.md +79 -0
  63. data/vendor-src/libleptris/TODO.xslt-full/09-xslt-noop-fillins.md +35 -0
  64. data/vendor-src/libleptris/TODO.xslt-full/10-xslt-tunnel-params.md +9 -0
  65. data/vendor-src/libleptris/TODO.xslt-full/11-xquery-core.md +119 -0
  66. data/vendor-src/libleptris/TODO.xslt-full/12-xquery-31.md +65 -0
  67. data/vendor-src/libleptris/TODO.xslt-full/13-perf-inprocess.md +425 -0
  68. data/vendor-src/libleptris/TODO.xslt-full/14-html-mode.md +803 -0
  69. data/vendor-src/libleptris/TODO.xslt-full/15-binding-entries.md +19 -0
  70. data/vendor-src/libleptris/TODO.xslt-full/16-schematron.md +156 -0
  71. data/vendor-src/libleptris/TODO.xslt-full/17-xml-diff.md +52 -0
  72. data/vendor-src/libleptris/TODO.xslt-full/18-compact-nodes.md +278 -0
  73. data/vendor-src/libleptris/TODO.xslt-full/README.md +26 -0
  74. data/vendor-src/libleptris/TODO.xslt-full/REMAINING.md +163 -0
  75. data/vendor-src/libleptris/TODO.xslt-full/legacy-v19/00-triage.md +171 -0
  76. data/vendor-src/libleptris/TODO.xslt-full/legacy-v19/01-fragment-nodes.md +19 -0
  77. data/vendor-src/libleptris/TODO.xslt-full/legacy-v19/02-root-node-semantics.md +34 -0
  78. data/vendor-src/libleptris/TODO.xslt-full/legacy-v19/03-crashes.md +15 -0
  79. data/vendor-src/libleptris/TODO.xslt-full/legacy-v19/04-namespaces.md +14 -0
  80. data/vendor-src/libleptris/TODO.xslt-full/legacy-v19/05-number-attrset-sort.md +13 -0
  81. data/vendor-src/libleptris/TODO.xslt-full/legacy-v19/06-document-chains.md +10 -0
  82. data/vendor-src/libleptris/TODO.xslt-full/legacy-v19/07-charef-serializer.md +9 -0
  83. data/vendor-src/libleptris/TODO.xslt-full/legacy-v19/08-perf-gate.md +8 -0
  84. data/vendor-src/libleptris/TODO.xslt-full/legacy-v19/09-release.md +14 -0
  85. data/vendor-src/libleptris/VALIDATION.md +151 -0
  86. data/vendor-src/libleptris/benchmarks/CMakeLists.txt +259 -0
  87. data/vendor-src/libleptris/benchmarks/README.adoc +228 -0
  88. data/vendor-src/libleptris/benchmarks/README.md +212 -0
  89. data/vendor-src/libleptris/benchmarks/common/benchmark.c +252 -0
  90. data/vendor-src/libleptris/benchmarks/common/benchmark.h +77 -0
  91. data/vendor-src/libleptris/benchmarks/common/test_data.c +415 -0
  92. data/vendor-src/libleptris/benchmarks/common/test_data.h +18 -0
  93. data/vendor-src/libleptris/benchmarks/comprehensive/CMakeLists.txt +184 -0
  94. data/vendor-src/libleptris/benchmarks/comprehensive/benchmark_decomp.cpp +110 -0
  95. data/vendor-src/libleptris/benchmarks/comprehensive/benchmark_first_access.cpp +261 -0
  96. data/vendor-src/libleptris/benchmarks/comprehensive/benchmark_many_attrs.cpp +150 -0
  97. data/vendor-src/libleptris/benchmarks/comprehensive/benchmark_memory.cpp +185 -0
  98. data/vendor-src/libleptris/benchmarks/comprehensive/benchmark_parse.cpp +270 -0
  99. data/vendor-src/libleptris/benchmarks/comprehensive/benchmark_parse_ops.cpp +392 -0
  100. data/vendor-src/libleptris/benchmarks/comprehensive/benchmark_sax.c +106 -0
  101. data/vendor-src/libleptris/benchmarks/comprehensive/benchmark_write.cpp +351 -0
  102. data/vendor-src/libleptris/benchmarks/data/attrs.xml +303 -0
  103. data/vendor-src/libleptris/benchmarks/data/cdata_test.xml +13 -0
  104. data/vendor-src/libleptris/benchmarks/data/comment_test.xml +15 -0
  105. data/vendor-src/libleptris/benchmarks/data/deep.xml +205 -0
  106. data/vendor-src/libleptris/benchmarks/data/generate_attrs.rb +22 -0
  107. data/vendor-src/libleptris/benchmarks/data/generate_deep.rb +25 -0
  108. data/vendor-src/libleptris/benchmarks/data/generate_large.rb +33 -0
  109. data/vendor-src/libleptris/benchmarks/data/generate_wide.rb +18 -0
  110. data/vendor-src/libleptris/benchmarks/data/large.xml +21003 -0
  111. data/vendor-src/libleptris/benchmarks/data/large_workflow.xml +4003 -0
  112. data/vendor-src/libleptris/benchmarks/data/medium.xml +67 -0
  113. data/vendor-src/libleptris/benchmarks/data/medium_workflow.xml +353 -0
  114. data/vendor-src/libleptris/benchmarks/data/pi_test.xml +9 -0
  115. data/vendor-src/libleptris/benchmarks/data/small.xml +10 -0
  116. data/vendor-src/libleptris/benchmarks/data/small_workflow.xml +36 -0
  117. data/vendor-src/libleptris/benchmarks/data/wide.xml +5003 -0
  118. data/vendor-src/libleptris/benchmarks/dom/bench_document_lifecycle.c +69 -0
  119. data/vendor-src/libleptris/benchmarks/dom/bench_leptris.c +184 -0
  120. data/vendor-src/libleptris/benchmarks/dom/bench_libxml2.c +176 -0
  121. data/vendor-src/libleptris/benchmarks/dom/bench_text_borrowed.c +74 -0
  122. data/vendor-src/libleptris/benchmarks/dom/dom_benchmark_v2.cpp +314 -0
  123. data/vendor-src/libleptris/benchmarks/fixtures/large.xml +4003 -0
  124. data/vendor-src/libleptris/benchmarks/fixtures/large_catalog.xml +50003 -0
  125. data/vendor-src/libleptris/benchmarks/fixtures/libxml2/eve.xml +6 -0
  126. data/vendor-src/libleptris/benchmarks/fixtures/libxml2/slashdot.rdf +66 -0
  127. data/vendor-src/libleptris/benchmarks/fixtures/libxml2/wap.xml +27 -0
  128. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/4rects.xml +11 -0
  129. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/a-valid.xml +10 -0
  130. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/a-wf.xml +9 -0
  131. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/bike.xml +41 -0
  132. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/circle.xml +11 -0
  133. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/defs.xml +14 -0
  134. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/desc.xml +14 -0
  135. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/ellipse.xml +10 -0
  136. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/flower2.xml +44 -0
  137. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/gradient.xml +16 -0
  138. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/group01.xml +15 -0
  139. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/group02.xml +13 -0
  140. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/group03.xml +13 -0
  141. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/image-valid.xml +11 -0
  142. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/image-wf.xml +11 -0
  143. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/lin-gradient.xml +16 -0
  144. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/marker.xml +28 -0
  145. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/mask.xml +13 -0
  146. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/mathswitch.xml +32 -0
  147. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/parentns.xml +12 -0
  148. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/path01.xml +5 -0
  149. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/path02.xml +10 -0
  150. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/patternfill.xml +12 -0
  151. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/polyline.xml +9 -0
  152. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/private.xml +19 -0
  153. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/rad-gradient.xml +17 -0
  154. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/rectangle.xml +10 -0
  155. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/richdesc.xml +12 -0
  156. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/script.xml +13 -0
  157. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/structure01.xml +10 -0
  158. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/style.xml +11 -0
  159. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/switch.xml +21 -0
  160. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/symbol-use.xml +28 -0
  161. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/template.xml +9 -0
  162. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/text01.xml +12 -0
  163. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/text02.xml +17 -0
  164. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/text03.xml +8 -0
  165. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/toap01.xml +10 -0
  166. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/toap02.xml +33 -0
  167. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/transform.xml +26 -0
  168. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/trivial.xml +6 -0
  169. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/twin-gradients.xml +19 -0
  170. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/v-template.xml +9 -0
  171. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/viewport-nest.xml +13 -0
  172. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/viewport-transform.xml +46 -0
  173. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/viewport.xml +11 -0
  174. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/wf-template.xml +7 -0
  175. data/vendor-src/libleptris/benchmarks/fixtures/libxml2_xsdtest.xml +5286 -0
  176. data/vendor-src/libleptris/benchmarks/fixtures/medium.xml +403 -0
  177. data/vendor-src/libleptris/benchmarks/fixtures/medium_catalog.xml +3003 -0
  178. data/vendor-src/libleptris/benchmarks/fixtures/pugixml/empty.xml +0 -0
  179. data/vendor-src/libleptris/benchmarks/fixtures/pugixml/large.xml +1 -0
  180. data/vendor-src/libleptris/benchmarks/fixtures/pugixml/latintest_latin1.xml +1 -0
  181. data/vendor-src/libleptris/benchmarks/fixtures/pugixml/latintest_utf8.xml +1 -0
  182. data/vendor-src/libleptris/benchmarks/fixtures/pugixml/multiline.xml +3 -0
  183. data/vendor-src/libleptris/benchmarks/fixtures/pugixml/small.xml +1 -0
  184. data/vendor-src/libleptris/benchmarks/fixtures/pugixml/truncation.xml +19 -0
  185. data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf16_be.xml +0 -0
  186. data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf16_be_bom.xml +0 -0
  187. data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf16_be_clean.xml +0 -0
  188. data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf16_be_nodecl.xml +0 -0
  189. data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf16_le.xml +0 -0
  190. data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf16_le_bom.xml +0 -0
  191. data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf16_le_clean.xml +0 -0
  192. data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf16_le_nodecl.xml +0 -0
  193. data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf32_be.xml +0 -0
  194. data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf32_be_bom.xml +0 -0
  195. data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf32_be_clean.xml +0 -0
  196. data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf32_be_nodecl.xml +0 -0
  197. data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf32_le.xml +0 -0
  198. data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf32_le_bom.xml +0 -0
  199. data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf32_le_clean.xml +0 -0
  200. data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf32_le_nodecl.xml +0 -0
  201. data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf8.xml +87 -0
  202. data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf8_bom.xml +87 -0
  203. data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf8_clean.xml +84 -0
  204. data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf8_nodecl.xml +86 -0
  205. data/vendor-src/libleptris/benchmarks/fixtures/pugixml//321/202/320/265/321/201/321/202.xml +1 -0
  206. data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/empty.xml +0 -0
  207. data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/large.xml +1 -0
  208. data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/latintest_latin1.xml +1 -0
  209. data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/latintest_utf8.xml +1 -0
  210. data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/multiline.xml +3 -0
  211. data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/small.xml +1 -0
  212. data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/truncation.xml +19 -0
  213. data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf16_be.xml +0 -0
  214. data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf16_be_bom.xml +0 -0
  215. data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf16_be_clean.xml +0 -0
  216. data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf16_be_nodecl.xml +0 -0
  217. data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf16_le.xml +0 -0
  218. data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf16_le_bom.xml +0 -0
  219. data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf16_le_clean.xml +0 -0
  220. data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf16_le_nodecl.xml +0 -0
  221. data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf32_be.xml +0 -0
  222. data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf32_be_bom.xml +0 -0
  223. data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf32_be_clean.xml +0 -0
  224. data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf32_be_nodecl.xml +0 -0
  225. data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf32_le.xml +0 -0
  226. data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf32_le_bom.xml +0 -0
  227. data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf32_le_clean.xml +0 -0
  228. data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf32_le_nodecl.xml +0 -0
  229. data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf8.xml +87 -0
  230. data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf8_bom.xml +87 -0
  231. data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf8_clean.xml +84 -0
  232. data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf8_nodecl.xml +86 -0
  233. data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests//321/202/320/265/321/201/321/202.xml +1 -0
  234. data/vendor-src/libleptris/benchmarks/fixtures/small.xml +38 -0
  235. data/vendor-src/libleptris/benchmarks/html/bench_html_parse.c +111 -0
  236. data/vendor-src/libleptris/benchmarks/html/gen_nokogiri_reference.rb +112 -0
  237. data/vendor-src/libleptris/benchmarks/html/nokogiri_html_parse.rb +64 -0
  238. data/vendor-src/libleptris/benchmarks/matrix/README.md +71 -0
  239. data/vendor-src/libleptris/benchmarks/matrix/bench2html.rb +316 -0
  240. data/vendor-src/libleptris/benchmarks/matrix/bench_matrix.cpp +724 -0
  241. data/vendor-src/libleptris/benchmarks/modification/bench_leptris_modify.c +211 -0
  242. data/vendor-src/libleptris/benchmarks/modification/bench_node_creation.c +130 -0
  243. data/vendor-src/libleptris/benchmarks/results/BENCHMARK_REPORT.md +226 -0
  244. data/vendor-src/libleptris/benchmarks/results/baseline_report.md +219 -0
  245. data/vendor-src/libleptris/benchmarks/results/benchmark_20251223_134550.json +13 -0
  246. data/vendor-src/libleptris/benchmarks/results/benchmark_20260129_225844.json +13 -0
  247. data/vendor-src/libleptris/benchmarks/results/leptris_dom_output.txt +24 -0
  248. data/vendor-src/libleptris/benchmarks/results/leptris_modify.json +36 -0
  249. data/vendor-src/libleptris/benchmarks/results/leptris_modify_optimized.json +36 -0
  250. data/vendor-src/libleptris/benchmarks/results/leptris_modify_session1.json +36 -0
  251. data/vendor-src/libleptris/benchmarks/results/leptris_modify_session2.json +36 -0
  252. data/vendor-src/libleptris/benchmarks/results/leptris_serialize.json +34 -0
  253. data/vendor-src/libleptris/benchmarks/results/leptris_xpath_output.txt +24 -0
  254. data/vendor-src/libleptris/benchmarks/results/libxml2_dom_output.txt +24 -0
  255. data/vendor-src/libleptris/benchmarks/results/libxml2_xpath_output.txt +24 -0
  256. data/vendor-src/libleptris/benchmarks/results/phase16_session2.json +21 -0
  257. data/vendor-src/libleptris/benchmarks/results/phase17.5_session1.json +30 -0
  258. data/vendor-src/libleptris/benchmarks/results/phase17_session1.json +30 -0
  259. data/vendor-src/libleptris/benchmarks/results/pugixml_dom_output.txt +51 -0
  260. data/vendor-src/libleptris/benchmarks/results/xpath_axes_leptris.json +318 -0
  261. data/vendor-src/libleptris/benchmarks/results/xpath_axes_libxml2.json +318 -0
  262. data/vendor-src/libleptris/benchmarks/results/xpath_functions_leptris.json +222 -0
  263. data/vendor-src/libleptris/benchmarks/results/xpath_functions_libxml2.json +222 -0
  264. data/vendor-src/libleptris/benchmarks/sax/bench_iterparse.c +115 -0
  265. data/vendor-src/libleptris/benchmarks/sax/bench_leptris.c +124 -0
  266. data/vendor-src/libleptris/benchmarks/sax/bench_libxml2.c +115 -0
  267. data/vendor-src/libleptris/benchmarks/serialization/bench_leptris_serialize.c +198 -0
  268. data/vendor-src/libleptris/benchmarks/src/benchmark_base.h +175 -0
  269. data/vendor-src/libleptris/benchmarks/twins/mutation_leptris.c +37 -0
  270. data/vendor-src/libleptris/benchmarks/twins/mutation_pugixml.cpp +28 -0
  271. data/vendor-src/libleptris/benchmarks/twins/parse_leptris.c +35 -0
  272. data/vendor-src/libleptris/benchmarks/twins/parse_pugixml.cpp +35 -0
  273. data/vendor-src/libleptris/benchmarks/utils.c +171 -0
  274. data/vendor-src/libleptris/benchmarks/utils.h +70 -0
  275. data/vendor-src/libleptris/benchmarks/workflows/bench_dom_modify.c +325 -0
  276. data/vendor-src/libleptris/benchmarks/workflows/bench_end_to_end.c +529 -0
  277. data/vendor-src/libleptris/benchmarks/xpath/bench_axes.c +411 -0
  278. data/vendor-src/libleptris/benchmarks/xpath/bench_axes_libxml2.c +108 -0
  279. data/vendor-src/libleptris/benchmarks/xpath/bench_diagnostic.c +431 -0
  280. data/vendor-src/libleptris/benchmarks/xpath/bench_functions.c +271 -0
  281. data/vendor-src/libleptris/benchmarks/xpath/bench_functions_libxml2.c +123 -0
  282. data/vendor-src/libleptris/benchmarks/xpath/bench_leptris.c +78 -0
  283. data/vendor-src/libleptris/benchmarks/xpath/bench_libxml2.c +98 -0
  284. data/vendor-src/libleptris/benchmarks/xpath/bench_pugixml.cpp +117 -0
  285. data/vendor-src/libleptris/benchmarks/xpath/bench_scalar_eval.c +86 -0
  286. data/vendor-src/libleptris/benchmarks/xpath/bench_scalar_eval_libxml2.c +70 -0
  287. data/vendor-src/libleptris/benchmarks/xpath/bench_xslt_transform.c +48 -0
  288. data/vendor-src/libleptris/benchmarks/xslt/bench_dispatch.c +52 -0
  289. data/vendor-src/libleptris/benchmarks/xslt/bench_dispatch_heavy.c +82 -0
  290. data/vendor-src/libleptris/benchmarks/xslt/bench_dispatch_pred.c +34 -0
  291. data/vendor-src/libleptris/benchmarks/xslt/bench_subtree_copy.c +55 -0
  292. data/vendor-src/libleptris/benchmarks/xslt/bench_valueof.c +46 -0
  293. data/vendor-src/libleptris/benchmarks/xslt/heavy_lxml.py +48 -0
  294. data/vendor-src/libleptris/benchmarks/xslt/scorecard_lxml.py +169 -0
  295. data/vendor-src/libleptris/bindings/ruby/leptris.gemspec +22 -0
  296. data/vendor-src/libleptris/bindings/ruby/lib/leptris/document.rb +60 -0
  297. data/vendor-src/libleptris/bindings/ruby/lib/leptris/element.rb +86 -0
  298. data/vendor-src/libleptris/bindings/ruby/lib/leptris/error.rb +6 -0
  299. data/vendor-src/libleptris/bindings/ruby/lib/leptris/node.rb +73 -0
  300. data/vendor-src/libleptris/bindings/ruby/lib/leptris/sax.rb +189 -0
  301. data/vendor-src/libleptris/bindings/ruby/lib/leptris/xpath.rb +44 -0
  302. data/vendor-src/libleptris/bindings/ruby/lib/leptris.rb +137 -0
  303. data/vendor-src/libleptris/bindings/ruby/spec/leptris_spec.rb +113 -0
  304. data/vendor-src/libleptris/bindings/ruby/spec/sax_spec.rb +141 -0
  305. data/vendor-src/libleptris/bindings/ruby/spec/spec_helper.rb +7 -0
  306. data/vendor-src/libleptris/bindings/ruby/test_full.rb +21 -0
  307. data/vendor-src/libleptris/bindings/rust/Cargo.lock +7 -0
  308. data/vendor-src/libleptris/bindings/rust/Cargo.toml +13 -0
  309. data/vendor-src/libleptris/bindings/rust/README.md +61 -0
  310. data/vendor-src/libleptris/bindings/rust/build.rs +74 -0
  311. data/vendor-src/libleptris/bindings/rust/src/ffi.rs +204 -0
  312. data/vendor-src/libleptris/bindings/rust/src/lib.rs +580 -0
  313. data/vendor-src/libleptris/bindings/rust/tests/integration.rs +156 -0
  314. data/vendor-src/libleptris/cli/ARCHITECTURE_REVIEW.md +514 -0
  315. data/vendor-src/libleptris/cli/CLI_ARCHITECTURE.md +851 -0
  316. data/vendor-src/libleptris/cli/CMakeLists.txt +46 -0
  317. data/vendor-src/libleptris/cli/cli.c +115 -0
  318. data/vendor-src/libleptris/cli/cli.h +232 -0
  319. data/vendor-src/libleptris/cli/commands/diff.c +208 -0
  320. data/vendor-src/libleptris/cli/commands/format.c +379 -0
  321. data/vendor-src/libleptris/cli/commands/parse.c +343 -0
  322. data/vendor-src/libleptris/cli/commands/validate.c +284 -0
  323. data/vendor-src/libleptris/cli/commands/version.c +49 -0
  324. data/vendor-src/libleptris/cli/commands/xpath.c +428 -0
  325. data/vendor-src/libleptris/cli/commands/xquery.c +188 -0
  326. data/vendor-src/libleptris/cli/completion/leptris.bash +86 -0
  327. data/vendor-src/libleptris/cli/completion/leptris.zsh +74 -0
  328. data/vendor-src/libleptris/cli/error.c +394 -0
  329. data/vendor-src/libleptris/cli/error.h +360 -0
  330. data/vendor-src/libleptris/cli/leptris +0 -0
  331. data/vendor-src/libleptris/cli/main.c +127 -0
  332. data/vendor-src/libleptris/cli/man/leptris-format.1.adoc +226 -0
  333. data/vendor-src/libleptris/cli/man/leptris-parse.1.adoc +213 -0
  334. data/vendor-src/libleptris/cli/man/leptris-xpath.1.adoc +479 -0
  335. data/vendor-src/libleptris/cli/man/leptris.1.adoc +192 -0
  336. data/vendor-src/libleptris/cli/options.c +451 -0
  337. data/vendor-src/libleptris/cli/options.h +378 -0
  338. data/vendor-src/libleptris/cli/output.c +841 -0
  339. data/vendor-src/libleptris/cli/output.h +361 -0
  340. data/vendor-src/libleptris/cmake/FindUtf8proc.cmake +56 -0
  341. data/vendor-src/libleptris/cmake/leptris-config.cmake.in +14 -0
  342. data/vendor-src/libleptris/cmake/leptris.pc.in +11 -0
  343. data/vendor-src/libleptris/cmake/modules/AdocMan.cmake +132 -0
  344. data/vendor-src/libleptris/docs/ARCHITECTURE_REVIEW.md +280 -0
  345. data/vendor-src/libleptris/docs/Doxyfile +47 -0
  346. data/vendor-src/libleptris/docs/FFI.md +165 -0
  347. data/vendor-src/libleptris/docs/README.md +47 -0
  348. data/vendor-src/libleptris/docs/ROADMAP-SAXON-PARITY.md +194 -0
  349. data/vendor-src/libleptris/docs/guide/building.md +199 -0
  350. data/vendor-src/libleptris/docs/guide/getting-started.md +134 -0
  351. data/vendor-src/libleptris/docs/guide/parsing.md +315 -0
  352. data/vendor-src/libleptris/docs/guide/xpath-queries.md +444 -0
  353. data/vendor-src/libleptris/examples/c/CMakeLists.txt +58 -0
  354. data/vendor-src/libleptris/examples/c/README.md +345 -0
  355. data/vendor-src/libleptris/examples/c/basic_example.c +80 -0
  356. data/vendor-src/libleptris/examples/c/dom_traversal_example.c +58 -0
  357. data/vendor-src/libleptris/examples/c/error_handling_example.c +121 -0
  358. data/vendor-src/libleptris/examples/c/namespace_example.c +49 -0
  359. data/vendor-src/libleptris/examples/c/xpath_example.c +74 -0
  360. data/vendor-src/libleptris/ports/leptris/portfile.cmake +41 -0
  361. data/vendor-src/libleptris/ports/leptris/usage +28 -0
  362. data/vendor-src/libleptris/scripts/check_dll_exports.py +54 -0
  363. data/vendor-src/libleptris/scripts/check_export_surface.py +84 -0
  364. data/vendor-src/libleptris/scripts/check_ffi_mirrors.py +163 -0
  365. data/vendor-src/libleptris/scripts/check_formatting.sh +30 -0
  366. data/vendor-src/libleptris/scripts/check_shared_exports.sh +120 -0
  367. data/vendor-src/libleptris/scripts/check_trailing_whitespace.sh +18 -0
  368. data/vendor-src/libleptris/scripts/gen-api-docs.sh +31 -0
  369. data/vendor-src/libleptris/scripts/run_static_analysis.sh +16 -0
  370. data/vendor-src/libleptris/scripts/validate.sh +199 -0
  371. data/vendor-src/libleptris/scripts/xslt_triage.sh +72 -0
  372. data/vendor-src/libleptris/src/CMakeLists.txt +597 -0
  373. data/vendor-src/libleptris/src/include/leptris/descriptor.h +178 -0
  374. data/vendor-src/libleptris/src/include/leptris/dom/document.h +213 -0
  375. data/vendor-src/libleptris/src/include/leptris/dom/element.h +435 -0
  376. data/vendor-src/libleptris/src/include/leptris/dom/serialize.h +133 -0
  377. data/vendor-src/libleptris/src/include/leptris/dtd.h +178 -0
  378. data/vendor-src/libleptris/src/include/leptris/error.h +97 -0
  379. data/vendor-src/libleptris/src/include/leptris/sax/sax.h +584 -0
  380. data/vendor-src/libleptris/src/include/leptris/types.h +386 -0
  381. data/vendor-src/libleptris/src/include/leptris/xpath/xpath.h +250 -0
  382. data/vendor-src/libleptris/src/include/leptris/xquery/xquery.h +80 -0
  383. data/vendor-src/libleptris/src/include/leptris.h +3701 -0
  384. data/vendor-src/libleptris/src/leptris/chartype.h +124 -0
  385. data/vendor-src/libleptris/src/leptris/common/chartype.c +90 -0
  386. data/vendor-src/libleptris/src/leptris/common/chartype.h +44 -0
  387. data/vendor-src/libleptris/src/leptris/common/cpu.c +40 -0
  388. data/vendor-src/libleptris/src/leptris/common/cpu.h +63 -0
  389. data/vendor-src/libleptris/src/leptris/common/entities.c +329 -0
  390. data/vendor-src/libleptris/src/leptris/common/entities.h +79 -0
  391. data/vendor-src/libleptris/src/leptris/common/format_number.c +273 -0
  392. data/vendor-src/libleptris/src/leptris/common/format_number.h +29 -0
  393. data/vendor-src/libleptris/src/leptris/common/port.h +171 -0
  394. data/vendor-src/libleptris/src/leptris/common/simd_text.c +237 -0
  395. data/vendor-src/libleptris/src/leptris/common/simd_text.h +104 -0
  396. data/vendor-src/libleptris/src/leptris/common/simd_text_avx2.c +105 -0
  397. data/vendor-src/libleptris/src/leptris/common/simd_text_neon.c +280 -0
  398. data/vendor-src/libleptris/src/leptris/common/string_view.c +204 -0
  399. data/vendor-src/libleptris/src/leptris/common/string_view.h +68 -0
  400. data/vendor-src/libleptris/src/leptris/common/types_internal.h +31 -0
  401. data/vendor-src/libleptris/src/leptris/core.c +201 -0
  402. data/vendor-src/libleptris/src/leptris/descriptor/plan.c +527 -0
  403. data/vendor-src/libleptris/src/leptris/diff/diff.c +491 -0
  404. data/vendor-src/libleptris/src/leptris/dom/cdata.c +47 -0
  405. data/vendor-src/libleptris/src/leptris/dom/cdata.h +73 -0
  406. data/vendor-src/libleptris/src/leptris/dom/comment.c +48 -0
  407. data/vendor-src/libleptris/src/leptris/dom/comment.h +74 -0
  408. data/vendor-src/libleptris/src/leptris/dom/compact.c +397 -0
  409. data/vendor-src/libleptris/src/leptris/dom/compact.h +307 -0
  410. data/vendor-src/libleptris/src/leptris/dom/diag.c +58 -0
  411. data/vendor-src/libleptris/src/leptris/dom/diag.h +75 -0
  412. data/vendor-src/libleptris/src/leptris/dom/digest.c +255 -0
  413. data/vendor-src/libleptris/src/leptris/dom/doctype.c +137 -0
  414. data/vendor-src/libleptris/src/leptris/dom/doctype.h +52 -0
  415. data/vendor-src/libleptris/src/leptris/dom/document_node.c +13 -0
  416. data/vendor-src/libleptris/src/leptris/dom/document_node.h +21 -0
  417. data/vendor-src/libleptris/src/leptris/dom/edges.h +60 -0
  418. data/vendor-src/libleptris/src/leptris/dom/element.c +1114 -0
  419. data/vendor-src/libleptris/src/leptris/dom/element.h +1109 -0
  420. data/vendor-src/libleptris/src/leptris/dom/element_index.c +444 -0
  421. data/vendor-src/libleptris/src/leptris/dom/element_index.h +135 -0
  422. data/vendor-src/libleptris/src/leptris/dom/element_modify.c +2185 -0
  423. data/vendor-src/libleptris/src/leptris/dom/element_query.c +1468 -0
  424. data/vendor-src/libleptris/src/leptris/dom/entity_ref.c +57 -0
  425. data/vendor-src/libleptris/src/leptris/dom/entity_ref.h +70 -0
  426. data/vendor-src/libleptris/src/leptris/dom/node.c +420 -0
  427. data/vendor-src/libleptris/src/leptris/dom/node.h +170 -0
  428. data/vendor-src/libleptris/src/leptris/dom/node_public.c +937 -0
  429. data/vendor-src/libleptris/src/leptris/dom/node_vtable.c +138 -0
  430. data/vendor-src/libleptris/src/leptris/dom/pi.c +70 -0
  431. data/vendor-src/libleptris/src/leptris/dom/pi.h +80 -0
  432. data/vendor-src/libleptris/src/leptris/dom/root_doc_map.c +310 -0
  433. data/vendor-src/libleptris/src/leptris/dom/root_doc_map.h +30 -0
  434. data/vendor-src/libleptris/src/leptris/dom/text.c +157 -0
  435. data/vendor-src/libleptris/src/leptris/dom/text.h +119 -0
  436. data/vendor-src/libleptris/src/leptris/dtd/content_check.c +300 -0
  437. data/vendor-src/libleptris/src/leptris/dtd/model.c +533 -0
  438. data/vendor-src/libleptris/src/leptris/dtd/model.h +354 -0
  439. data/vendor-src/libleptris/src/leptris/dtd/parser.c +827 -0
  440. data/vendor-src/libleptris/src/leptris/dtd/resolver.c +354 -0
  441. data/vendor-src/libleptris/src/leptris/dtd/validator.c +668 -0
  442. data/vendor-src/libleptris/src/leptris/encoding/encoders.c +346 -0
  443. data/vendor-src/libleptris/src/leptris/encoding/encoders.h +61 -0
  444. data/vendor-src/libleptris/src/leptris/encoding/encoding.c +451 -0
  445. data/vendor-src/libleptris/src/leptris/encoding/encoding.h +118 -0
  446. data/vendor-src/libleptris/src/leptris/encoding/unicode.c +317 -0
  447. data/vendor-src/libleptris/src/leptris/encoding/unicode.h +64 -0
  448. data/vendor-src/libleptris/src/leptris/encoding/utf16.c +204 -0
  449. data/vendor-src/libleptris/src/leptris/encoding/utf16.h +78 -0
  450. data/vendor-src/libleptris/src/leptris/encoding/wrapper.c +243 -0
  451. data/vendor-src/libleptris/src/leptris/error.c +134 -0
  452. data/vendor-src/libleptris/src/leptris/flat/direct_parse.c +1935 -0
  453. data/vendor-src/libleptris/src/leptris/flat/direct_parse.h +41 -0
  454. data/vendor-src/libleptris/src/leptris/html/html_parse.c +8040 -0
  455. data/vendor-src/libleptris/src/leptris/leptris.c +1264 -0
  456. data/vendor-src/libleptris/src/leptris/leptris_internal.h +910 -0
  457. data/vendor-src/libleptris/src/leptris/leptris_memory.c +179 -0
  458. data/vendor-src/libleptris/src/leptris/leptris_memory.h +180 -0
  459. data/vendor-src/libleptris/src/leptris/leptris_parse.h +195 -0
  460. data/vendor-src/libleptris/src/leptris/memory/arena.c +243 -0
  461. data/vendor-src/libleptris/src/leptris/memory/arena.h +93 -0
  462. data/vendor-src/libleptris/src/leptris/memory/pool.c +1055 -0
  463. data/vendor-src/libleptris/src/leptris/memory/pool.h +426 -0
  464. data/vendor-src/libleptris/src/leptris/rng/parse.c +814 -0
  465. data/vendor-src/libleptris/src/leptris/rng/rng_internal.h +112 -0
  466. data/vendor-src/libleptris/src/leptris/rng/rng_public.c +159 -0
  467. data/vendor-src/libleptris/src/leptris/rng/rng_regex.c +453 -0
  468. data/vendor-src/libleptris/src/leptris/rng/validate.c +1923 -0
  469. data/vendor-src/libleptris/src/leptris/sax/iterparse.c +435 -0
  470. data/vendor-src/libleptris/src/leptris/sax/parser.c +105 -0
  471. data/vendor-src/libleptris/src/leptris/sax/pull.c +489 -0
  472. data/vendor-src/libleptris/src/leptris/sax/recorder.c +252 -0
  473. data/vendor-src/libleptris/src/leptris/sax/sax_internal.h +163 -0
  474. data/vendor-src/libleptris/src/leptris/sax/streaming.c +1469 -0
  475. data/vendor-src/libleptris/src/leptris/sch/schematron.c +1588 -0
  476. data/vendor-src/libleptris/src/leptris/serialize/c14n.c +1143 -0
  477. data/vendor-src/libleptris/src/leptris/serialize/serialize.c +2333 -0
  478. data/vendor-src/libleptris/src/leptris/serialize/serialize.h +188 -0
  479. data/vendor-src/libleptris/src/leptris/simd_helpers.h +447 -0
  480. data/vendor-src/libleptris/src/leptris/unicode/unicode.c +237 -0
  481. data/vendor-src/libleptris/src/leptris/unicode/unicode.h +113 -0
  482. data/vendor-src/libleptris/src/leptris/xinclude/xinclude.c +794 -0
  483. data/vendor-src/libleptris/src/leptris/xpath/bytecode.h +229 -0
  484. data/vendor-src/libleptris/src/leptris/xpath/compiler.c +1478 -0
  485. data/vendor-src/libleptris/src/leptris/xpath/evaluator.c +1099 -0
  486. data/vendor-src/libleptris/src/leptris/xpath/evaluator.h +189 -0
  487. data/vendor-src/libleptris/src/leptris/xpath/evaluator_axes.c +787 -0
  488. data/vendor-src/libleptris/src/leptris/xpath/evaluator_internal.h +112 -0
  489. data/vendor-src/libleptris/src/leptris/xpath/evaluator_operators.c +2138 -0
  490. data/vendor-src/libleptris/src/leptris/xpath/evaluator_path.c +1312 -0
  491. data/vendor-src/libleptris/src/leptris/xpath/evaluator_types.c +294 -0
  492. data/vendor-src/libleptris/src/leptris/xpath/functions.c +2544 -0
  493. data/vendor-src/libleptris/src/leptris/xpath/functions.h +161 -0
  494. data/vendor-src/libleptris/src/leptris/xpath/functions_exslt.c +545 -0
  495. data/vendor-src/libleptris/src/leptris/xpath/functions_ext31.c +4316 -0
  496. data/vendor-src/libleptris/src/leptris/xpath/lexer.c +636 -0
  497. data/vendor-src/libleptris/src/leptris/xpath/lexer.h +25 -0
  498. data/vendor-src/libleptris/src/leptris/xpath/parser.c +2992 -0
  499. data/vendor-src/libleptris/src/leptris/xpath/parser.h +28 -0
  500. data/vendor-src/libleptris/src/leptris/xpath/vm.c +2903 -0
  501. data/vendor-src/libleptris/src/leptris/xpath/xpath_ast_cache.c +319 -0
  502. data/vendor-src/libleptris/src/leptris/xpath/xpath_compiled.c +263 -0
  503. data/vendor-src/libleptris/src/leptris/xpath/xpath_internal.h +134 -0
  504. data/vendor-src/libleptris/src/leptris/xpath/xpath_public.c +1139 -0
  505. data/vendor-src/libleptris/src/leptris/xpath/xpath_variables.c +410 -0
  506. data/vendor-src/libleptris/src/leptris/xpath/xpath_variables.h +230 -0
  507. data/vendor-src/libleptris/src/leptris/xquery/xquery.c +2641 -0
  508. data/vendor-src/libleptris/src/leptris/xslt/xslt_exec.c +4887 -0
  509. data/vendor-src/libleptris/src/leptris/xslt/xslt_functions.c +1612 -0
  510. data/vendor-src/libleptris/src/leptris/xslt/xslt_internal.h +862 -0
  511. data/vendor-src/libleptris/src/leptris/xslt/xslt_parse.c +2418 -0
  512. data/vendor-src/libleptris/src/leptris/xslt/xslt_pattern.c +441 -0
  513. data/vendor-src/libleptris/src/leptris/xslt/xslt_public.c +710 -0
  514. data/vendor-src/libleptris/src/leptris.symvers +16 -0
  515. data/vendor-src/libleptris/src/man/libleptris.5.adoc +961 -0
  516. data/vendor-src/libleptris/test/CMakeLists.txt +234 -0
  517. data/vendor-src/libleptris/test/README.md +59 -0
  518. data/vendor-src/libleptris/test/abi/test_descriptor.cpp +441 -0
  519. data/vendor-src/libleptris/test/abi/test_doctype_api.cpp +51 -0
  520. data/vendor-src/libleptris/test/abi/test_dom_deep_copy.cpp +110 -0
  521. data/vendor-src/libleptris/test/abi/test_dom_mutation_bugs.cpp +210 -0
  522. data/vendor-src/libleptris/test/abi/test_header_hygiene.cpp +269 -0
  523. data/vendor-src/libleptris/test/abi/test_namespace_mutation_and_create.cpp +198 -0
  524. data/vendor-src/libleptris/test/abi/test_node_get_xpath.cpp +128 -0
  525. data/vendor-src/libleptris/test/abi/test_nokogiri_api.cpp +392 -0
  526. data/vendor-src/libleptris/test/abi/test_parse_fragment.cpp +114 -0
  527. data/vendor-src/libleptris/test/abi/test_previous_sibling_and_c14n_ex.cpp +299 -0
  528. data/vendor-src/libleptris/test/abi/test_public_surface.cpp +463 -0
  529. data/vendor-src/libleptris/test/abi/test_serialize_abi.cpp +67 -0
  530. data/vendor-src/libleptris/test/abi/test_v0_5_14_bugs.cpp +299 -0
  531. data/vendor-src/libleptris/test/abi/test_xpath_custom_fns.cpp +106 -0
  532. data/vendor-src/libleptris/test/cli/test_cli.cpp +493 -0
  533. data/vendor-src/libleptris/test/common/test_simd_spans.cpp +88 -0
  534. data/vendor-src/libleptris/test/common/test_simd_text.cpp +142 -0
  535. data/vendor-src/libleptris/test/concurrency/test_concurrency.cpp +218 -0
  536. data/vendor-src/libleptris/test/diff/test_diff.cpp +244 -0
  537. data/vendor-src/libleptris/test/dom/test_compact.cpp +339 -0
  538. data/vendor-src/libleptris/test/dom/test_digest.cpp +111 -0
  539. data/vendor-src/libleptris/test/dom/test_document_children.cpp +270 -0
  540. data/vendor-src/libleptris/test/dom/test_dom.cpp +2310 -0
  541. data/vendor-src/libleptris/test/dom/test_map_lifecycle.cpp +111 -0
  542. data/vendor-src/libleptris/test/dom/test_node_surface_parity.cpp +268 -0
  543. data/vendor-src/libleptris/test/dom/test_text_borrowed.cpp +126 -0
  544. data/vendor-src/libleptris/test/dom/test_vtable.cpp +108 -0
  545. data/vendor-src/libleptris/test/dtd/test_dtd_validate.cpp +1227 -0
  546. data/vendor-src/libleptris/test/dtd/test_w3c_conformance.cpp +212 -0
  547. data/vendor-src/libleptris/test/fixtures/basic.xml +13 -0
  548. data/vendor-src/libleptris/test/fixtures/cdata.xml +5 -0
  549. data/vendor-src/libleptris/test/fixtures/malformed.xml +2 -0
  550. data/vendor-src/libleptris/test/fixtures/namespaces.xml +11 -0
  551. data/vendor-src/libleptris/test/fixtures/utf16_decl.xml +5 -0
  552. data/vendor-src/libleptris/test/fuzz/fuzz_parse.c +40 -0
  553. data/vendor-src/libleptris/test/html/html5lib-redlist.txt +1366 -0
  554. data/vendor-src/libleptris/test/html/html5lib-tests/LICENSE +21 -0
  555. data/vendor-src/libleptris/test/html/html5lib-tests/README.md +11 -0
  556. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/adoption01.dat +354 -0
  557. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/adoption02.dat +39 -0
  558. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/blocks.dat +695 -0
  559. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/comments01.dat +217 -0
  560. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/doctype01.dat +474 -0
  561. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/domjs-unsafe.dat +0 -0
  562. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/entities01.dat +943 -0
  563. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/entities02.dat +309 -0
  564. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/foreign-fragment.dat +645 -0
  565. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/html5test-com.dat +301 -0
  566. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/inbody01.dat +54 -0
  567. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/isindex.dat +49 -0
  568. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/main-element.dat +46 -0
  569. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/math.dat +104 -0
  570. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/menuitem-element.dat +240 -0
  571. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/namespace-sensitivity.dat +22 -0
  572. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/noscript01.dat +237 -0
  573. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/pending-spec-changes-plain-text-unsafe.dat +0 -0
  574. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/pending-spec-changes.dat +46 -0
  575. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/plain-text-unsafe.dat +0 -0
  576. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/ruby.dat +302 -0
  577. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/scriptdata01.dat +372 -0
  578. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/search-element.dat +46 -0
  579. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/svg.dat +104 -0
  580. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tables01.dat +308 -0
  581. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/template.dat +1673 -0
  582. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests1.dat +1956 -0
  583. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests10.dat +849 -0
  584. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests11.dat +523 -0
  585. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests12.dat +62 -0
  586. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests14.dat +75 -0
  587. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests15.dat +216 -0
  588. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests16.dat +2602 -0
  589. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests17.dat +179 -0
  590. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests18.dat +558 -0
  591. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests19.dat +1398 -0
  592. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests2.dat +821 -0
  593. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests20.dat +842 -0
  594. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests21.dat +306 -0
  595. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests22.dat +190 -0
  596. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests23.dat +168 -0
  597. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests24.dat +79 -0
  598. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests25.dat +288 -0
  599. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests26.dat +453 -0
  600. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests3.dat +305 -0
  601. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests4.dat +58 -0
  602. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests5.dat +210 -0
  603. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests6.dat +663 -0
  604. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests7.dat +417 -0
  605. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests8.dat +165 -0
  606. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests9.dat +472 -0
  607. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests_innerHTML_1.dat +843 -0
  608. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tricky01.dat +336 -0
  609. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/webkit01.dat +785 -0
  610. data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/webkit02.dat +554 -0
  611. data/vendor-src/libleptris/test/html/html5lib_cases.h.in +6 -0
  612. data/vendor-src/libleptris/test/html/nokogiri-parity-redlist.txt +1183 -0
  613. data/vendor-src/libleptris/test/html/nokogiri-tree-tests.dat +18107 -0
  614. data/vendor-src/libleptris/test/html/test_html.cpp +2191 -0
  615. data/vendor-src/libleptris/test/html/test_html5lib.cpp +831 -0
  616. data/vendor-src/libleptris/test/memory/test_arena.cpp +252 -0
  617. data/vendor-src/libleptris/test/memory/test_oom_injection.cpp +170 -0
  618. data/vendor-src/libleptris/test/memory/test_pool.cpp +331 -0
  619. data/vendor-src/libleptris/test/memory/test_pool_arena.cpp +180 -0
  620. data/vendor-src/libleptris/test/parser/test_encoding.cpp +282 -0
  621. data/vendor-src/libleptris/test/parser/test_large_documents.cpp +346 -0
  622. data/vendor-src/libleptris/test/parser/test_parser.cpp +565 -0
  623. data/vendor-src/libleptris/test/parser/test_simd_count.cpp +70 -0
  624. data/vendor-src/libleptris/test/perf/test_perf.cpp +362 -0
  625. data/vendor-src/libleptris/test/perf/test_stress_high_doc_count.cpp +67 -0
  626. data/vendor-src/libleptris/test/rng/include-cases/bad-construct.rng +7 -0
  627. data/vendor-src/libleptris/test/rng/include-cases/bad-override.rng +6 -0
  628. data/vendor-src/libleptris/test/rng/include-cases/bad-start-override.rng +5 -0
  629. data/vendor-src/libleptris/test/rng/include-cases/ext-lib.rng +3 -0
  630. data/vendor-src/libleptris/test/rng/include-cases/ext-main.rng +7 -0
  631. data/vendor-src/libleptris/test/rng/include-cases/lib.rng +5 -0
  632. data/vendor-src/libleptris/test/rng/include-cases/lib2.rng +6 -0
  633. data/vendor-src/libleptris/test/rng/include-cases/main.rng +4 -0
  634. data/vendor-src/libleptris/test/rng/include-cases/no-href.rng +4 -0
  635. data/vendor-src/libleptris/test/rng/include-cases/override.rng +8 -0
  636. data/vendor-src/libleptris/test/rng/include-cases/self-include.rng +4 -0
  637. data/vendor-src/libleptris/test/rng/include-cases/start-override.rng +5 -0
  638. data/vendor-src/libleptris/test/rng/jing-cases/000.bad.xml +1 -0
  639. data/vendor-src/libleptris/test/rng/jing-cases/000.ok.xml +1 -0
  640. data/vendor-src/libleptris/test/rng/jing-cases/000.rng +1 -0
  641. data/vendor-src/libleptris/test/rng/jing-cases/001.bad.xml +1 -0
  642. data/vendor-src/libleptris/test/rng/jing-cases/001.ok.xml +1 -0
  643. data/vendor-src/libleptris/test/rng/jing-cases/001.rng +1 -0
  644. data/vendor-src/libleptris/test/rng/jing-cases/002.bad.xml +1 -0
  645. data/vendor-src/libleptris/test/rng/jing-cases/002.ok.xml +1 -0
  646. data/vendor-src/libleptris/test/rng/jing-cases/002.rng +1 -0
  647. data/vendor-src/libleptris/test/rng/jing-cases/003.bad.xml +1 -0
  648. data/vendor-src/libleptris/test/rng/jing-cases/003.ok.xml +1 -0
  649. data/vendor-src/libleptris/test/rng/jing-cases/003.rng +1 -0
  650. data/vendor-src/libleptris/test/rng/jing-cases/004.bad.xml +1 -0
  651. data/vendor-src/libleptris/test/rng/jing-cases/004.ok.xml +1 -0
  652. data/vendor-src/libleptris/test/rng/jing-cases/004.rng +1 -0
  653. data/vendor-src/libleptris/test/rng/jing-cases/005.bad.xml +1 -0
  654. data/vendor-src/libleptris/test/rng/jing-cases/005.ok.xml +1 -0
  655. data/vendor-src/libleptris/test/rng/jing-cases/005.rng +1 -0
  656. data/vendor-src/libleptris/test/rng/jing-cases/006.bad.xml +1 -0
  657. data/vendor-src/libleptris/test/rng/jing-cases/006.ok.xml +1 -0
  658. data/vendor-src/libleptris/test/rng/jing-cases/006.rng +1 -0
  659. data/vendor-src/libleptris/test/rng/jing-cases/007.bad.xml +1 -0
  660. data/vendor-src/libleptris/test/rng/jing-cases/007.ok.xml +1 -0
  661. data/vendor-src/libleptris/test/rng/jing-cases/007.rng +1 -0
  662. data/vendor-src/libleptris/test/rng/jing-cases/008.bad.xml +1 -0
  663. data/vendor-src/libleptris/test/rng/jing-cases/008.ok.xml +1 -0
  664. data/vendor-src/libleptris/test/rng/jing-cases/008.rng +1 -0
  665. data/vendor-src/libleptris/test/rng/jing-cases/009.bad.xml +1 -0
  666. data/vendor-src/libleptris/test/rng/jing-cases/009.ok.xml +1 -0
  667. data/vendor-src/libleptris/test/rng/jing-cases/009.rng +1 -0
  668. data/vendor-src/libleptris/test/rng/jing-cases/010.bad.xml +1 -0
  669. data/vendor-src/libleptris/test/rng/jing-cases/010.ok.xml +1 -0
  670. data/vendor-src/libleptris/test/rng/jing-cases/010.rng +1 -0
  671. data/vendor-src/libleptris/test/rng/jing-cases/011.bad.xml +1 -0
  672. data/vendor-src/libleptris/test/rng/jing-cases/011.ok.xml +1 -0
  673. data/vendor-src/libleptris/test/rng/jing-cases/011.rng +1 -0
  674. data/vendor-src/libleptris/test/rng/jing-cases/012.bad.xml +1 -0
  675. data/vendor-src/libleptris/test/rng/jing-cases/012.ok.xml +1 -0
  676. data/vendor-src/libleptris/test/rng/jing-cases/012.rng +1 -0
  677. data/vendor-src/libleptris/test/rng/jing-cases/013.bad.xml +1 -0
  678. data/vendor-src/libleptris/test/rng/jing-cases/013.ok.xml +1 -0
  679. data/vendor-src/libleptris/test/rng/jing-cases/013.rng +1 -0
  680. data/vendor-src/libleptris/test/rng/jing-cases/014.bad.xml +1 -0
  681. data/vendor-src/libleptris/test/rng/jing-cases/014.ok.xml +1 -0
  682. data/vendor-src/libleptris/test/rng/jing-cases/014.rng +1 -0
  683. data/vendor-src/libleptris/test/rng/jing-cases/015.bad.xml +1 -0
  684. data/vendor-src/libleptris/test/rng/jing-cases/015.ok.xml +1 -0
  685. data/vendor-src/libleptris/test/rng/jing-cases/015.rng +1 -0
  686. data/vendor-src/libleptris/test/rng/jing-cases/016.bad.xml +1 -0
  687. data/vendor-src/libleptris/test/rng/jing-cases/016.ok.xml +1 -0
  688. data/vendor-src/libleptris/test/rng/jing-cases/016.rng +1 -0
  689. data/vendor-src/libleptris/test/rng/jing-cases/017.bad.xml +1 -0
  690. data/vendor-src/libleptris/test/rng/jing-cases/017.ok.xml +1 -0
  691. data/vendor-src/libleptris/test/rng/jing-cases/017.rng +1 -0
  692. data/vendor-src/libleptris/test/rng/jing-cases/018.bad.xml +1 -0
  693. data/vendor-src/libleptris/test/rng/jing-cases/018.ok.xml +1 -0
  694. data/vendor-src/libleptris/test/rng/jing-cases/018.rng +1 -0
  695. data/vendor-src/libleptris/test/rng/jing-cases/019.bad.xml +1 -0
  696. data/vendor-src/libleptris/test/rng/jing-cases/019.ok.xml +1 -0
  697. data/vendor-src/libleptris/test/rng/jing-cases/019.rng +7 -0
  698. data/vendor-src/libleptris/test/rng/jing-cases/020-book.rng +4 -0
  699. data/vendor-src/libleptris/test/rng/jing-cases/020.bad.xml +1 -0
  700. data/vendor-src/libleptris/test/rng/jing-cases/020.ok.xml +1 -0
  701. data/vendor-src/libleptris/test/rng/jing-cases/020.rng +3 -0
  702. data/vendor-src/libleptris/test/rng/jing-cases/README.md +32 -0
  703. data/vendor-src/libleptris/test/rng/jing-cases/jing-ref.json +212 -0
  704. data/vendor-src/libleptris/test/rng/jing-cases/meta.json +1 -0
  705. data/vendor-src/libleptris/test/rng/test_rng.cpp +1365 -0
  706. data/vendor-src/libleptris/test/rng/test_rng_corpus.cpp +133 -0
  707. data/vendor-src/libleptris/test/rng/test_rng_corpus_msg.cpp +233 -0
  708. data/vendor-src/libleptris/test/sax/test_iterparse.cpp +203 -0
  709. data/vendor-src/libleptris/test/sax/test_pull.cpp +214 -0
  710. data/vendor-src/libleptris/test/sax/test_pull_batch.cpp +201 -0
  711. data/vendor-src/libleptris/test/sax/test_recorder.cpp +265 -0
  712. data/vendor-src/libleptris/test/sax/test_sax.cpp +665 -0
  713. data/vendor-src/libleptris/test/sax/test_streaming.cpp +434 -0
  714. data/vendor-src/libleptris/test/sch/conformance-cases/README.md +15 -0
  715. data/vendor-src/libleptris/test/sch/conformance-cases/extends-baseuri-fixup-01.xml +28 -0
  716. data/vendor-src/libleptris/test/sch/conformance-cases/extends-recursive-01.xml +27 -0
  717. data/vendor-src/libleptris/test/sch/conformance-cases/include-baseuri-fixup-01.xml +24 -0
  718. data/vendor-src/libleptris/test/sch/conformance-cases/include-recursive-01.xml +24 -0
  719. data/vendor-src/libleptris/test/sch/conformance-cases/let-name-collision-error-01.xml +20 -0
  720. data/vendor-src/libleptris/test/sch/conformance-cases/let-name-collision-error-02.xml +20 -0
  721. data/vendor-src/libleptris/test/sch/conformance-cases/let-name-collision-error-03.xml +20 -0
  722. data/vendor-src/libleptris/test/sch/conformance-cases/let-name-collision-error-04.xml +23 -0
  723. data/vendor-src/libleptris/test/sch/conformance-cases/let-name-collision-error-05.xml +20 -0
  724. data/vendor-src/libleptris/test/sch/conformance-cases/let-name-collision-error-06.xml +25 -0
  725. data/vendor-src/libleptris/test/sch/conformance-cases/let-pattern-global-01.xml +24 -0
  726. data/vendor-src/libleptris/test/sch/conformance-cases/let-reference-undefined-01.xml +18 -0
  727. data/vendor-src/libleptris/test/sch/conformance-cases/let-reference-undefined-02.xml +18 -0
  728. data/vendor-src/libleptris/test/sch/conformance-cases/let-reference-undefined-03.xml +18 -0
  729. data/vendor-src/libleptris/test/sch/conformance-cases/let-reference-undefined-04.xml +19 -0
  730. data/vendor-src/libleptris/test/sch/conformance-cases/let-reference-undefined-05.xml +20 -0
  731. data/vendor-src/libleptris/test/sch/conformance-cases/let-reference-undefined-06.xml +20 -0
  732. data/vendor-src/libleptris/test/sch/conformance-cases/let-reference-undefined-07.xml +18 -0
  733. data/vendor-src/libleptris/test/sch/conformance-cases/let-rule-global-01.xml +20 -0
  734. data/vendor-src/libleptris/test/sch/conformance-cases/let-rule-global-02.xml +23 -0
  735. data/vendor-src/libleptris/test/sch/conformance-cases/let-scope-pattern-01.xml +25 -0
  736. data/vendor-src/libleptris/test/sch/conformance-cases/let-scope-phase-01.xml +23 -0
  737. data/vendor-src/libleptris/test/sch/conformance-cases/let-scope-rule-01.xml +23 -0
  738. data/vendor-src/libleptris/test/sch/conformance-cases/let-value-element-content-01.xml +33 -0
  739. data/vendor-src/libleptris/test/sch/conformance-cases/pattern-abstract-01.xml +22 -0
  740. data/vendor-src/libleptris/test/sch/conformance-cases/pattern-subordinate-document-01.xml +21 -0
  741. data/vendor-src/libleptris/test/sch/conformance-cases/pattern-subordinate-document-02.xml +21 -0
  742. data/vendor-src/libleptris/test/sch/conformance-cases/rule-abstract-01.xml +21 -0
  743. data/vendor-src/libleptris/test/sch/conformance-cases/rule-abstract-02.xml +23 -0
  744. data/vendor-src/libleptris/test/sch/conformance-cases/rule-context-attribute-01.xml +18 -0
  745. data/vendor-src/libleptris/test/sch/conformance-cases/rule-context-comment-01.xml +20 -0
  746. data/vendor-src/libleptris/test/sch/conformance-cases/rule-context-element-01.xml +18 -0
  747. data/vendor-src/libleptris/test/sch/conformance-cases/rule-context-pi-01.xml +20 -0
  748. data/vendor-src/libleptris/test/sch/conformance-cases/rule-context-root-01.xml +18 -0
  749. data/vendor-src/libleptris/test/sch/conformance-cases/rule-context-text-01.xml +18 -0
  750. data/vendor-src/libleptris/test/sch/conformance-cases/rule-context-variable-01.xml +22 -0
  751. data/vendor-src/libleptris/test/sch/conformance-cases/rule-context-variable-02.xml +25 -0
  752. data/vendor-src/libleptris/test/sch/conformance-cases/rule-context-variable-03.xml +22 -0
  753. data/vendor-src/libleptris/test/sch/conformance-cases/rule-order-01.xml +21 -0
  754. data/vendor-src/libleptris/test/sch/conformance-cases/schema-default-phase-01.xml +26 -0
  755. data/vendor-src/libleptris/test/sch/conformance-cases/schema-default-phase-02.xml +25 -0
  756. data/vendor-src/libleptris/test/sch/conformance-cases/svrl-diagnostic-01.xml +28 -0
  757. data/vendor-src/libleptris/test/sch/conformance-cases/svrl-diagnostic-02.xml +25 -0
  758. data/vendor-src/libleptris/test/sch/conformance-cases/svrl-name-nopath-01.xml +23 -0
  759. data/vendor-src/libleptris/test/sch/conformance-cases/svrl-name-path-01.xml +23 -0
  760. data/vendor-src/libleptris/test/sch/conformance-cases/svrl-property-01.xml +28 -0
  761. data/vendor-src/libleptris/test/sch/conformance-cases/svrl-property-copy-of.xml +26 -0
  762. data/vendor-src/libleptris/test/sch/conformance-cases/svrl-value-of-01.xml +23 -0
  763. data/vendor-src/libleptris/test/sch/conformance-cases/xslt-key-01.xml +19 -0
  764. data/vendor-src/libleptris/test/sch/conformance-cases/xslt-key-element-content-01.xml +21 -0
  765. data/vendor-src/libleptris/test/sch/test_schematron.cpp +337 -0
  766. data/vendor-src/libleptris/test/sch/test_schematron_corpus.cpp +421 -0
  767. data/vendor-src/libleptris/test/serializer/test_c14n.cpp +539 -0
  768. data/vendor-src/libleptris/test/serializer/test_serialize.cpp +890 -0
  769. data/vendor-src/libleptris/test/smoke/test_smoke.cpp +41 -0
  770. data/vendor-src/libleptris/test/xinclude/test_xinclude.cpp +903 -0
  771. data/vendor-src/libleptris/test/xpath/test_bytecode_vm.cpp +755 -0
  772. data/vendor-src/libleptris/test/xpath/test_compiled.cpp +171 -0
  773. data/vendor-src/libleptris/test/xpath/test_exslt.cpp +141 -0
  774. data/vendor-src/libleptris/test/xpath/test_xpath.cpp +2433 -0
  775. data/vendor-src/libleptris/test/xpath/test_xpath_conformance.cpp +570 -0
  776. data/vendor-src/libleptris/test/xpath/test_xslt.cpp +4245 -0
  777. data/vendor-src/libleptris/test/xquery/books.xml +1 -0
  778. data/vendor-src/libleptris/test/xquery/qt3/README.md +28 -0
  779. data/vendor-src/libleptris/test/xquery/qt3/fn/concat.xml +878 -0
  780. data/vendor-src/libleptris/test/xquery/qt3/fn/contains.xml +795 -0
  781. data/vendor-src/libleptris/test/xquery/qt3/fn/ends-with.xml +556 -0
  782. data/vendor-src/libleptris/test/xquery/qt3/fn/starts-with.xml +644 -0
  783. data/vendor-src/libleptris/test/xquery/qt3/fn/substring/concepts.xml +1 -0
  784. data/vendor-src/libleptris/test/xquery/qt3/fn/substring.xml +449 -0
  785. data/vendor-src/libleptris/test/xquery/test_qt3.cpp +324 -0
  786. data/vendor-src/libleptris/test/xquery/test_xquery.cpp +768 -0
  787. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/ATTRIBUTION.md +12 -0
  788. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/array.out +4 -0
  789. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/array.xml +7 -0
  790. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/array.xsl +26 -0
  791. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-1-.out +6 -0
  792. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-1-.xml +7 -0
  793. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-1-.xsl +21 -0
  794. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-10-.out +2 -0
  795. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-10-.xml +3 -0
  796. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-10-.xsl +10 -0
  797. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-100.out +2 -0
  798. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-100.xml +1 -0
  799. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-100.xsl +9 -0
  800. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-101.out +2 -0
  801. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-101.xml +1 -0
  802. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-101.xsl +8 -0
  803. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-102-inc.xsl +21 -0
  804. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-102.out +3 -0
  805. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-102.xml +1 -0
  806. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-102.xsl +10 -0
  807. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-103.out +2 -0
  808. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-103.xml +1 -0
  809. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-103.xsl +13 -0
  810. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-104.out +2 -0
  811. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-104.xml +1 -0
  812. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-104.xsl +10 -0
  813. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-105.out +2 -0
  814. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-105.xml +1 -0
  815. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-105.xsl +8 -0
  816. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-106.out +2 -0
  817. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-106.xml +2 -0
  818. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-106.xsl +12 -0
  819. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-107.out +8 -0
  820. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-107.xml +7 -0
  821. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-107.xsl +11 -0
  822. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-108.out +25 -0
  823. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-108.xml +4 -0
  824. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-108.xsl +21 -0
  825. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-109.out +3 -0
  826. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-109.xml +4 -0
  827. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-109.xsl +7 -0
  828. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-11-.out +1 -0
  829. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-11-.xml +4 -0
  830. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-11-.xsl +12 -0
  831. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-110.ent +1 -0
  832. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-110.out +1 -0
  833. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-110.xml +9 -0
  834. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-110.xsl +20 -0
  835. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-111.out +6 -0
  836. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-111.xml +17 -0
  837. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-111.xsl +45 -0
  838. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-112.out +2 -0
  839. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-112.xml +1 -0
  840. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-112.xsl +22 -0
  841. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-113.out +4 -0
  842. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-113.xml +7 -0
  843. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-113.xsl +15 -0
  844. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-114.out +3 -0
  845. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-114.xml +7 -0
  846. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-114.xsl +16 -0
  847. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-115.out +2 -0
  848. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-115.xml +1 -0
  849. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-115.xsl +19 -0
  850. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-116.out +2 -0
  851. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-116.xml +1 -0
  852. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-116.xsl +22 -0
  853. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-117.out +5 -0
  854. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-117.xml +10 -0
  855. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-117.xsl +59 -0
  856. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-118.out +3 -0
  857. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-118.xml +6 -0
  858. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-118.xsl +14 -0
  859. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-119.out +10 -0
  860. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-119.xml +12 -0
  861. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-119.xsl +12 -0
  862. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-12-.out +2 -0
  863. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-12-.xml +9 -0
  864. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-12-.xsl +16 -0
  865. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-120.out +8 -0
  866. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-120.xml +15 -0
  867. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-120.xsl +27 -0
  868. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-121.out +1 -0
  869. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-121.xml +1 -0
  870. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-121.xsl +8 -0
  871. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-122.out +2 -0
  872. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-122.xml +11 -0
  873. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-122.xsl +17 -0
  874. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-123.out +2 -0
  875. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-123.xml +2 -0
  876. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-123.xsl +14 -0
  877. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-124.out +2 -0
  878. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-124.xml +6 -0
  879. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-124.xsl +14 -0
  880. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-125.out +351 -0
  881. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-125.xml +118 -0
  882. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-125.xsl +99 -0
  883. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-126.out +9 -0
  884. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-126.xml +1 -0
  885. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-126.xsl +17 -0
  886. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-127.out +1 -0
  887. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-127.xml +1 -0
  888. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-127.xsl +18 -0
  889. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-128.out +5 -0
  890. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-128.xml +26 -0
  891. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-128.xsl +26 -0
  892. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-129.out +6 -0
  893. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-129.xml +6 -0
  894. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-129.xsl +10 -0
  895. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-13-.out +2 -0
  896. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-13-.xml +1 -0
  897. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-13-.xsl +10 -0
  898. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-130-imp1.imp +25 -0
  899. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-130-imp2.imp +14 -0
  900. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-130-imp3.imp +16 -0
  901. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-130-imp4.imp +22 -0
  902. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-130.doc +7 -0
  903. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-130.out +1 -0
  904. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-130.xml +4 -0
  905. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-130.xsl +22 -0
  906. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-131-imp.imp +19 -0
  907. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-131.out +2 -0
  908. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-131.xml +3 -0
  909. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-131.xsl +13 -0
  910. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-132.out +6 -0
  911. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-132.xml +6 -0
  912. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-132.xsl +13 -0
  913. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-133.out +6 -0
  914. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-133.xml +7 -0
  915. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-133.xsl +32 -0
  916. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-134.out +2 -0
  917. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-134.xml +5 -0
  918. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-134.xsl +12 -0
  919. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-135.out +2 -0
  920. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-135.xml +5 -0
  921. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-135.xsl +10 -0
  922. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-136.out +4 -0
  923. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-136.xml +4 -0
  924. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-136.xsl +8 -0
  925. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-137.imp +12 -0
  926. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-137.out +2 -0
  927. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-137.xml +1 -0
  928. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-137.xsl +8 -0
  929. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-138.out +23 -0
  930. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-138.xml +15 -0
  931. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-138.xsl +28 -0
  932. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-139.out +4 -0
  933. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-139.xml +9 -0
  934. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-139.xsl +14 -0
  935. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-14-.out +4 -0
  936. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-14-.xml +7 -0
  937. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-14-.xsl +23 -0
  938. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-140.out +4 -0
  939. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-140.xml +6 -0
  940. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-140.xsl +32 -0
  941. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-141.out +46 -0
  942. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-141.xml +9 -0
  943. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-141.xsl +25 -0
  944. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-142.out +35 -0
  945. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-142.xml +65 -0
  946. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-142.xsl +85 -0
  947. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-143.out +2 -0
  948. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-143.xml +1 -0
  949. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-143.xsl +10 -0
  950. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-144.out +2 -0
  951. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-144.xml +1 -0
  952. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-144.xsl +10 -0
  953. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-145.err +5 -0
  954. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-145.xml +10 -0
  955. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-145.xsl +10 -0
  956. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-147-1.imp +11 -0
  957. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-147-2.imp +11 -0
  958. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-147-3.imp +57 -0
  959. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-147-4.imp +15 -0
  960. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-147-5.imp +27 -0
  961. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-147-6.imp +31 -0
  962. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-147.out +17 -0
  963. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-147.xml +21 -0
  964. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-147.xsl +29 -0
  965. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-148.out +2 -0
  966. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-148.xml +1 -0
  967. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-148.xsl +13 -0
  968. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-149.out +2 -0
  969. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-149.xml +1 -0
  970. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-149.xsl +11 -0
  971. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-15-.out +5 -0
  972. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-15-.xml +5 -0
  973. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-15-.xsl +15 -0
  974. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-150.out +2 -0
  975. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-150.xml +1 -0
  976. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-150.xsl +9 -0
  977. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-151.xml +1 -0
  978. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-151.xsl +15 -0
  979. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-152.out +12 -0
  980. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-152.xml +1 -0
  981. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-152.xsl +30 -0
  982. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-153.doc +4 -0
  983. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-153.out +2 -0
  984. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-153.xml +9 -0
  985. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-153.xsl +19 -0
  986. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-154.xml +1 -0
  987. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-154.xsl +4 -0
  988. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-155.out +3 -0
  989. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-155.xml +5 -0
  990. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-155.xsl +10 -0
  991. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-156.err +2 -0
  992. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-156.imp1.imp +16 -0
  993. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-156.imp2.imp +10 -0
  994. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-156.xml +1 -0
  995. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-156.xsl +12 -0
  996. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-157.err +3 -0
  997. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-157.out +9 -0
  998. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-157.xml +6 -0
  999. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-157.xsl +22 -0
  1000. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-158.doc +3 -0
  1001. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-158.out +4 -0
  1002. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-158.xml +2 -0
  1003. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-158.xsl +19 -0
  1004. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-159.out +8 -0
  1005. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-159.xml +1 -0
  1006. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-159.xsl +17 -0
  1007. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-16-.out +14 -0
  1008. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-16-.xml +17 -0
  1009. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-16-.xsl +13 -0
  1010. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-160.out +7 -0
  1011. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-160.xml +8 -0
  1012. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-160.xsl +14 -0
  1013. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-161.out +6 -0
  1014. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-161.xml +5 -0
  1015. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-161.xsl +18 -0
  1016. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-163.out +2 -0
  1017. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-163.xml +5 -0
  1018. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-163.xsl +6 -0
  1019. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-164.out +4 -0
  1020. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-164.xml +4 -0
  1021. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-164.xsl +13 -0
  1022. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-165.err +6 -0
  1023. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-165.xml +10 -0
  1024. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-165.xsl +9 -0
  1025. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-166.out +15256 -0
  1026. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-166.xml +15255 -0
  1027. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-166.xsl +131 -0
  1028. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-167.out +1 -0
  1029. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-167.xml +1 -0
  1030. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-167.xsl +20 -0
  1031. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-168.out +2 -0
  1032. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-168.xml +9 -0
  1033. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-168.xsl +9 -0
  1034. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-169.imp +5 -0
  1035. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-169.out +2 -0
  1036. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-169.xml +1 -0
  1037. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-169.xsl +11 -0
  1038. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-17-.out +2 -0
  1039. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-17-.xml +1 -0
  1040. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-17-.xsl +7 -0
  1041. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-170.out +4 -0
  1042. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-170.xml +3 -0
  1043. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-170.xsl +6 -0
  1044. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-171.out +2 -0
  1045. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-171.xml +4 -0
  1046. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-171.xsl +7 -0
  1047. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-172.out +6 -0
  1048. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-172.xml +6 -0
  1049. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-172.xsl +22 -0
  1050. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-173.out +1 -0
  1051. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-173.xml +1 -0
  1052. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-173.xsl +11 -0
  1053. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-174.err +1 -0
  1054. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-174.xml +1 -0
  1055. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-174.xsl +18 -0
  1056. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-175.err +2 -0
  1057. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-175.out +8 -0
  1058. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-175.xml +1 -0
  1059. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-175.xsl +33 -0
  1060. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-176.out +2 -0
  1061. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-176.xml +1 -0
  1062. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-176.xsl +11 -0
  1063. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-177.out +2 -0
  1064. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-177.xml +1 -0
  1065. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-177.xsl +7 -0
  1066. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-178.out +2 -0
  1067. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-178.xml +1 -0
  1068. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-178.xsl +18 -0
  1069. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-179.out +9 -0
  1070. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-179.xml +1 -0
  1071. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-179.xsl +24 -0
  1072. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-18-.out +2 -0
  1073. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-18-.xml +3 -0
  1074. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-18-.xsl +17 -0
  1075. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-180.err +4 -0
  1076. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-180.xml +2 -0
  1077. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-180.xsl +8 -0
  1078. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-181.out +5 -0
  1079. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-181.xml +4 -0
  1080. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-181.xsl +13 -0
  1081. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-182.out +2 -0
  1082. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-182.xml +4 -0
  1083. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-182.xsl +21 -0
  1084. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-183.out +2 -0
  1085. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-183.xml +5 -0
  1086. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-183.xsl +9 -0
  1087. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-184.err +6 -0
  1088. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-184.xml +1 -0
  1089. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-184.xsl +8 -0
  1090. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-186.out +5 -0
  1091. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-186.xml +4 -0
  1092. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-186.xsl +7 -0
  1093. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-187.err +6 -0
  1094. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-187.out +14 -0
  1095. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-187.xml +1 -0
  1096. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-187.xsl +42 -0
  1097. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-188-imp.xsl +8 -0
  1098. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-188.out +4 -0
  1099. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-188.xml +1 -0
  1100. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-188.xsl +20 -0
  1101. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-189.out +5 -0
  1102. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-189.xml +1 -0
  1103. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-189.xsl +25 -0
  1104. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-19-.out +2 -0
  1105. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-19-.xml +3 -0
  1106. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-19-.xsl +17 -0
  1107. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-190-imp.xsl +10 -0
  1108. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-190.out +4 -0
  1109. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-190.xml +1 -0
  1110. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-190.xsl +16 -0
  1111. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-191-imp.xsl +8 -0
  1112. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-191.err +2 -0
  1113. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-191.xml +1 -0
  1114. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-191.xsl +9 -0
  1115. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-192.out +1 -0
  1116. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-192.xml +1 -0
  1117. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-192.xsl +33 -0
  1118. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-193.out +2 -0
  1119. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-193.xml +1 -0
  1120. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-193.xsl +11 -0
  1121. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-194.err +9 -0
  1122. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-194.xml +1 -0
  1123. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-194.xsl +8 -0
  1124. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-195.out +8 -0
  1125. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-195.xml +9 -0
  1126. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-195.xsl +19 -0
  1127. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-196.out +7 -0
  1128. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-196.xml +9 -0
  1129. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-196.xsl +19 -0
  1130. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-197.out +6 -0
  1131. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-197.xml +6 -0
  1132. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-197.xsl +16 -0
  1133. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-198.out +2 -0
  1134. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-198.xml +2 -0
  1135. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-198.xsl +17 -0
  1136. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-199.out +6 -0
  1137. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-199.xml +6 -0
  1138. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-199.xsl +18 -0
  1139. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-2-.out +8 -0
  1140. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-2-.xml +12 -0
  1141. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-2-.xsl +16 -0
  1142. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-20-.out +4 -0
  1143. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-20-.xml +7 -0
  1144. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-20-.xsl +22 -0
  1145. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-200.out +2 -0
  1146. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-200.xml +1 -0
  1147. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-200.xsl +5 -0
  1148. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-201.err +6 -0
  1149. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-201.xml +1 -0
  1150. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-201.xsl +16 -0
  1151. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-202.err +2 -0
  1152. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-202.xml +1 -0
  1153. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-202.xsl +5 -0
  1154. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-203.err +1 -0
  1155. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-203.xml +1 -0
  1156. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-203.xsl +5 -0
  1157. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-204.err +2 -0
  1158. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-204.xml +1 -0
  1159. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-204.xsl +6 -0
  1160. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-205.out +2 -0
  1161. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-205.xml +1 -0
  1162. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-205.xsl +10 -0
  1163. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-206.out +2 -0
  1164. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-206.xml +1 -0
  1165. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-206.xsl +9 -0
  1166. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-207.out +2 -0
  1167. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-207.xml +1 -0
  1168. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-207.xsl +61 -0
  1169. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-208.err +6 -0
  1170. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-208.xml +8 -0
  1171. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-208.xsl +8 -0
  1172. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-209.out +2 -0
  1173. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-209.xml +1 -0
  1174. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-209.xsl +21 -0
  1175. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-21-.out +2 -0
  1176. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-21-.xml +8 -0
  1177. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-21-.xsl +7 -0
  1178. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-210.out +2 -0
  1179. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-210.xml +1 -0
  1180. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-210.xsl +20 -0
  1181. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-211.out +2 -0
  1182. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-211.xml +1 -0
  1183. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-211.xsl +26 -0
  1184. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-212.out +1 -0
  1185. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-212.xml +1 -0
  1186. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-212.xsl +25 -0
  1187. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-213.out +1 -0
  1188. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-213.xml +1 -0
  1189. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-213.xsl +26 -0
  1190. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-214.out +6 -0
  1191. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-214.xml +6 -0
  1192. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-214.xsl +25 -0
  1193. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-215.err +5 -0
  1194. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-215.xml +1 -0
  1195. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-215.xsl +6 -0
  1196. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-216.out +2 -0
  1197. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-216.xml +1 -0
  1198. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-216.xsl +11 -0
  1199. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-217.out +2 -0
  1200. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-217.xml +1 -0
  1201. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-217.xsl +24 -0
  1202. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-218.out +2 -0
  1203. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-218.xml +1 -0
  1204. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-218.xsl +8 -0
  1205. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-219.out +68 -0
  1206. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-219.xml +22 -0
  1207. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-219.xsl +17 -0
  1208. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-22-.out +12 -0
  1209. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-22-.xml +18 -0
  1210. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-22-.xsl +19 -0
  1211. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-220.out +2 -0
  1212. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-220.xml +1 -0
  1213. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-220.xsl +15 -0
  1214. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-221.out +2 -0
  1215. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-221.xml +9 -0
  1216. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-221.xsl +15 -0
  1217. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-222.out +2 -0
  1218. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-222.xml +1 -0
  1219. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-222.xsl +6 -0
  1220. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-223-imp.xsl +12 -0
  1221. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-223-inc.xsl +12 -0
  1222. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-223.out +1 -0
  1223. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-223.xml +1 -0
  1224. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-223.xsl +17 -0
  1225. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-224.out +9 -0
  1226. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-224.xml +8 -0
  1227. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-224.xsl +28 -0
  1228. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-225.out +2 -0
  1229. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-225.xml +1 -0
  1230. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-225.xsl +32 -0
  1231. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-23-.out +15 -0
  1232. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-23-.xml +21 -0
  1233. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-23-.xsl +20 -0
  1234. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-24-.out +27 -0
  1235. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-24-.xml +2419 -0
  1236. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-24-.xsl +22 -0
  1237. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-25-.out +3 -0
  1238. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-25-.xml +1 -0
  1239. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-25-.xsl +10 -0
  1240. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-26-.out +2 -0
  1241. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-26-.xml +1 -0
  1242. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-26-.xsl +9 -0
  1243. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-27-.out +2 -0
  1244. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-27-.xml +1 -0
  1245. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-27-.xsl +14 -0
  1246. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-28-.out +1 -0
  1247. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-28-.xml +1 -0
  1248. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-28-.xsl +9 -0
  1249. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-29-.ent +7 -0
  1250. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-29-.out +10 -0
  1251. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-29-.xml +5 -0
  1252. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-29-.xsl +16 -0
  1253. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-3-.out +2 -0
  1254. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-3-.xml +1 -0
  1255. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-3-.xsl +13 -0
  1256. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-30-.out +2 -0
  1257. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-30-.xml +1 -0
  1258. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-30-.xsl +7 -0
  1259. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-31-.out +3 -0
  1260. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-31-.xml +4 -0
  1261. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-31-.xsl +10 -0
  1262. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-32-.out +2 -0
  1263. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-32-.xml +1 -0
  1264. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-32-.xsl +17 -0
  1265. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-33-.out +16 -0
  1266. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-33-.xml +14 -0
  1267. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-33-.xsl +29 -0
  1268. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-35-.out +2 -0
  1269. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-35-.xml +1 -0
  1270. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-35-.xsl +10 -0
  1271. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-36-.out +4 -0
  1272. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-36-.xml +5 -0
  1273. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-36-.xsl +8 -0
  1274. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-36-inc.xsl +16 -0
  1275. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-37-.out +4 -0
  1276. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-37-.xml +5 -0
  1277. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-37-.xsl +8 -0
  1278. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-37-inc.xsl +15 -0
  1279. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-38-.out +2 -0
  1280. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-38-.xml +17 -0
  1281. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-38-.xsl +17 -0
  1282. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-39-.out +3 -0
  1283. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-39-.xml +3 -0
  1284. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-39-.xsl +34 -0
  1285. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-4-.out +6 -0
  1286. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-4-.xml +38 -0
  1287. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-4-.xsl +12 -0
  1288. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-40-.out +2 -0
  1289. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-40-.xml +1 -0
  1290. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-40-.xsl +16 -0
  1291. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-41-.out +2 -0
  1292. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-41-.xml +1 -0
  1293. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-41-.xsl +19 -0
  1294. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-42-.out +2 -0
  1295. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-42-.xml +1 -0
  1296. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-42-.xsl +16 -0
  1297. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-43-.out +2 -0
  1298. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-43-.xml +1 -0
  1299. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-43-.xsl +19 -0
  1300. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-44-.out +2 -0
  1301. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-44-.xml +1 -0
  1302. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-44-.xsl +19 -0
  1303. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-45-.out +2 -0
  1304. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-45-.xml +1 -0
  1305. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-45-.xsl +27 -0
  1306. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-46-.out +2 -0
  1307. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-46-.xml +1 -0
  1308. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-46-.xsl +16 -0
  1309. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-47-.out +2 -0
  1310. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-47-.xml +1 -0
  1311. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-47-.xsl +18 -0
  1312. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-48-.out +2 -0
  1313. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-48-.xml +1 -0
  1314. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-48-.xsl +24 -0
  1315. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-49-.out +2 -0
  1316. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-49-.xml +1 -0
  1317. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-49-.xsl +15 -0
  1318. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-5-.out +954 -0
  1319. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-5-.xml +475 -0
  1320. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-5-.xsl +158 -0
  1321. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-50-.out +7 -0
  1322. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-50-.xml +3 -0
  1323. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-50-.xsl +14 -0
  1324. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-52.out +3 -0
  1325. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-52.xml +12 -0
  1326. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-52.xsl +16 -0
  1327. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-53.out +1 -0
  1328. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-53.xml +6 -0
  1329. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-53.xsl +11 -0
  1330. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-54.out +2 -0
  1331. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-54.xml +2 -0
  1332. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-54.xsl +22 -0
  1333. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-55.out +2 -0
  1334. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-55.xml +3 -0
  1335. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-55.xsl +9 -0
  1336. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-56.out +3 -0
  1337. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-56.xml +1 -0
  1338. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-56.xsl +28 -0
  1339. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-57.out +2 -0
  1340. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-57.xml +8 -0
  1341. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-57.xsl +21 -0
  1342. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-58.xsl +274 -0
  1343. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-59.out +2 -0
  1344. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-59.xml +1 -0
  1345. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-59.xsl +9 -0
  1346. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-6-.out +4 -0
  1347. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-6-.xml +6 -0
  1348. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-6-.xsl +32 -0
  1349. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-60.err +2 -0
  1350. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-60.out +2 -0
  1351. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-60.xml +1 -0
  1352. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-60.xsl +15 -0
  1353. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-61.out +10 -0
  1354. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-61.xml +1 -0
  1355. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-61.xsl +14 -0
  1356. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-62-inc.xsl +4 -0
  1357. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-62.out +2 -0
  1358. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-62.xml +1 -0
  1359. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-62.xsl +8 -0
  1360. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-63.out +22 -0
  1361. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-63.xml +13 -0
  1362. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-63.xsl +13 -0
  1363. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-64.out +2 -0
  1364. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-64.xml +1 -0
  1365. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-64.xsl +8 -0
  1366. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-65.ent +7 -0
  1367. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-65.out +8 -0
  1368. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-65.xml +5 -0
  1369. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-65.xsl +26 -0
  1370. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-66.out +2 -0
  1371. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-66.xml +8 -0
  1372. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-66.xsl +12 -0
  1373. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-68.out +1 -0
  1374. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-68.xml +1 -0
  1375. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-68.xsl +8 -0
  1376. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-69.out +2 -0
  1377. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-69.xml +2 -0
  1378. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-69.xsl +12 -0
  1379. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-7-.out +2 -0
  1380. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-7-.xml +3 -0
  1381. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-7-.xsl +11 -0
  1382. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-70.out +9 -0
  1383. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-70.xml +10 -0
  1384. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-70.xsl +13 -0
  1385. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-71.out +2 -0
  1386. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-71.xml +1 -0
  1387. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-71.xsl +17 -0
  1388. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-72.out +6 -0
  1389. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-72.xml +3 -0
  1390. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-72.xsl +31 -0
  1391. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-73.out +3 -0
  1392. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-73.xml +5 -0
  1393. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-73.xsl +17 -0
  1394. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-74.out +2 -0
  1395. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-74.xml +3 -0
  1396. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-74.xsl +12 -0
  1397. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-75.out +6 -0
  1398. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-75.xml +1 -0
  1399. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-75.xsl +9 -0
  1400. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-76.out +4 -0
  1401. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-76.xml +4 -0
  1402. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-76.xsl +16 -0
  1403. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-77.out +5 -0
  1404. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-77.xml +4 -0
  1405. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-77.xsl +18 -0
  1406. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-78.out +3 -0
  1407. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-78.xml +8 -0
  1408. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-78.xsl +17 -0
  1409. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-79.out +5 -0
  1410. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-79.xml +4 -0
  1411. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-79.xsl +4 -0
  1412. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-8-.out +3 -0
  1413. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-8-.xml +5 -0
  1414. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-8-.xsl +13 -0
  1415. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-80.out +2 -0
  1416. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-80.xml +6 -0
  1417. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-80.xsl +29 -0
  1418. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-81.out +4 -0
  1419. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-81.xml +12 -0
  1420. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-81.xsl +18 -0
  1421. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-82.out +5 -0
  1422. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-82.xml +4 -0
  1423. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-82.xsl +12 -0
  1424. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-83.out +1 -0
  1425. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-83.xml +1 -0
  1426. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-83.xsl +14 -0
  1427. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-84.out +15 -0
  1428. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-84.xml +22 -0
  1429. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-84.xsl +14 -0
  1430. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-86.out +6 -0
  1431. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-86.xml +7 -0
  1432. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-86.xsl +7 -0
  1433. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-87.out +5 -0
  1434. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-87.xml +6 -0
  1435. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-87.xsl +16 -0
  1436. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-88.out +2 -0
  1437. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-88.xml +1 -0
  1438. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-88.xsl +6 -0
  1439. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-89.out +12 -0
  1440. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-89.xml +13 -0
  1441. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-89.xsl +105 -0
  1442. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-9-.out +2 -0
  1443. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-9-.xml +3 -0
  1444. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-9-.xsl +10 -0
  1445. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-90.out +13 -0
  1446. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-90.xml +15 -0
  1447. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-90.xsl +35 -0
  1448. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-91.out +3 -0
  1449. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-91.xml +4 -0
  1450. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-91.xsl +8 -0
  1451. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-92.out +15 -0
  1452. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-92.xml +19 -0
  1453. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-92.xsl +19 -0
  1454. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-93-inc.xsl +12 -0
  1455. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-93.out +3 -0
  1456. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-93.xml +1 -0
  1457. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-93.xsl +7 -0
  1458. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-94.out +2 -0
  1459. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-94.xml +9 -0
  1460. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-94.xsl +35 -0
  1461. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-95.out +4 -0
  1462. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-95.xml +5 -0
  1463. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-95.xsl +22 -0
  1464. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-96.out +5 -0
  1465. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-96.xml +5 -0
  1466. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-96.xsl +10 -0
  1467. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-97.out +9 -0
  1468. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-97.xml +16 -0
  1469. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-97.xsl +32 -0
  1470. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-98.out +6 -0
  1471. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-98.xml +10 -0
  1472. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-98.xsl +31 -0
  1473. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-99.out +2 -0
  1474. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-99.xml +1 -0
  1475. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-99.xsl +16 -0
  1476. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/character.out +2 -0
  1477. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/character.xml +23 -0
  1478. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/character.xsl +16 -0
  1479. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/date_add.out +9 -0
  1480. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/date_add.xml +1 -0
  1481. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/date_add.xsl +16 -0
  1482. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/doc.dtd +7 -0
  1483. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/doc.out +16 -0
  1484. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/doc.xml +17 -0
  1485. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/doc.xsl +62 -0
  1486. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/inner.xsl +12 -0
  1487. data/vendor-src/libleptris/test/xslt/libxslt_suite_general/items.xml +34 -0
  1488. data/vendor-src/libleptris/test/xslt/open_cases.txt +0 -0
  1489. data/vendor-src/libleptris/test/xslt/test_libxslt_suite.cpp +398 -0
  1490. data/vendor-src/libleptris/vcpkg.json +29 -0
  1491. data/vendor-src/utf8proc/CMakeLists.txt +133 -0
  1492. data/vendor-src/utf8proc/Doxyfile +2765 -0
  1493. data/vendor-src/utf8proc/LICENSE.md +93 -0
  1494. data/vendor-src/utf8proc/MANIFEST +9 -0
  1495. data/vendor-src/utf8proc/Makefile +203 -0
  1496. data/vendor-src/utf8proc/NEWS.md +479 -0
  1497. data/vendor-src/utf8proc/README.md +143 -0
  1498. data/vendor-src/utf8proc/appveyor.yml +46 -0
  1499. data/vendor-src/utf8proc/bench/Makefile +40 -0
  1500. data/vendor-src/utf8proc/bench/bench.c +56 -0
  1501. data/vendor-src/utf8proc/bench/icu.c +61 -0
  1502. data/vendor-src/utf8proc/bench/unistring.c +60 -0
  1503. data/vendor-src/utf8proc/bench/util.c +39 -0
  1504. data/vendor-src/utf8proc/bench/util.h +22 -0
  1505. data/vendor-src/utf8proc/cmake/utf8proc-config.cmake.in +5 -0
  1506. data/vendor-src/utf8proc/data/Makefile +62 -0
  1507. data/vendor-src/utf8proc/data/Manifest.toml +16 -0
  1508. data/vendor-src/utf8proc/data/Project.toml +2 -0
  1509. data/vendor-src/utf8proc/data/data_generator.jl +498 -0
  1510. data/vendor-src/utf8proc/libutf8proc.pc.cmakein +10 -0
  1511. data/vendor-src/utf8proc/libutf8proc.pc.in +10 -0
  1512. data/vendor-src/utf8proc/lump.md +27 -0
  1513. data/vendor-src/utf8proc/test/app/CMakeLists.txt +6 -0
  1514. data/vendor-src/utf8proc/test/app/app.c +9 -0
  1515. data/vendor-src/utf8proc/test/case.c +76 -0
  1516. data/vendor-src/utf8proc/test/charwidth.c +91 -0
  1517. data/vendor-src/utf8proc/test/custom.c +28 -0
  1518. data/vendor-src/utf8proc/test/fuzz_main.c +54 -0
  1519. data/vendor-src/utf8proc/test/fuzzer.c +97 -0
  1520. data/vendor-src/utf8proc/test/graphemetest.c +136 -0
  1521. data/vendor-src/utf8proc/test/iscase.c +63 -0
  1522. data/vendor-src/utf8proc/test/iterate.c +168 -0
  1523. data/vendor-src/utf8proc/test/maxdecomposition.c +22 -0
  1524. data/vendor-src/utf8proc/test/misc.c +51 -0
  1525. data/vendor-src/utf8proc/test/normtest.c +64 -0
  1526. data/vendor-src/utf8proc/test/ossfuzz.sh +13 -0
  1527. data/vendor-src/utf8proc/test/printproperty.c +68 -0
  1528. data/vendor-src/utf8proc/test/tests.c +60 -0
  1529. data/vendor-src/utf8proc/test/tests.h +27 -0
  1530. data/vendor-src/utf8proc/test/valid.c +41 -0
  1531. data/vendor-src/utf8proc/utf8proc.c +834 -0
  1532. data/vendor-src/utf8proc/utf8proc.h +794 -0
  1533. data/vendor-src/utf8proc/utf8proc_data.c +17141 -0
  1534. data/vendor-src/utf8proc/utils.cmake +20 -0
  1535. metadata +1528 -2
@@ -0,0 +1,4887 @@
1
+ /* xslt/xslt_exec.c — the template engine (TODO.transform 03/04).
2
+ *
3
+ * Dispatch-table execution: each instruction kind maps to a handler
4
+ * registered in a static table — adding instructions (XSLT or
5
+ * EXSLT) never touches the walker (OCP). Template selection per
6
+ * §5.4/5.5: highest priority wins; among equal priorities, the LAST
7
+ * in document order (list append order) wins — imports prepend
8
+ * lower precedence by construction.
9
+ *
10
+ * Output grows in exec->result through the public mutation API;
11
+ * text-method output accumulates string-values only. */
12
+ #include "../common/port.h"
13
+ #include "xslt_internal.h"
14
+ #include "../serialize/serialize.h" /* SerializeBuffer (#682 stream) */
15
+ #include "../dtd/model.h" /* leptris_dtd_apply_attribute_defaults (#606) */
16
+ #include "../dom/text.h"
17
+ #include "../xpath/xpath_internal.h" /* xpath_ast_cache_owner_* (#682 Phase 2) */
18
+ #include "../dom/cdata.h"
19
+ #include "../dom/element_index.h" /* index_invalidate: append parity */
20
+
21
+ /* Result-tree appends: the exec already holds the owning document
22
+ * (ex->result — swapped in sync during RTF capture), so append via
23
+ * the doc-resolved internal instead of the public wrapper, which
24
+ * re-derives the doc by root-climb + map lookup per node (#682). */
25
+ static void out_append_child(XsltExec* ex, LeptrisElement parent,
26
+ void* child) {
27
+ leptris_element_append_child_internal_doc(
28
+ parent, (LeptrisNode*)child, ex->result);
29
+ leptris_element_index_invalidate(ex->result);
30
+ }
31
+ #include <stdlib.h>
32
+ #include <stdio.h>
33
+ #include <ctype.h>
34
+ #include <math.h> /* NAN — MSVC rejects constant NAN (C2124) */
35
+ #if defined(_WIN32)
36
+ # include <direct.h> /* _mkdir (xsl:result-document) */
37
+ #else
38
+ # include <sys/stat.h> /* mkdir (xsl:result-document) */
39
+ #endif
40
+
41
+ #define XSLT_MAX_DEPTH 512
42
+
43
+ /* xpath/xpath_public.c — drops the doc's cached merged registry
44
+ * (xslt_state is one of its three inputs). */
45
+ void leptris_xpath_invalidate_fn_registry(struct leptris_document* doc);
46
+
47
+ /* functions_ext31.c — the shared value-level map builder (08). */
48
+ void* xpath_map_builder_new(void);
49
+ void xpath_map_builder_add(void* b, const char* k, const char* v);
50
+ struct leptris_xpath_result* xpath_map_builder_finish(void* b);
51
+
52
+ static char* xslt_capture_children_text(XsltExec* ex,
53
+ const XsltInstr* child,
54
+ LeptrisElement node);
55
+
56
+ static struct leptris_xpath_result* xslt_capture_content(
57
+ XsltExec* ex, const XsltInstr* child, LeptrisElement node);
58
+
59
+ /* Portable ASCII case-insensitive comparison (strcasecmp is
60
+ * POSIX-only; MSVC has _stricmp). */
61
+ static int xslt_ci_eq(const char* a, const char* b) {
62
+ while (*a && *b) {
63
+ int ca = tolower((unsigned char)*a);
64
+ int cb = tolower((unsigned char)*b);
65
+ if (ca != cb) return 0;
66
+ a++; b++;
67
+ }
68
+ return *a == 0 && *b == 0;
69
+ }
70
+
71
+ static XsltInstrFn g_ops[XSLT_INSTR_UNKNOWN_XSL + 1];
72
+
73
+ void xslt_register_op(XsltInstrKind kind, XsltInstrFn fn) {
74
+ if ((int)kind >= 0 && kind <= XSLT_INSTR_UNKNOWN_XSL) {
75
+ g_ops[kind] = fn;
76
+ }
77
+ }
78
+
79
+ /* Forward decl (xslt_exec.c) — result-tree-fragment ownership
80
+ * chain. The node pointers in a variable's nodeset-reference RTF
81
+ * live for the binding's lifetime; the exec owns the chain so
82
+ * nodes stay alive until xslt_exec_free. */
83
+ struct xslt_rtf_entry {
84
+ LeptrisDocument doc;
85
+ struct xslt_rtf_entry* next;
86
+ };
87
+
88
+ /* ---- Evaluation with the variable frame chain ----
89
+ *
90
+ * Variable-aware path uses leptris_xpath_compiled_eval_vars (the
91
+ * AST interpreter via compiled_eval_context) because the VM's
92
+ * namespace-collection path has tripped a context-cleanup fault in
93
+ * this configuration — the interpreter's path is the proven route.
94
+ * current() (§12.4) is tracked via saved/set/restore on
95
+ * ex->current_node. Node-set vars transport through
96
+ * xpath_variable_set_nodeset (the evaluator returns a leased
97
+ * nodeset; we copy so re-evals are independent). */
98
+
99
+ struct leptris_xpath_result* xslt_eval(XsltExec* ex,
100
+ LeptrisXPathCompiled c,
101
+ LeptrisElement node) {
102
+ if (!c || !ex) return NULL;
103
+
104
+ /* current() (§12.4): save and set on EVERY path — the var-less
105
+ * fast route previously skipped this and current() resolved to
106
+ * an empty nodeset in plain for-each bodies. Restore on exit so
107
+ * nested evals don't clobber outer scopes. */
108
+ LeptrisElement saved_cur = ex->current_node;
109
+ ex->current_node = node;
110
+
111
+ /* No frame chain — fast VM path (ns contexts need the
112
+ * interpreter's prefixed-test resolution). current_pos rides
113
+ * along so position() sees the in-flight iteration (§12.4). */
114
+ if (!ex->vars) {
115
+ struct leptris_xpath_result* r = leptris_xpath_compiled_eval_ctx(
116
+ c, ex->source, node,
117
+ (struct leptris_xpath_ns_map*)ex->current_ns,
118
+ NULL, ex->current_pos, ex->current_size);
119
+ if (!r && !ex->eval_error) {
120
+ ex->eval_error = 1;
121
+ const char* expr = leptris_xpath_compiled_text(c);
122
+ snprintf(ex->error, sizeof(ex->error),
123
+ "XPath evaluation returned no result%s%s",
124
+ expr ? ": " : "", expr ? expr : "");
125
+ }
126
+ ex->current_node = saved_cur;
127
+ return r;
128
+ }
129
+
130
+ if (!ex->varset) {
131
+ ex->varset = xpath_variable_set_new();
132
+ if (!ex->varset) { ex->current_node = saved_cur; return NULL; }
133
+ }
134
+ /* The scratch varset mirrors the frame chain. Frames only change
135
+ * through push/pop — both mark vars_dirty — so a clean varset is
136
+ * a faithful mirror and the (frame-count × type-switch) rebuild
137
+ * is skipped entirely: eval-heavy loops with stable bindings pay
138
+ * the materialization once per scope, not per expression. */
139
+ if (ex->vars_dirty) {
140
+ ex->vars_dirty = 0;
141
+ while (ex->varset->count > 0) {
142
+ xpath_variable_set_remove(ex->varset,
143
+ ex->varset->variables[0]->name);
144
+ }
145
+ /* Shadowing (§11): the scratch set keeps the FIRST binding of a
146
+ * name (xpath_variable_set_add returns existing), so materialize
147
+ * OLDEST→NEWEST — later writes win and inner scopes shadow. */
148
+ size_t nframes = 0;
149
+ for (XsltVar* v = ex->vars; v; v = v->prev) nframes++;
150
+ XsltVar** frames = (XsltVar**)malloc(
151
+ (nframes ? nframes : 1) * sizeof(XsltVar*));
152
+ if (frames) {
153
+ size_t i = nframes;
154
+ for (XsltVar* v = ex->vars; v; v = v->prev) frames[--i] = v;
155
+ }
156
+ for (size_t fi = 0; frames && fi < nframes; fi++) {
157
+ XsltVar* v = frames[fi];
158
+ if (!v->name) continue;
159
+ switch (v->value ? v->value->type : XPATH_RESULT_STRING) {
160
+ case XPATH_RESULT_NUMBER: {
161
+ XPathVariable* xv = xpath_variable_set_add(
162
+ ex->varset, v->name, XPATH_VAR_TYPE_NUMBER);
163
+ if (xv && v->value)
164
+ xpath_variable_set_number(
165
+ xv, v->value->value.number_value);
166
+ break;
167
+ }
168
+ case XPATH_RESULT_BOOLEAN: {
169
+ XPathVariable* xv = xpath_variable_set_add(
170
+ ex->varset, v->name, XPATH_VAR_TYPE_BOOLEAN);
171
+ if (xv && v->value)
172
+ xpath_variable_set_boolean(
173
+ xv, v->value->value.boolean_value);
174
+ break;
175
+ }
176
+ case XPATH_RESULT_STRING: {
177
+ XPathVariable* xv = xpath_variable_set_add(
178
+ ex->varset, v->name, XPATH_VAR_TYPE_STRING);
179
+ if (xv && v->value && v->value->value.string_value)
180
+ xpath_variable_set_string(
181
+ xv, v->value->value.string_value);
182
+ break;
183
+ }
184
+ case XPATH_RESULT_NODESET: {
185
+ /* Node-set variables transport as a fresh XPathNodeSet
186
+ * so each eval sees a stable snapshot — RTFs may be
187
+ * mutated by xsl:variable bodies after the first eval,
188
+ * and the evaluator borrows the nodeset until the
189
+ * result is read. */
190
+ XPathVariable* xv = xpath_variable_set_add(
191
+ ex->varset, v->name, XPATH_VAR_TYPE_NODE_SET);
192
+ if (!xv) {
193
+ /* Type mismatch from a previous eval — clear and retry. */
194
+ xpath_variable_set_remove(ex->varset, v->name);
195
+ xv = xpath_variable_set_add(
196
+ ex->varset, v->name, XPATH_VAR_TYPE_NODE_SET);
197
+ }
198
+ if (xv) {
199
+ /* Avoid leaking the previous var's nodeset —
200
+ * xpath_variable_set_nodeset replaces without
201
+ * freeing. */
202
+ if (xv->value.v.nodeset_value)
203
+ xpath_nodeset_free(xv->value.v.nodeset_value);
204
+ xv->value.v.nodeset_value = NULL;
205
+ if (v->value && v->value->value.nodeset_value) {
206
+ /* Deep copy (#1066): owned synthetic text
207
+ * members must be COPIED with their
208
+ * owns_synthetic_text flag — a plain pointer
209
+ * copy drops the flag, so the variable-lookup
210
+ * guard (which deep-copies only when the
211
+ * varset nodeset owns its synthetics) skips
212
+ * and sequence consumers alias the binding's
213
+ * nodes. xsl:iterate param-threaded sequences
214
+ * then read freed storage after the scope
215
+ * pop ("alpha,beta,gamma" -> ",,gamma").
216
+ * Document nodes are still borrowed. */
217
+ XPathNodeSet* copy = xpath_nodeset_deep_copy(
218
+ v->value->value.nodeset_value);
219
+ if (copy) xpath_variable_set_nodeset(xv, copy);
220
+ }
221
+ }
222
+ break;
223
+ }
224
+ default: break;
225
+ }
226
+ }
227
+ free(frames);
228
+ } /* vars_dirty rebuild */
229
+
230
+ struct leptris_xpath_result* r = leptris_xpath_compiled_eval_ctx(
231
+ c, ex->source, node,
232
+ (struct leptris_xpath_ns_map*)ex->current_ns, ex->varset,
233
+ ex->current_pos, ex->current_size);
234
+
235
+ /* Issue 627: NULL means the evaluation FAILED (unknown function,
236
+ * unbound variable, arity mismatch) — record it; the dispatcher
237
+ * unwinds and the public entry returns no result, matching
238
+ * libxslt's runtime abort instead of a silent empty value. */
239
+ if (!r && !ex->eval_error) {
240
+ ex->eval_error = 1;
241
+ const char* expr = leptris_xpath_compiled_text(c);
242
+ snprintf(ex->error, sizeof(ex->error),
243
+ "XPath evaluation returned no result%s%s",
244
+ expr ? ": " : "", expr ? expr : "");
245
+ }
246
+
247
+ ex->current_node = saved_cur;
248
+ return r;
249
+ }
250
+
251
+ void xslt_push_var(XsltExec* ex, const char* name,
252
+ struct leptris_xpath_result* v) {
253
+ if (!ex || !name) return;
254
+ XsltVar* fv = (XsltVar*)calloc(1, sizeof(*fv));
255
+ if (!fv) return;
256
+ fv->name = name;
257
+ fv->value = v;
258
+ fv->prev = ex->vars;
259
+ ex->vars = fv;
260
+ ex->vars_dirty = 1; /* the scratch varset is stale */
261
+ }
262
+
263
+ void xslt_pop_var(XsltExec* ex, const char* name) {
264
+ if (!ex || !ex->vars) return;
265
+ XsltVar* top = ex->vars;
266
+ ex->vars = top->prev;
267
+ ex->vars_dirty = 1;
268
+ if (top->value) leptris_xpath_result_free(top->value);
269
+ free(top);
270
+ (void)name;
271
+ }
272
+
273
+ /* Block scope (§11.1/§11.5): pop the frame chain back to `mark`.
274
+ * The instruction walker snapshots ex->vars at sequence entry and
275
+ * restores on exit, so a variable declared among following
276
+ * siblings persists for those siblings and their descendants but
277
+ * is gone when the containing sequence (element body, template
278
+ * body, for-each iteration) completes. */
279
+ void xslt_pop_vars_to(XsltExec* ex, XsltVar* mark) {
280
+ while (ex->vars && ex->vars != mark) xslt_pop_var(ex, NULL);
281
+ }
282
+
283
+ /* ---- Shared small helpers ---- */
284
+
285
+ /* Place a created element into the result (root chain or parent),
286
+ * preserving a source element's PREFIX and namespace URI. */
287
+ static LeptrisElement out_place_elem(XsltExec* ex, LeptrisElement parent,
288
+ LeptrisElement e) {
289
+ if (!e) return NULL;
290
+ if (!parent) {
291
+ LeptrisElement root = leptris_document_root(ex->result);
292
+ if (!root) {
293
+ leptris_document_set_root(ex->result, e);
294
+ ex->root_sib_tail = NULL; /* new chain: root is the head */
295
+ } else {
296
+ /* Cached tail (append-only chain; NULL-next validates);
297
+ * stale entries rewalk from the root. */
298
+ LeptrisElement last = (LeptrisElement)ex->root_sib_tail;
299
+ if (!last ||
300
+ leptris_node_get_next_sibling(
301
+ leptris_element_as_node(last)))
302
+ for (last = root; leptris_node_get_next_sibling(
303
+ leptris_element_as_node(last));
304
+ last = (LeptrisElement)leptris_node_get_next_sibling(
305
+ leptris_element_as_node(last))) {}
306
+ leptris_node_set_next_sibling(
307
+ leptris_element_as_node(last), leptris_element_as_node(e));
308
+ ex->root_sib_tail = (LeptrisNodeRef)e;
309
+ }
310
+ } else {
311
+ out_append_child(ex, parent, e);
312
+ }
313
+ return e;
314
+ }
315
+
316
+ static LeptrisElement out_append_elem(XsltExec* ex, LeptrisElement parent,
317
+ const char* name, const char* ns) {
318
+ LeptrisElement e = leptris_element_create(ex->result, name);
319
+ if (!e) return NULL;
320
+ if (ns && *ns) leptris_element_set_namespace_uri(e, ns);
321
+ return out_place_elem(ex, parent, e);
322
+ }
323
+
324
+ /* Is `prefix` already bound to `uri` on a RESULT ancestor? Then a
325
+ * copy's declaration would be redundant (libxslt omits it). */
326
+ static int result_ns_in_scope(LeptrisElement e, const char* prefix,
327
+ const char* uri) {
328
+ const char* pf = prefix ? prefix : "";
329
+ /* Zero-declaration result tree: no ancestor can bind anything.
330
+ * has_namespaces is the exact any-declaration gate (the same one
331
+ * the resolver consults); namespace-free outputs skip the
332
+ * ancestor climb entirely. */
333
+ struct leptris_document* rd = leptris_element_get_document(e);
334
+ if (rd && !rd->has_namespaces) return 0;
335
+ for (LeptrisElement a = leptris_node_parent((LeptrisNodeRef)e);
336
+ a; a = leptris_node_parent((LeptrisNodeRef)a)) {
337
+ for (struct leptris_namespace* ns = leptris_elem_namespaces(a);
338
+ ns; ns = ns->next) {
339
+ const char* npf = ns->prefix ? ns->prefix : "";
340
+ if (strcmp(npf, pf) == 0 && ns->uri && uri &&
341
+ strcmp(ns->uri, uri) == 0)
342
+ return 1;
343
+ }
344
+ }
345
+ return 0;
346
+ }
347
+
348
+ /* Copy of a source ELEMENT: same local name, prefix and namespace
349
+ * URI as the source (§7.5). */
350
+ static LeptrisElement out_copy_elem(XsltExec* ex, LeptrisElement parent,
351
+ LeptrisElement src) {
352
+ LeptrisElement e = leptris_element_create(
353
+ ex->result, leptris_element_get_name(src));
354
+ if (!e) return NULL;
355
+ const char* pfx = leptris_element_get_prefix(src);
356
+ if (pfx && *pfx) leptris_element_set_prefix(e, pfx);
357
+ const char* uri = leptris_element_get_namespace_uri(src);
358
+ if (uri && *uri) leptris_element_set_namespace_uri(e, uri);
359
+ return out_place_elem(ex, parent, e);
360
+ }
361
+
362
+ static void xslt_append_fragment_node(XsltExec* ex, LeptrisNodeRef n);
363
+
364
+ /* ---- #682 stream emitters ------------------------------------------
365
+ * Text escaping mirrors the serializer's text mode (& < >); attr
366
+ * values mirror serialize.c's attribute rules (apostrophe raw per
367
+ * bug-86; tab/newline/CR as character references). */
368
+ /* Run-based emission: bulk-append the plain spans (strcspn finds
369
+ * the next special), then the escape — per-character appends ate
370
+ * the streaming win on first measurement. */
371
+ static void stream_emit_text(struct SerializeBuffer* b, const char* t) {
372
+ if (!t) return;
373
+ for (const char* p = t; *p; ) {
374
+ size_t run = strcspn(p, "&<>");
375
+ if (run) buffer_append_len(b, p, run);
376
+ if (!p[run]) break;
377
+ buffer_append(b, p[run] == '&' ? "&amp;"
378
+ : p[run] == '<' ? "&lt;" : "&gt;");
379
+ p += run + 1;
380
+ }
381
+ }
382
+
383
+ static void stream_emit_attr_value(struct SerializeBuffer* b, const char* t) {
384
+ if (!t) return;
385
+ for (const char* p = t; *p; ) {
386
+ size_t run = strcspn(p, "&<>\"\t\n\r");
387
+ if (run) buffer_append_len(b, p, run);
388
+ if (!p[run]) break;
389
+ switch (p[run]) {
390
+ case '&': buffer_append(b, "&amp;"); break;
391
+ case '<': buffer_append(b, "&lt;"); break;
392
+ case '>': buffer_append(b, "&gt;"); break;
393
+ case '"': buffer_append(b, "&quot;"); break;
394
+ case '\t': buffer_append(b, "&#9;"); break;
395
+ case '\n': buffer_append(b, "&#10;"); break;
396
+ default: buffer_append(b, "&#13;"); break;
397
+ }
398
+ p += run + 1;
399
+ }
400
+ }
401
+
402
+ static void out_append_text(XsltExec* ex, LeptrisElement parent,
403
+ const char* text) {
404
+ if (ex->streaming && !ex->rtf_capturing && text && *text) {
405
+ stream_emit_text(ex->sbuf, text);
406
+ return;
407
+ }
408
+ if (!text || !*text) return;
409
+ if (parent) {
410
+ LeptrisNodeRef t = leptris_text_node_create(ex->result, text);
411
+ if (t) out_append_child(ex, parent, t);
412
+ return;
413
+ }
414
+ /* No insertion point yet: fragment-level text. BEFORE the first
415
+ * element it is top_text (prepended); once elements exist the
416
+ * text belongs AFTER them — tail_text, appended post-serialization
417
+ * (§1: the result is a fragment; order matters). */
418
+ size_t tl = strlen(text);
419
+ /* RTF capture: pure-text variable bodies route here instead of
420
+ * leaking into the fragment output. */
421
+ if (ex->rtf_capturing) {
422
+ if (ex->rtf_text_len + tl + 1 > ex->rtf_text_cap) {
423
+ size_t nc = ex->rtf_text_cap ? ex->rtf_text_cap * 2 : 64;
424
+ while (nc < ex->rtf_text_len + tl + 1) nc *= 2;
425
+ char* grown = (char*)realloc(ex->rtf_text, nc);
426
+ if (!grown) return;
427
+ ex->rtf_text = grown;
428
+ ex->rtf_text_cap = nc;
429
+ }
430
+ memcpy(ex->rtf_text + ex->rtf_text_len, text, tl);
431
+ ex->rtf_text_len += tl;
432
+ ex->rtf_text[ex->rtf_text_len] = 0;
433
+ return;
434
+ }
435
+ /* Fragment text = an ordered node like any other (§1: the
436
+ * result is a fragment; text keeps its position among the
437
+ * elements/comments/PIs). */
438
+ {
439
+ LeptrisNodeRef t = leptris_text_node_create(ex->result, text);
440
+ if (t) xslt_append_fragment_node(ex, t);
441
+ }
442
+ }
443
+
444
+ /* String-value of an element subtree (XPath string-value: all
445
+ * descendant text concatenated). */
446
+ static char* string_value_deep(LeptrisElement e) {
447
+ /* Serialize + strip tags is wrong for CDATA-marked content;
448
+ * walk the tree collecting TEXT/CDATA contents. */
449
+ size_t cap = 64, len = 0;
450
+ char* buf = (char*)malloc(cap);
451
+ if (!buf) return NULL;
452
+ /* Iterative DFS via our own small stack. */
453
+ LeptrisNodeRef stack[256];
454
+ int sp = 0;
455
+ stack[sp++] = leptris_element_as_node(e);
456
+ while (sp > 0) {
457
+ LeptrisNodeRef n = stack[--sp];
458
+ int ty = leptris_node_get_type(n);
459
+ if (ty == LEPTRIS_NODE_TYPE_TEXT || ty == LEPTRIS_NODE_TYPE_CDATA) {
460
+ const char* t = leptris_text_get_content((LeptrisTextNode*)n);
461
+ if (t) {
462
+ size_t tl = strlen(t);
463
+ if (len + tl + 1 > cap) {
464
+ while (len + tl + 1 > cap) cap *= 2;
465
+ char* grown = (char*)realloc(buf, cap);
466
+ if (!grown) { free(buf); return NULL; }
467
+ buf = grown;
468
+ }
469
+ memcpy(buf + len, t, tl);
470
+ len += tl;
471
+ }
472
+ } else if (ty == LEPTRIS_NODE_TYPE_ELEMENT) {
473
+ /* Push children (order: append then reverse siblings by
474
+ * pushing last-first is unnecessary for concatenation). */
475
+ for (LeptrisNodeRef c = leptris_node_first_child(n); c;
476
+ c = leptris_node_next_sibling(c)) {
477
+ if (sp < 256) stack[sp++] = c;
478
+ }
479
+ }
480
+ }
481
+ buf[len] = '\0';
482
+ return buf;
483
+ }
484
+
485
+ /* ---- Instruction handlers (registered below) ---- */
486
+
487
+ /* AVT compiled-expression cache (#682): a literal result element's
488
+ * "book-{@id}" attribute otherwise recompiles its {expr} part for
489
+ * every node it is evaluated against. Distinct expressions per
490
+ * transform are few, so a keyed chain compiles each once. */
491
+ typedef struct XsltAvtEntry {
492
+ struct XsltAvtEntry* next;
493
+ LeptrisXPathCompiled c;
494
+ char expr[];
495
+ } XsltAvtEntry;
496
+
497
+ static LeptrisXPathCompiled avt_compiled(XsltExec* ex, const char* s,
498
+ size_t n) {
499
+ for (XsltAvtEntry* e = (XsltAvtEntry*)ex->avt_cache; e; e = e->next)
500
+ if (strlen(e->expr) == n && memcmp(e->expr, s, n) == 0)
501
+ return e->c;
502
+ XsltAvtEntry* e = (XsltAvtEntry*)malloc(sizeof(*e) + n + 1);
503
+ if (!e) return NULL;
504
+ memcpy(e->expr, s, n);
505
+ e->expr[n] = 0;
506
+ e->c = leptris_xpath_compile(e->expr);
507
+ if (!e->c) { free(e); return NULL; }
508
+ e->next = (XsltAvtEntry*)ex->avt_cache;
509
+ ex->avt_cache = e;
510
+ return e->c;
511
+ }
512
+
513
+ static void xslt_avt_free(XsltExec* ex) {
514
+ while (ex->avt_cache) {
515
+ XsltAvtEntry* e = (XsltAvtEntry*)ex->avt_cache;
516
+ ex->avt_cache = e->next;
517
+ leptris_xpath_compiled_free(e->c);
518
+ free(e);
519
+ }
520
+ }
521
+
522
+ /* Evaluate an attribute-value template: "a{expr}b" pieces are
523
+ * concatenated; {{ and }} are literal braces (§7.1.1). */
524
+ static char* eval_avt(XsltExec* ex, const char* tmpl, LeptrisElement node) {
525
+ if (!tmpl) return leptris_strdup("");
526
+ /* #682 Phase 2: brace-free templates are the common literal
527
+ * case (every literal attribute on every result element) — one
528
+ * strpbrk replaces the per-char grow loop + malloc churn. */
529
+ if (!strpbrk(tmpl, "{}")) return leptris_strdup(tmpl);
530
+ size_t cap = strlen(tmpl) + 32, len = 0;
531
+ char* out = (char*)malloc(cap);
532
+ if (!out) return NULL;
533
+ const char* p = tmpl;
534
+ while (*p) {
535
+ if (*p == '{' && p[1] == '{') { p += 2;
536
+ if (len + 1 >= cap) { cap *= 2; out = realloc(out, cap); }
537
+ out[len++] = '{';
538
+ } else if (*p == '}' && p[1] == '}') { p += 2;
539
+ if (len + 1 >= cap) { cap *= 2; out = realloc(out, cap); }
540
+ out[len++] = '}';
541
+ } else if (*p == '{') {
542
+ /* Find the close brace OUTSIDE string literals — a
543
+ * brace inside '...'/"..." belongs to the expression
544
+ * (bug-168: concat('{',...)). No nesting in AVTs. */
545
+ const char* close = NULL;
546
+ {
547
+ const char* q = p + 1;
548
+ char lit = 0;
549
+ while (*q) {
550
+ if (lit) {
551
+ if (*q == lit) lit = 0;
552
+ } else if (*q == '\'' || *q == '"') {
553
+ lit = *q;
554
+ } else if (*q == '}') {
555
+ close = q;
556
+ break;
557
+ }
558
+ q++;
559
+ }
560
+ }
561
+ if (!close) {
562
+ if (len + 1 >= cap) { cap *= 2; out = realloc(out, cap); }
563
+ out[len++] = *p++;
564
+ continue;
565
+ }
566
+ size_t elen = (size_t)(close - p - 1);
567
+ LeptrisXPathCompiled c = avt_compiled(ex, p + 1, elen);
568
+ if (c) {
569
+ struct leptris_xpath_result* r =
570
+ xslt_eval(ex, c, node);
571
+ char* sv = r ? leptris_xpath_result_string(r) : NULL;
572
+ if (r) leptris_xpath_result_free(r);
573
+ if (sv) {
574
+ size_t sl = strlen(sv);
575
+ while (len + sl + 1 >= cap) { cap *= 2; out = realloc(out, cap); }
576
+ memcpy(out + len, sv, sl);
577
+ len += sl;
578
+ leptris_free_string(sv);
579
+ }
580
+ }
581
+ p = close + 1;
582
+ } else {
583
+ if (len + 1 >= cap) { cap *= 2; out = realloc(out, cap); }
584
+ out[len++] = *p++;
585
+ }
586
+ }
587
+ if (!out) return NULL;
588
+ out[len] = 0;
589
+ return out;
590
+ }
591
+
592
+ /* §7.1.4 QName match: unprefixed names compare literally; prefixed
593
+ * names compare (URI, local) so a declaration and a reference may
594
+ * spell different prefixes for the same namespace (bug-190). */
595
+ static int set_name_matches(const XsltAttrSet* s, const char* uname,
596
+ const char* uuri) {
597
+ if (!s->name || !uname) return 0;
598
+ const char* sc = strchr(s->name, ':');
599
+ const char* uc = strchr(uname, ':');
600
+ if (!sc && !uc) return strcmp(s->name, uname) == 0;
601
+ const char* sl = sc ? sc + 1 : s->name;
602
+ const char* ul = uc ? uc + 1 : uname;
603
+ const char* su = sc ? s->name_uri : NULL;
604
+ const char* uu = uc ? uuri : NULL;
605
+ if (su && uu) return strcmp(su, uu) == 0 && strcmp(sl, ul) == 0;
606
+ if (!su && !uu) return strcmp(sl, ul) == 0; /* unbound prefixes */
607
+ return 0;
608
+ }
609
+
610
+ /* Precedence semantics (§12.1.4, libxslt bug-80/102/188/189/217):
611
+ * declarations of `name` resolve HIGHEST precedence first —
612
+ * higher-precedence declarations seed attribute positions and LOCK
613
+ * their names; lower-precedence declarations only fill gaps. Within
614
+ * one precedence level, document order applies and later
615
+ * declarations update values in place. A declaration's OWN attrs
616
+ * precede (position) and beat (value) the sets it references. The
617
+ * use-list at the instruction applies with update-in-place: later
618
+ * entries override (§7.1.4), then literal attrs, then
619
+ * xsl:attribute children. */
620
+ typedef struct {
621
+ const XsltAttrSet* s;
622
+ int rank;
623
+ size_t seq; /* position in the prepend list: higher = earlier in doc */
624
+ } AttrSetDecl;
625
+
626
+ static int attrset_decl_cmp(const void* pa, const void* pb) {
627
+ const AttrSetDecl* a = (const AttrSetDecl*)pa;
628
+ const AttrSetDecl* b = (const AttrSetDecl*)pb;
629
+ if (a->rank != b->rank) return a->rank < b->rank ? -1 : 1;
630
+ return a->seq > b->seq ? -1 : 1; /* doc order within a rank */
631
+ }
632
+
633
+ typedef struct {
634
+ const char** names;
635
+ size_t n, cap;
636
+ } NameBag;
637
+
638
+ /* Resolved attribute vector: the use-list's merged names/values.
639
+ * Values update in place (later entries override — §7.1.4);
640
+ * positions follow first insertion. Applied to the target with
641
+ * skip-if-exists so explicit attributes win. */
642
+ typedef struct {
643
+ char** names;
644
+ char** values;
645
+ size_t n, cap;
646
+ } AttrVec;
647
+
648
+ static size_t attrvec_find(const AttrVec* v, const char* nm) {
649
+ for (size_t i = 0; i < v->n; i++)
650
+ if (strcmp(v->names[i], nm) == 0) return i;
651
+ return (size_t)-1;
652
+ }
653
+
654
+ static void attrvec_set(AttrVec* v, const char* nm, char* val) {
655
+ size_t i = attrvec_find(v, nm);
656
+ if (i != (size_t)-1) {
657
+ free(v->values[i]);
658
+ v->values[i] = val;
659
+ return;
660
+ }
661
+ if (v->n == v->cap) {
662
+ size_t cap = v->cap ? v->cap * 2 : 8;
663
+ char** gn = (char**)realloc(v->names, cap * sizeof(*gn));
664
+ char** gv = (char**)realloc(v->values, cap * sizeof(*gv));
665
+ if (!gn || !gv) {
666
+ free(gn);
667
+ free(gv);
668
+ free(val);
669
+ return;
670
+ }
671
+ v->names = gn;
672
+ v->values = gv;
673
+ v->cap = cap;
674
+ }
675
+ v->names[v->n] = (char*)nm; /* borrowed: set-decl lifetime */
676
+ v->values[v->n] = val;
677
+ v->n++;
678
+ }
679
+
680
+ static int name_bag_has(const NameBag* b, const char* nm) {
681
+ for (size_t i = 0; i < b->n; i++)
682
+ if (strcmp(b->names[i], nm) == 0) return 1;
683
+ return 0;
684
+ }
685
+
686
+ static void name_bag_add(NameBag* b, const char* nm) {
687
+ if (!nm || name_bag_has(b, nm)) return;
688
+ if (b->n == b->cap) {
689
+ size_t cap = b->cap ? b->cap * 2 : 8;
690
+ const char** grown =
691
+ (const char**)realloc(b->names, cap * sizeof(*grown));
692
+ if (!grown) return;
693
+ b->names = grown;
694
+ b->cap = cap;
695
+ }
696
+ b->names[b->n++] = nm;
697
+ }
698
+
699
+ static void apply_named_set(XsltExec* ex, const char* name,
700
+ const char* uri, AttrVec* vec,
701
+ LeptrisElement node, int depth,
702
+ const NameBag* pre_locked,
703
+ NameBag* written) {
704
+ if (!ex || !ex->sheet || !name || !vec || depth > 8) return;
705
+ size_t n = 0;
706
+ for (XsltAttrSet* s = ex->sheet->attrsets; s; s = s->next)
707
+ if (set_name_matches(s, name, uri)) n++;
708
+ if (!n) return;
709
+ AttrSetDecl* matches = (AttrSetDecl*)malloc(n * sizeof(*matches));
710
+ if (!matches) return;
711
+ size_t k = 0, seq = 0;
712
+ for (XsltAttrSet* s = ex->sheet->attrsets; s; s = s->next, seq++)
713
+ if (set_name_matches(s, name, uri)) {
714
+ matches[k].s = s;
715
+ matches[k].rank = s->import_rank;
716
+ matches[k].seq = seq;
717
+ k++;
718
+ }
719
+ qsort(matches, n, sizeof(*matches), attrset_decl_cmp);
720
+ NameBag locked = {NULL, 0, 0};
721
+ if (pre_locked)
722
+ for (size_t i = 0; i < pre_locked->n; i++)
723
+ name_bag_add(&locked, pre_locked->names[i]);
724
+ /* `written` is CALLER-OWNED: names a declaration's reference
725
+ * expansions write count as that declaration's contributions
726
+ * when the rank boundary locks (bug-188). */
727
+ int cur_rank = matches[0].rank;
728
+
729
+ for (size_t i = 0; i < n; i++) {
730
+ const XsltAttrSet* s = matches[i].s;
731
+ if (s->import_rank != cur_rank) {
732
+ /* Rank boundary: everything written so far belongs to a
733
+ * higher-precedence level and now locks its names. */
734
+ for (size_t w = 0; w < written->n; w++)
735
+ name_bag_add(&locked, written->names[w]);
736
+ cur_rank = s->import_rank;
737
+ }
738
+ /* Own attributes, document order (stored newest-first). */
739
+ NameBag own = {NULL, 0, 0};
740
+ size_t na = 0;
741
+ for (XsltLAttr* a = s->attrs; a; a = a->next) na++;
742
+ const XsltLAttr** rev =
743
+ (const XsltLAttr**)malloc((na ? na : 1) * sizeof(*rev));
744
+ if (rev) {
745
+ size_t j = 0;
746
+ for (XsltLAttr* a = s->attrs; a; a = a->next) rev[j++] = a;
747
+ for (j = na; j-- > 0;) {
748
+ const XsltLAttr* a = rev[j];
749
+ if (!a->name) continue;
750
+ name_bag_add(&own, a->name);
751
+ if (name_bag_has(&locked, a->name)) continue;
752
+ char* v = eval_avt(ex, a->value, node);
753
+ if (v) attrvec_set(vec, a->name, v);
754
+ else free(v);
755
+ name_bag_add(written, a->name);
756
+ }
757
+ free(rev);
758
+ }
759
+ /* Referenced sets: part of THIS declaration's vector — they
760
+ * must not override its own attributes. */
761
+ for (size_t u = 0; u < s->use_count; u++)
762
+ if (s->use_names[u])
763
+ apply_named_set(ex, s->use_names[u],
764
+ s->use_uris ? s->use_uris[u] : NULL,
765
+ vec, node, depth + 1, &own, written);
766
+ free(own.names);
767
+ }
768
+ free(locked.names);
769
+ free(matches);
770
+ }
771
+
772
+ void xslt_apply_attr_sets(XsltExec* ex, const XsltInstr* in,
773
+ LeptrisElement target, LeptrisElement node) {
774
+ if (!ex || !ex->sheet || !target || !in || in->attr_set_count == 0) return;
775
+ AttrVec vec = {NULL, NULL, 0, 0};
776
+ NameBag written = {NULL, 0, 0};
777
+ for (size_t i = 0; i < in->attr_set_count; i++) {
778
+ if (!in->attr_set_names[i]) continue;
779
+ apply_named_set(ex, in->attr_set_names[i],
780
+ in->attr_set_uris ? in->attr_set_uris[i] : NULL,
781
+ &vec, node, 0, NULL, &written);
782
+ }
783
+ /* Skip-if-exists: explicit attributes on the target (literal
784
+ * result attrs, xsl:copy's source attrs) win over set values. */
785
+ for (size_t i = 0; i < vec.n; i++) {
786
+ if (leptris_element_attribute(target, vec.names[i])) continue;
787
+ leptris_element_set_attribute(target, vec.names[i], vec.values[i]);
788
+ }
789
+ for (size_t i = 0; i < vec.n; i++) free(vec.values[i]);
790
+ free(vec.names);
791
+ free(vec.values);
792
+ free(written.names);
793
+ }
794
+
795
+ static int op_attr_set_ref(XsltExec* ex, const XsltInstr* in,
796
+ LeptrisElement node) {
797
+ /* Placeholder for a runtime attr-set reference from nested
798
+ * instructions. Attribute-set application happens implicitly
799
+ * during literal-result-element/op_element/op_copy creation;
800
+ * a stand-alone ATTR_SET_REF instruction appears when an
801
+ * xsl:attribute-set nests a use-attribute-sets chain — for v1
802
+ * the compile step flattens those into attr_set_names on the
803
+ * parent instruction, so this branch is reserved for future
804
+ * hookups. */
805
+ (void)ex; (void)in; (void)node;
806
+ return 0;
807
+ }
808
+
809
+ /* §7.1.1 xsl:namespace-alias: rewrite the literal result prefix
810
+ * from the stylesheet prefix to the result prefix. */
811
+ static const char* apply_ns_alias(const XsltStylesheet* sheet,
812
+ const char* qname) {
813
+ if (!sheet->ns_alias || !qname) return qname;
814
+ const char* colon = strchr(qname, ':');
815
+ if (!colon) return qname; /* default ns aliases need decl maps */
816
+ size_t pl = (size_t)(colon - qname);
817
+ for (const XsltNsAlias* na = sheet->ns_alias; na; na = na->next) {
818
+ if (!na->stylesheet_prefix ||
819
+ strlen(na->stylesheet_prefix) != pl ||
820
+ strncmp(na->stylesheet_prefix, qname, pl) != 0) continue;
821
+ if (!na->result_prefix) return colon + 1; /* → default ns */
822
+ static char buf[128]; /* single-threaded per transform */
823
+ snprintf(buf, sizeof(buf), "%s%s", na->result_prefix, colon);
824
+ return buf;
825
+ }
826
+ return qname;
827
+ }
828
+
829
+ static int op_result_elem(XsltExec* ex, const XsltInstr* in,
830
+ LeptrisElement node) {
831
+ /* libxslt's own test extension element (bug-100): <test/> in
832
+ * http://xmlsoft.org/XSLT/ is registered by libxslt's engine —
833
+ * it never serializes; it emits its marker comment. */
834
+ if (in->ns_uri && strcmp(in->ns_uri, "http://xmlsoft.org/XSLT/") == 0) {
835
+ const char* nm = in->name ? in->name : "";
836
+ const char* loc = strchr(nm, ':');
837
+ loc = loc ? loc + 1 : nm;
838
+ if (strcmp(loc, "test") == 0) {
839
+ LeptrisNodeRef cm = leptris_comment_node_create(
840
+ ex->result, "libxslt:test element test worked");
841
+ if (cm) {
842
+ if (ex->pending_parent)
843
+ leptris_element_append_child_internal(
844
+ ex->pending_parent, (LeptrisNode*)cm);
845
+ else
846
+ xslt_append_fragment_node(ex, cm);
847
+ }
848
+ return 0;
849
+ }
850
+ }
851
+ LeptrisElement parent = ex->pending_parent;
852
+ const char* out_name = apply_ns_alias(ex->sheet, in->name);
853
+ if (ex->streaming) {
854
+ /* Gate guarantees: no namespaces, no attr-sets, no
855
+ * xsl:attribute children — the open tag is complete before
856
+ * the children run, so it emits whole and the empty case
857
+ * rewrites the trailing '>' to '/>'. */
858
+ buffer_append_char(ex->sbuf, '<');
859
+ buffer_append(ex->sbuf, out_name ? out_name : "element");
860
+ for (XsltLAttr* a = in->attrs; a; a = a->next) {
861
+ char* v = eval_avt(ex, a->value, node);
862
+ buffer_append_char(ex->sbuf, ' ');
863
+ buffer_append(ex->sbuf, a->name);
864
+ buffer_append(ex->sbuf, "=\"");
865
+ stream_emit_attr_value(ex->sbuf, v ? v : "");
866
+ buffer_append_char(ex->sbuf, '"');
867
+ free(v);
868
+ }
869
+ buffer_append_char(ex->sbuf, '>');
870
+ size_t mark = ex->sbuf->size;
871
+ int rc = xslt_exec_instrs(ex, in->child, node);
872
+ if (rc == 0 && mark == ex->sbuf->size) {
873
+ /* 3.0 §26.4 on-empty: element came back empty — run the
874
+ * on-empty child's content into it. */
875
+ for (const XsltInstr* c = in->child; c; c = c->next) {
876
+ if (c->kind != XSLT_INSTR_ON_EMPTY) continue;
877
+ rc = xslt_exec_instrs(ex, c->child, node);
878
+ break;
879
+ }
880
+ }
881
+ if (mark == ex->sbuf->size && ex->sbuf->size > 0) {
882
+ ex->sbuf->data[ex->sbuf->size - 1] = '/';
883
+ buffer_append_char(ex->sbuf, '>');
884
+ } else {
885
+ buffer_append(ex->sbuf, "</");
886
+ buffer_append(ex->sbuf, out_name ? out_name : "element");
887
+ buffer_append_char(ex->sbuf, '>');
888
+ }
889
+ return rc;
890
+ }
891
+ LeptrisElement e = out_append_elem(ex, parent, out_name, in->ns_uri);
892
+ if (!e) return -1;
893
+ /* libxslt namespace fixup: an unprefixed literal with NO
894
+ * namespace of its own, constructed under a result ancestor
895
+ * binding the default prefix non-empty, must UNBIND it — the
896
+ * nearest ancestor declaration decides (bug-130's
897
+ * imported-module <div> under a default-namespaced <html>). */
898
+ if (!strchr(out_name ? out_name : "", ':') &&
899
+ (!in->ns_uri || !in->ns_uri[0]) &&
900
+ ex->result->has_namespaces) {
901
+ for (LeptrisElement a = leptris_node_parent((LeptrisNodeRef)e);
902
+ a; a = leptris_node_parent((LeptrisNodeRef)a)) {
903
+ int decided = 0;
904
+ for (struct leptris_namespace* ns = leptris_elem_namespaces(a);
905
+ ns; ns = ns->next) {
906
+ if (!ns->prefix || !ns->prefix[0]) {
907
+ if (ns->uri && ns->uri[0])
908
+ leptris_element_add_namespace_definition(e, "", "");
909
+ decided = 1;
910
+ break;
911
+ }
912
+ }
913
+ if (decided) break;
914
+ }
915
+ }
916
+ /* §7.1.1: copy in-scope namespace declarations. Skip any
917
+ * binding already present on a RESULT ancestor (full chain,
918
+ * not just the immediate parent — a literal-result-element
919
+ * may appear deeply nested without redeclaring its ancestors'
920
+ * ns). The element's OWN prefix binding leads the chain —
921
+ * libxslt creates the element with its namespace, then copies
922
+ * the remaining in-scope declarations (bug-71). */
923
+ const char* oname = out_name ? out_name : "";
924
+ const char* ocolon = strchr(oname, ':');
925
+ const char* own_pfx = NULL;
926
+ char pbuf[96];
927
+ if (ocolon && in->ns_uri) {
928
+ size_t pl = (size_t)(ocolon - oname);
929
+ if (pl < sizeof(pbuf)) {
930
+ memcpy(pbuf, oname, pl);
931
+ pbuf[pl] = 0;
932
+ own_pfx = pbuf;
933
+ if (!result_ns_in_scope(e, own_pfx, in->ns_uri))
934
+ leptris_element_add_namespace_definition(e, own_pfx,
935
+ in->ns_uri);
936
+ }
937
+ }
938
+ /* The default namespace emits at its SOURCE position among the
939
+ * prefixed declarations (bug-150), not pinned last. */
940
+ size_t dpos = in->ns_out_count;
941
+ if (in->ns_out_default &&
942
+ in->ns_out_default_pos != (size_t)-1 &&
943
+ in->ns_out_default_pos <= in->ns_out_count)
944
+ dpos = in->ns_out_default_pos;
945
+ for (size_t i = 0; i <= in->ns_out_count; i++) {
946
+ if (in->ns_out_default && i == dpos &&
947
+ !result_ns_in_scope(e, "", in->ns_out_default)) {
948
+ leptris_element_add_namespace_definition(
949
+ e, "", in->ns_out_default);
950
+ }
951
+ if (i == in->ns_out_count) break;
952
+ if (result_ns_in_scope(e, in->ns_out_pfx[i],
953
+ in->ns_out_uri[i])) continue;
954
+ /* The hoisted own-prefix binding (same URI) is covered. */
955
+ if (own_pfx && in->ns_out_pfx[i] &&
956
+ strcmp(own_pfx, in->ns_out_pfx[i]) == 0 &&
957
+ in->ns_out_uri[i] && in->ns_uri &&
958
+ strcmp(in->ns_out_uri[i], in->ns_uri) == 0)
959
+ continue;
960
+ leptris_element_add_namespace_definition(e, in->ns_out_pfx[i],
961
+ in->ns_out_uri[i]);
962
+ }
963
+ /* §7.1.4: literal attrs first (they win positions and values);
964
+ * the resolved attribute-set vector then fills missing names. */
965
+ for (XsltLAttr* a = in->attrs; a; a = a->next) {
966
+ char* v = eval_avt(ex, a->value, node);
967
+ if (v) {
968
+ leptris_element_set_attribute(e, a->name, v);
969
+ free(v);
970
+ }
971
+ }
972
+ xslt_apply_attr_sets(ex, in, e, node);
973
+ ex->pending_parent = e;
974
+ int rc = xslt_exec_instrs(ex, in->child, node);
975
+ /* 3.0 §26.4 xsl:on-empty: content came back empty (no child
976
+ * nodes built) — run the on-empty child's content into the
977
+ * element. The walker skips ON_EMPTY (no registered op). Raw
978
+ * first-child: text nodes count as content (the *_any accessor
979
+ * skips them). */
980
+ if (rc == 0 && !leptris_elem_first_child(e)) {
981
+ for (const XsltInstr* c = in->child; c; c = c->next) {
982
+ if (c->kind != XSLT_INSTR_ON_EMPTY) continue;
983
+ ex->pending_parent = e;
984
+ rc = xslt_exec_instrs(ex, c->child, node);
985
+ break;
986
+ }
987
+ }
988
+ ex->pending_parent = parent;
989
+ return rc;
990
+ }
991
+
992
+ /* Escape & < > for fragment-level accumulation under the xml/html
993
+ * methods (the accumulators concatenate verbatim; §16.3 text method
994
+ * never escapes). DOE text stays raw. */
995
+ static char* escape_fragment_text(const char* t, int doe) {
996
+ if (!t || doe) return (char*)t;
997
+ size_t n = 0;
998
+ for (const char* p = t; *p; p++) {
999
+ if (*p == '&') n += 5; /* &amp; */
1000
+ else if (*p == '<' || *p == '>') n += 4; /* &lt; &gt; */
1001
+ else n++;
1002
+ }
1003
+ if (n == strlen(t)) return (char*)t; /* nothing to escape */
1004
+ char* out = (char*)malloc(n + 1);
1005
+ if (!out) return (char*)t;
1006
+ char* o = out;
1007
+ for (const char* p = t; *p; p++) {
1008
+ if (*p == '&') { memcpy(o, "&amp;", 5); o += 5; }
1009
+ else if (*p == '<') { memcpy(o, "&lt;", 4); o += 4; }
1010
+ else if (*p == '>') { memcpy(o, "&gt;", 4); o += 4; }
1011
+ else *o++ = *p;
1012
+ }
1013
+ *o = 0;
1014
+ return out;
1015
+ }
1016
+
1017
+
1018
+ /* Fragment-level node (comment/PI with no pending parent): chain as
1019
+ * a child of the current result root when one exists, else hold on
1020
+ * the frag list until an element anchors the chain. Both chains
1021
+ * append at the CACHED tail — the per-append tail walk was O(N)
1022
+ * (#682). */
1023
+ static void xslt_append_fragment_node(XsltExec* ex, LeptrisNodeRef n) {
1024
+ LeptrisElement root = leptris_document_root(ex->result);
1025
+ if (root) {
1026
+ /* Chain AFTER the root's sibling tail — the same layout
1027
+ * out_append_elem uses for multiple top-level elements, so
1028
+ * serialization walks one chain for every node kind. The
1029
+ * cached tail is valid while its next is NULL (result
1030
+ * chains are append-only); a stale entry falls back to the
1031
+ * walk. */
1032
+ LeptrisNodeRef last = ex->root_sib_tail;
1033
+ if (!last || leptris_node_get_next_sibling(last))
1034
+ for (last = leptris_element_as_node(root);
1035
+ leptris_node_get_next_sibling(last);
1036
+ last = leptris_node_get_next_sibling(last)) {}
1037
+ leptris_node_set_next_sibling(last, n);
1038
+ ex->root_sib_tail = n;
1039
+ return;
1040
+ }
1041
+ XsltFragNode* fn = (XsltFragNode*)calloc(1, sizeof(*fn));
1042
+ if (!fn) return;
1043
+ fn->node = n;
1044
+ if (!ex->frag_nodes) {
1045
+ ex->frag_nodes = fn;
1046
+ } else {
1047
+ XsltFragNode* t = (XsltFragNode*)ex->frag_tail;
1048
+ if (!t)
1049
+ for (t = (XsltFragNode*)ex->frag_nodes; t->next; t = t->next) {}
1050
+ t->next = fn;
1051
+ }
1052
+ ex->frag_tail = fn;
1053
+ }
1054
+
1055
+ static int op_text(XsltExec* ex, const XsltInstr* in, LeptrisElement node) {
1056
+ /* 3.0 §10.4.2: expand {expr} value templates first (xsl:text
1057
+ * content included — Saxon-verified). */
1058
+ char* tvt = in->tvt && in->text ? eval_avt(ex, in->text, node) : NULL;
1059
+ const char* text = tvt ? tvt : in->text;
1060
+ if (ex->streaming && !ex->rtf_capturing) {
1061
+ /* Gate rejects DOE in stream sheets; escaping matches the
1062
+ * serializer's text mode. */
1063
+ if (text) stream_emit_text(ex->sbuf, text);
1064
+ free(tvt);
1065
+ return 0;
1066
+ }
1067
+ LeptrisElement parent = ex->pending_parent;
1068
+ if (parent) {
1069
+ if (in->doe && text) {
1070
+ /* §16.4 disable-output-escaping: raw flag — the
1071
+ * serializer emits the string verbatim. */
1072
+ LeptrisNodeRef t = leptris_text_node_create(ex->result, text);
1073
+ if (t) {
1074
+ ((LeptrisTextNode*)t)->base.raw = 1;
1075
+ out_append_child(ex, parent, t);
1076
+ }
1077
+ free(tvt);
1078
+ return 0;
1079
+ }
1080
+ /* Non-DOE: out_append_text (carries the cdata-section-
1081
+ * elements conversion for listed parents). */
1082
+ out_append_text(ex, parent, text);
1083
+ free(tvt);
1084
+ return 0;
1085
+ }
1086
+ /* Fragment-level: accumulate verbatim-safe — escape unless DOE
1087
+ * or method=text (§16.3 never escapes). RTF capture stores the
1088
+ * LOGICAL text: a pure-text fragment binds as a string, and
1089
+ * string($rtf) is unescaped — pre-escaping here leaked &amp;
1090
+ * into param values (bug-90). */
1091
+ char* v = text ? escape_fragment_text(
1092
+ text,
1093
+ in->doe || ex->sheet->out_method_text ||
1094
+ ex->rtf_capturing) : NULL;
1095
+ if (v) {
1096
+ out_append_text(ex, NULL, v);
1097
+ if (v != text) free(v);
1098
+ }
1099
+ free(tvt);
1100
+ return 0;
1101
+ }
1102
+
1103
+ /* value-of display semantics: an item sequence (for/range/sequence)
1104
+ * joins members with the default separator " "; a 2.0+ stylesheet
1105
+ * selects a sequence from ANY expression — every item prints. A 1.0
1106
+ * stylesheet's plain nodeset keeps the 1.0 first-member rule. */
1107
+ static char* value_of_string(XsltExec* ex,
1108
+ const struct leptris_xpath_result* r) {
1109
+ if (r->type == XPATH_RESULT_NODESET && r->value.nodeset_value &&
1110
+ (r->value.nodeset_value->is_sequence ||
1111
+ (ex->sheet && ex->sheet->version_major >= 2))) {
1112
+ XPathNodeSet* ns = r->value.nodeset_value;
1113
+ size_t total = 1; /* NUL; + separators below */
1114
+ for (size_t i = 0; i < ns->count; i++) {
1115
+ extern char* get_node_text(void* n);
1116
+ char* t = get_node_text(ns->nodes[i]);
1117
+ if (t) { total += strlen(t); free(t); }
1118
+ if (i + 1 < ns->count) total += 1; /* " " */
1119
+ }
1120
+ char* sv = (char*)malloc(total);
1121
+ if (sv) {
1122
+ char* w = sv;
1123
+ for (size_t i = 0; i < ns->count; i++) {
1124
+ char* t = get_node_text(ns->nodes[i]);
1125
+ if (t) { size_t l = strlen(t); memcpy(w, t, l); w += l; free(t); }
1126
+ if (i + 1 < ns->count) *w++ = ' ';
1127
+ }
1128
+ *w = '\0';
1129
+ }
1130
+ return sv;
1131
+ }
1132
+ return leptris_xpath_result_string(
1133
+ (struct leptris_xpath_result*)r);
1134
+ }
1135
+
1136
+ static void xslt_sort_items(XsltExec* ex, const XsltInstr* in,
1137
+ LeptrisElement* items, size_t n);
1138
+ static int copy_node_deep(XsltExec* ex, LeptrisElement node,
1139
+ LeptrisElement parent);
1140
+
1141
+ /* xsl:sequence / xsl:perform-sort (3.0): atomic items serialize
1142
+ * space-joined into the output; node items are copied in order
1143
+ * (Saxon ground truth). perform-sort applies the xsl:sort
1144
+ * children to the item list first. */
1145
+ static int op_sequence(XsltExec* ex, const XsltInstr* in,
1146
+ LeptrisElement node) {
1147
+ if (!in->select) return 0;
1148
+ struct leptris_xpath_result* r = xslt_eval(ex, in->select, node);
1149
+ if (!r) return 0;
1150
+ /* A single ATOMIC item is a scalar result — count() is 0 for
1151
+ * those, so string-join it directly (#685 remainder: single-
1152
+ * item sequences silently dropped their content). */
1153
+ if (r->type != XPATH_RESULT_NODESET) {
1154
+ char* p = leptris_xpath_result_string(r);
1155
+ /* Sequence items serialize space-separated — including
1156
+ * across consecutive sequence instructions (fork arms). */
1157
+ if (p && p[0] && ex->pending_parent &&
1158
+ leptris_elem_first_child(ex->pending_parent))
1159
+ out_append_text(ex, ex->pending_parent, " ");
1160
+ out_append_text(ex, ex->pending_parent, p ? p : "");
1161
+ free(p);
1162
+ leptris_xpath_result_free(r);
1163
+ return 0;
1164
+ }
1165
+ size_t n = leptris_xpath_result_count(r);
1166
+ LeptrisElement* items = NULL;
1167
+ if (n) {
1168
+ items = (LeptrisElement*)calloc(n, sizeof(LeptrisElement));
1169
+ if (!items) { leptris_xpath_result_free(r); return -1; }
1170
+ for (size_t i = 0; i < n; i++)
1171
+ items[i] = (LeptrisElement)leptris_xpath_result_get_node(r, i);
1172
+ if (in->sorts) xslt_sort_items(ex, in, items, n);
1173
+ }
1174
+ int rc = 0;
1175
+ for (size_t i = 0; i < n && rc == 0; i++) {
1176
+ LeptrisNodeRef it = (LeptrisNodeRef)items[i];
1177
+ int ty = it ? leptris_node_get_type(it) : 0;
1178
+ if (ty == LEPTRIS_NODE_TYPE_ELEMENT ||
1179
+ ty == LEPTRIS_NODE_TYPE_COMMENT ||
1180
+ ty == LEPTRIS_NODE_TYPE_PI ||
1181
+ ty == LEPTRIS_NODE_TYPE_CDATA) {
1182
+ copy_node_deep(ex, (LeptrisElement)it, ex->pending_parent);
1183
+ (void)0;
1184
+ } else {
1185
+ /* Atomic/textual item: space-joined text. */
1186
+ extern char* get_node_text(void* n);
1187
+ char* piece = get_node_text(it);
1188
+ if (i && piece && piece[0]) out_append_text(ex, ex->pending_parent, " ");
1189
+ if (piece) {
1190
+ out_append_text(ex, ex->pending_parent, piece);
1191
+ free(piece);
1192
+ }
1193
+ }
1194
+ }
1195
+ free(items);
1196
+ leptris_xpath_result_free(r);
1197
+ return rc;
1198
+ }
1199
+
1200
+ static int op_value_of(XsltExec* ex, const XsltInstr* in,
1201
+ LeptrisElement node) {
1202
+ /* select="." (parse-time flag): the string-value of the context
1203
+ * node, directly — the eval machinery would build a single-node
1204
+ * nodeset, a result wrapper and a conversion string per call
1205
+ * (#682; get_node_text IS the string-value for every node
1206
+ * kind, markers stripped). */
1207
+ char* sv = NULL;
1208
+ if (in->select_is_dot) {
1209
+ extern char* get_node_text(void* n);
1210
+ sv = get_node_text(node);
1211
+ } else if (in->select_attr_name) {
1212
+ /* #682: one unprefixed attribute step — same string as the
1213
+ * one-attribute nodeset (value or "" when absent, both
1214
+ * value_of_string paths agree) without the eval machinery.
1215
+ * The lookup rides the hash-prefiltered exact-name walk
1216
+ * directly: a colon-free needle can only match an attr whose
1217
+ * FULL name is the needle, which is exactly the bare-name
1218
+ * rule (#542). Entity-bearing values fall back to the public
1219
+ * accessor for the lazy decode; non-element context nodes
1220
+ * yield the empty axis. */
1221
+ const char* v = NULL;
1222
+ if (((LeptrisNode*)node)->type == LEPTRIS_NODE_TYPE_ELEMENT) {
1223
+ struct leptris_attribute* a = leptris_dom_attr_find(
1224
+ node, in->select_attr_name,
1225
+ leptris_cstr_len16(in->select_attr_name));
1226
+ if (a) {
1227
+ if (attr_has_entities(a)) {
1228
+ v = leptris_element_attribute(node,
1229
+ in->select_attr_name);
1230
+ } else {
1231
+ LeptrisStringView vs = leptris_attr_value_sv(a);
1232
+ v = vs.length ? vs.data : "";
1233
+ }
1234
+ }
1235
+ }
1236
+ sv = leptris_strdup(v ? v : "");
1237
+ } else {
1238
+ struct leptris_xpath_result* r = xslt_eval(ex, in->select, node);
1239
+ if (!r) return 0;
1240
+ sv = value_of_string(ex, r);
1241
+ leptris_xpath_result_free(r);
1242
+ }
1243
+ if (sv) {
1244
+ op_text(ex, &(XsltInstr){ .kind = XSLT_INSTR_TEXT, .text = sv,
1245
+ .doe = in->doe },
1246
+ node);
1247
+ leptris_free_string(sv);
1248
+ }
1249
+ return 0;
1250
+ }
1251
+
1252
+ /* xsl:evaluate (3.0 §26): @xpath evaluates to a STRING — the XPath
1253
+ * to compile and run now; @context-item picks its context node
1254
+ * (omitted or empty = absent context: the source document node
1255
+ * anchors absolute paths, Saxon-verified default). */
1256
+ static int op_evaluate(XsltExec* ex, const XsltInstr* in,
1257
+ LeptrisElement node) {
1258
+ struct leptris_xpath_result* xr = xslt_eval(ex, in->select, node);
1259
+ if (!xr) return 0;
1260
+ char* expr = leptris_xpath_result_string(xr);
1261
+ leptris_xpath_result_free(xr);
1262
+ if (!expr) return 0;
1263
+ LeptrisXPathCompiled c = leptris_xpath_compile(expr);
1264
+ free(expr);
1265
+ if (!c) return 0;
1266
+ LeptrisElement ctx = NULL;
1267
+ if (in->context_item) {
1268
+ struct leptris_xpath_result* cr =
1269
+ xslt_eval(ex, in->context_item, node);
1270
+ if (cr && cr->type == XPATH_RESULT_NODESET &&
1271
+ cr->value.nodeset_value && cr->value.nodeset_value->count)
1272
+ ctx = (LeptrisElement)cr->value.nodeset_value->nodes[0];
1273
+ if (cr) leptris_xpath_result_free(cr);
1274
+ }
1275
+ if (!ctx) {
1276
+ LeptrisNodeRef dn =
1277
+ (LeptrisNodeRef)leptris_document_get_node(ex->source);
1278
+ ctx = (LeptrisElement)dn;
1279
+ }
1280
+ /* Child xsl:with-param bindings are visible to the DYNAMIC
1281
+ * evaluation only (Saxon-HE 12.7 verified: @xpath's own
1282
+ * evaluation resolves the outer bindings). xslt_push_var (not a
1283
+ * raw XsltVar link) — the eval varset must be marked dirty or
1284
+ * the new binding never reaches variable lookup. */
1285
+ XsltVar* scope_mark = ex->vars;
1286
+ for (const XsltInstr* w = in->child; w; w = w->next) {
1287
+ if (w->kind != XSLT_INSTR_WITH_PARAM || !w->name) continue;
1288
+ struct leptris_xpath_result* v = NULL;
1289
+ if (w->select) v = xslt_eval(ex, w->select, node);
1290
+ else if (w->child) v = xslt_capture_content(ex, w->child, node);
1291
+ xslt_push_var(ex, w->name, v);
1292
+ }
1293
+ struct leptris_xpath_result* r = ctx ? xslt_eval(ex, c, ctx) : NULL;
1294
+ xslt_pop_vars_to(ex, scope_mark);
1295
+ leptris_xpath_compiled_free(c);
1296
+ if (!r) return 0;
1297
+ char* sv = value_of_string(ex, r);
1298
+ leptris_xpath_result_free(r);
1299
+ if (sv) {
1300
+ op_text(ex, &(XsltInstr){ .kind = XSLT_INSTR_TEXT, .text = sv },
1301
+ node);
1302
+ leptris_free_string(sv);
1303
+ }
1304
+ return 0;
1305
+ }
1306
+
1307
+ /* xsl:analyze-string (3.0 §18): regex-scan the selected string;
1308
+ * matching/non-matching segments run their sub-instruction bodies
1309
+ * with a synthetic text node carrying the segment (string(.) reads
1310
+ * it). POSIX ERE on POSIX platforms; MSVC builds no-op (same
1311
+ * limitation as the EXSLT regexp handlers). */
1312
+ #ifndef _WIN32
1313
+ #include <regex.h>
1314
+ #endif
1315
+
1316
+ static XPathTextNode* as_segment_node(const char* s, size_t len) {
1317
+ XPathTextNode* tn = (XPathTextNode*)calloc(1, sizeof(*tn));
1318
+ if (!tn) return NULL;
1319
+ char* copy = (char*)malloc(len + 1);
1320
+ if (!copy) { free(tn); return NULL; }
1321
+ memcpy(copy, s, len);
1322
+ copy[len] = '\0';
1323
+ tn->node_type = LEPTRIS_NODE_TEXT;
1324
+ tn->content = copy;
1325
+ return tn;
1326
+ }
1327
+
1328
+ static void as_segment_free(XPathTextNode* tn) {
1329
+ if (!tn) return;
1330
+ free(tn->content);
1331
+ free(tn);
1332
+ }
1333
+
1334
+ static int op_analyze_string(XsltExec* ex, const XsltInstr* in,
1335
+ LeptrisElement node) {
1336
+ if (!in->select || !in->regex) return 0;
1337
+ struct leptris_xpath_result* r = xslt_eval(ex, in->select, node);
1338
+ if (!r) return 0;
1339
+ char* src = leptris_xpath_result_string(r);
1340
+ leptris_xpath_result_free(r);
1341
+ if (!src) return 0;
1342
+ int rc = 0;
1343
+ #ifndef _WIN32
1344
+ regex_t rx;
1345
+ int cflags = REG_EXTENDED;
1346
+ if (in->regex_flags && strchr(in->regex_flags, 'i'))
1347
+ cflags |= REG_ICASE;
1348
+ if (regcomp(&rx, in->regex, cflags) != 0) { free(src); return 0; }
1349
+ size_t nmatch = rx.re_nsub + 1;
1350
+ regmatch_t* pm = (regmatch_t*)calloc(nmatch, sizeof(*pm));
1351
+ if (!pm) { regfree(&rx); free(src); return 0; }
1352
+
1353
+ const XsltInstr* match_body = NULL;
1354
+ const XsltInstr* nonmatch_body = NULL;
1355
+ for (const XsltInstr* c = in->child; c; c = c->next) {
1356
+ if (c->kind == XSLT_INSTR_MATCHING_SUBSTRING)
1357
+ match_body = c->child;
1358
+ else if (c->kind == XSLT_INSTR_NONMATCHING_SUBSTRING)
1359
+ nonmatch_body = c->child;
1360
+ }
1361
+
1362
+ char* saved_src = ex->as_src;
1363
+ void* saved_pm = ex->as_pmatch;
1364
+ size_t saved_nmatch = ex->as_nmatch;
1365
+ size_t saved_pos = ex->as_pos;
1366
+
1367
+ size_t pos = 0;
1368
+ while (src[pos] && rc == 0) {
1369
+ if (regexec(&rx, src + pos, nmatch, pm, 0) != 0) break;
1370
+ size_t so = pos + (size_t)(pm[0].rm_so > 0 ? pm[0].rm_so : 0);
1371
+ size_t eo = pos + (size_t)pm[0].rm_eo;
1372
+ if (nonmatch_body && so > pos) {
1373
+ XPathTextNode* tn = as_segment_node(src + pos, so - pos);
1374
+ if (tn) {
1375
+ rc = xslt_exec_instrs(ex, nonmatch_body,
1376
+ (LeptrisElement)tn);
1377
+ as_segment_free(tn);
1378
+ }
1379
+ }
1380
+ if (match_body && rc == 0) {
1381
+ ex->as_src = src;
1382
+ ex->as_pmatch = pm;
1383
+ ex->as_nmatch = nmatch;
1384
+ ex->as_pos = pos;
1385
+ XPathTextNode* tn = as_segment_node(src + so, eo - so);
1386
+ if (tn) {
1387
+ rc = xslt_exec_instrs(ex, match_body,
1388
+ (LeptrisElement)tn);
1389
+ as_segment_free(tn);
1390
+ }
1391
+ ex->as_src = saved_src;
1392
+ ex->as_pmatch = saved_pm;
1393
+ ex->as_nmatch = saved_nmatch;
1394
+ ex->as_pos = saved_pos;
1395
+ }
1396
+ /* Zero-length match: advance one char so the scan terminates. */
1397
+ pos = (eo == so) ? so + 1 : eo;
1398
+ }
1399
+ if (rc == 0 && nonmatch_body && src[pos]) {
1400
+ XPathTextNode* tn = as_segment_node(src + pos, strlen(src) - pos);
1401
+ if (tn) {
1402
+ rc = xslt_exec_instrs(ex, nonmatch_body, (LeptrisElement)tn);
1403
+ as_segment_free(tn);
1404
+ }
1405
+ }
1406
+ regfree(&rx);
1407
+ free(pm);
1408
+ #else
1409
+ /* MSVC has no POSIX <regex.h>: raise a loud, CATCHABLE dynamic
1410
+ * error (xsl:try) instead of silently emitting empty output
1411
+ * (issue #686). A portable regex engine is the full fix. */
1412
+ (void)rc;
1413
+ ex->eval_error = 1;
1414
+ snprintf(ex->error, sizeof(ex->error),
1415
+ "xsl:analyze-string unavailable in this platform build "
1416
+ "(no regex engine) — issue #686");
1417
+ free(src);
1418
+ return 1;
1419
+ #endif
1420
+ #ifndef _WIN32
1421
+ free(src);
1422
+ return rc;
1423
+ #endif
1424
+ }
1425
+
1426
+ /* xsl:try/xsl:catch (3.0 §17): the body is the children before the
1427
+ * first xsl:catch. A dynamic error (eval_error channel — raised by
1428
+ * failing evaluations or the error() bridge) runs the catch content
1429
+ * with $err:description bound to the message; the channel clears so
1430
+ * the transform continues. */
1431
+ /* 3.0 §26.4: Saxon-HE 12.7 evaluates on-non-empty content
1432
+ * unconditionally (verified against the oracle; the spec allows
1433
+ * buffering, parity follows observed behavior). */
1434
+ /* 3.0 §14 fork: non-streaming = the arms run sequentially into
1435
+ * the same destination (Saxon-HE ground truth). */
1436
+ static int op_fork(XsltExec* ex, const XsltInstr* in,
1437
+ LeptrisElement node) {
1438
+ if (!in->child) return 0;
1439
+ return xslt_exec_instrs(ex, in->child, node);
1440
+ }
1441
+
1442
+ /* 2.0 §11.7 xsl:namespace: bind prefix->URI on the pending
1443
+ * parent (a namespace node in the result). The URI is the string
1444
+ * value of the content, captured off-tree (a scratch rtf buffer —
1445
+ * emitting into the live result leaks text into the output). */
1446
+ static int op_namespace(XsltExec* ex, const XsltInstr* in,
1447
+ LeptrisElement node) {
1448
+ if (!in->name || !ex->pending_parent) return 0;
1449
+ char* uri = xslt_capture_children_text(ex, in->child, node);
1450
+ if (uri) {
1451
+ leptris_element_add_namespace_definition(ex->pending_parent,
1452
+ in->name, uri);
1453
+ free(uri);
1454
+ }
1455
+ return 0;
1456
+ }
1457
+
1458
+ /* 2.0 §11.8 xsl:document: content flows to the pending parent. */
1459
+ static int op_document(XsltExec* ex, const XsltInstr* in,
1460
+ LeptrisElement node) {
1461
+ if (!in->child) return 0;
1462
+ return xslt_exec_instrs(ex, in->child, node);
1463
+ }
1464
+
1465
+ /* §16.1 character-map substitution on a SERIALIZED string: mapped
1466
+ * characters are replaced in text spans and inside attribute-value
1467
+ * quotes — never elsewhere in markup (comments/PIs count as markup).
1468
+ * Returns a fresh string, or NULL when no active map matches. */
1469
+ char* xslt_apply_output_charmaps(const XsltStylesheet* sheet,
1470
+ const char* s) {
1471
+ if (!sheet || !s || !sheet->out_charmap_name_count) return NULL;
1472
+ size_t active = 0;
1473
+ for (size_t i = 0; i < sheet->out_charmap_name_count; i++)
1474
+ for (size_t m = 0; m < sheet->charmap_count; m++)
1475
+ if (sheet->charmaps[m].name &&
1476
+ strcmp(sheet->out_charmap_names[i],
1477
+ sheet->charmaps[m].name) == 0)
1478
+ active += sheet->charmaps[m].count;
1479
+ if (!active) return NULL;
1480
+ size_t cap = strlen(s) + 64, len = 0;
1481
+ char* out = (char*)malloc(cap);
1482
+ if (!out) return NULL;
1483
+ int in_tag = 0, quote = 0, changed = 0;
1484
+ for (size_t i = 0; s[i];) {
1485
+ const char* repl = NULL;
1486
+ size_t clen = 1;
1487
+ if (!in_tag || quote) {
1488
+ for (size_t n = 0; n < sheet->out_charmap_name_count && !repl;
1489
+ n++)
1490
+ for (size_t m = 0; m < sheet->charmap_count && !repl; m++) {
1491
+ if (!sheet->charmaps[m].name ||
1492
+ strcmp(sheet->out_charmap_names[n],
1493
+ sheet->charmaps[m].name) != 0)
1494
+ continue;
1495
+ for (size_t k = 0; k < sheet->charmaps[m].count; k++) {
1496
+ const char* c = sheet->charmaps[m].chars[k];
1497
+ size_t cl = strlen(c);
1498
+ if (cl && strncmp(s + i, c, cl) == 0) {
1499
+ repl = sheet->charmaps[m].repls[k];
1500
+ clen = cl;
1501
+ break;
1502
+ }
1503
+ }
1504
+ }
1505
+ }
1506
+ const char* emit;
1507
+ size_t elen;
1508
+ if (repl) {
1509
+ emit = repl;
1510
+ elen = strlen(repl);
1511
+ changed = 1;
1512
+ } else {
1513
+ emit = s + i;
1514
+ elen = 1;
1515
+ if (!in_tag) {
1516
+ if (s[i] == '<') in_tag = 1;
1517
+ } else if (quote) {
1518
+ if (s[i] == quote) quote = 0;
1519
+ } else {
1520
+ if (s[i] == '"' || s[i] == '\'') quote = s[i];
1521
+ else if (s[i] == '>') in_tag = 0;
1522
+ }
1523
+ }
1524
+ while (len + elen + 1 > cap) {
1525
+ cap *= 2;
1526
+ char* ng = (char*)realloc(out, cap);
1527
+ if (!ng) { free(out); return NULL; }
1528
+ out = ng;
1529
+ }
1530
+ memcpy(out + len, emit, elen);
1531
+ len += elen;
1532
+ i += clen;
1533
+ }
1534
+ if (!changed) { free(out); return NULL; }
1535
+ out[len] = '\0';
1536
+ return out;
1537
+ }
1538
+
1539
+ /* Create every directory component of a file path (best effort). */
1540
+ static void mkpath_for_file(const char* file) {
1541
+ char* dup = leptris_strdup(file);
1542
+ if (!dup) return;
1543
+ for (char* p = dup + 1; *p; p++) {
1544
+ if (*p != '/') continue;
1545
+ *p = '\0';
1546
+ #if defined(_WIN32)
1547
+ _mkdir(dup);
1548
+ #else
1549
+ mkdir(dup, 0755);
1550
+ #endif
1551
+ *p = '/';
1552
+ }
1553
+ free(dup);
1554
+ }
1555
+
1556
+ /* 2.0/3.0 §11.8 xsl:result-document: build the content in a fresh
1557
+ * scratch document, serialize it (with the sheet's character maps),
1558
+ * and write it to the href file. The principal result is unchanged. */
1559
+ static int op_result_document(XsltExec* ex, const XsltInstr* in,
1560
+ LeptrisElement node) {
1561
+ if (!in->name || !in->child) return 0;
1562
+ LeptrisDocument saved_res = ex->result;
1563
+ LeptrisElement saved_pp = ex->pending_parent;
1564
+ ex->result = leptris_document_create();
1565
+ ex->pending_parent = NULL;
1566
+ xslt_exec_instrs(ex, in->child, node);
1567
+ LeptrisDocument rd = ex->result;
1568
+ ex->result = saved_res;
1569
+ ex->pending_parent = saved_pp;
1570
+ LeptrisSerializeOptions opts;
1571
+ memset(&opts, 0, sizeof(opts));
1572
+ opts.xml_declaration = 1;
1573
+ opts.encoding = "UTF-8";
1574
+ char* out = leptris_document_serialize(rd, &opts);
1575
+ leptris_document_free(rd);
1576
+ if (!out) return 0;
1577
+ char* mapped = xslt_apply_output_charmaps(ex->sheet, out);
1578
+ if (mapped) { free(out); out = mapped; }
1579
+ mkpath_for_file(in->name);
1580
+ FILE* f = fopen(in->name, "wb");
1581
+ if (f) {
1582
+ fwrite(out, 1, strlen(out), f);
1583
+ fclose(f);
1584
+ }
1585
+ free(out);
1586
+ return 0;
1587
+ }
1588
+
1589
+ static int op_on_non_empty(XsltExec* ex, const XsltInstr* in,
1590
+ LeptrisElement node) {
1591
+ if (!in->child) return 0;
1592
+ return xslt_exec_instrs(ex, in->child, node);
1593
+ }
1594
+
1595
+ /* 3.0 §26.2 where-populated: content runs into a scratch element;
1596
+ * nodes built there splice into the real parent, an empty build
1597
+ * vanishes. */
1598
+ static int op_where_populated(XsltExec* ex, const XsltInstr* in,
1599
+ LeptrisElement node) {
1600
+ if (!in->child) return 0;
1601
+ LeptrisElement saved = ex->pending_parent;
1602
+ /* A detached scratch element on the result document — never in
1603
+ * the fragment chain, so an empty build cannot leak a wrapper
1604
+ * into the output. */
1605
+ LeptrisElement scratch = leptris_element_create(ex->result, "wp");
1606
+ if (!scratch) {
1607
+ ex->pending_parent = saved;
1608
+ return xslt_exec_instrs(ex, in->child, node);
1609
+ }
1610
+ ex->pending_parent = scratch;
1611
+ int rc = xslt_exec_instrs(ex, in->child, node);
1612
+ ex->pending_parent = saved;
1613
+ if (rc) return rc;
1614
+ if (!leptris_elem_first_child(scratch)) return 0; /* empty: drop */
1615
+ /* Splice scratch children into the real parent. */
1616
+ LeptrisNodeRef c = leptris_node_first_child(leptris_element_as_node(scratch));
1617
+ while (c) {
1618
+ LeptrisNodeRef nx = leptris_node_next_sibling(c);
1619
+ leptris_element_append_child_internal(
1620
+ ex->pending_parent ? ex->pending_parent
1621
+ : (LeptrisElement)leptris_document_root(
1622
+ ex->result),
1623
+ (LeptrisNode*)c);
1624
+ c = nx;
1625
+ }
1626
+ return 0;
1627
+ }
1628
+
1629
+ /* 3.0 §6.6 next-match: among templates matching the node, invoke
1630
+ * the best one strictly WORSE than the current rule (import rank,
1631
+ * then priority, then declaration order). */
1632
+ static int op_apply_templates(XsltExec* ex, const XsltInstr* in,
1633
+ LeptrisElement node);
1634
+ static int xslt_invoke_template(XsltExec* ex, const XsltTemplate* t,
1635
+ LeptrisElement node,
1636
+ const XsltInstr* with_params);
1637
+
1638
+ static double cur_pri_of(const XsltTemplate* t) {
1639
+ double pri = 0;
1640
+ for (const XsltPattern* pa = t->matches; pa; pa = pa->next)
1641
+ if (pa->priority > pri) pri = pa->priority;
1642
+ return pri;
1643
+ }
1644
+
1645
+ /* #866: a template reachable through several name keys must be
1646
+ * considered once per dispatch — stamp it with the select call's
1647
+ * generation instead of keeping a seen-list. */
1648
+ static LEPTRIS_THREAD_LOCAL unsigned xslt_dispatch_gen;
1649
+ #define XSLT_DISPATCH_NEXT_GEN() (++xslt_dispatch_gen)
1650
+
1651
+ static const XsltTemplate* xslt_select_next_match(
1652
+ const XsltExec* ex, LeptrisElement node, const char* mode) {
1653
+ const XsltTemplate* cur = ex->current_template;
1654
+ if (!cur) return NULL;
1655
+ const XsltTemplate* best = NULL;
1656
+ double best_pri = 0;
1657
+ size_t best_order = 0;
1658
+ const double cur_pri = cur_pri_of(cur);
1659
+ const size_t cur_order = cur->order;
1660
+ const XsltModeBucket* bucket = xslt_sheet_mode(ex->sheet, mode);
1661
+ if (!bucket) return NULL;
1662
+ const int node_is_elem = leptris_node_get_type((LeptrisNodeRef)node) ==
1663
+ LEPTRIS_NODE_TYPE_ELEMENT;
1664
+ const XsltNameKey* nkey = NULL;
1665
+ if (node_is_elem) {
1666
+ const char* nn = leptris_element_get_name(node);
1667
+ if (nn) nkey = xslt_bucket_name_key(bucket, nn);
1668
+ }
1669
+ size_t nattrs = node_is_elem
1670
+ ? leptris_element_attribute_count(node) : 0;
1671
+ const unsigned gen = XSLT_DISPATCH_NEXT_GEN();
1672
+ for (int part = 0; part < 2 + (int)nattrs; part++) {
1673
+ XsltTemplate* const* cand = NULL;
1674
+ size_t ncand = 0;
1675
+ if (part == 0) {
1676
+ if (!nkey) continue;
1677
+ cand = nkey->list;
1678
+ ncand = nkey->n;
1679
+ } else if (part == 1) {
1680
+ cand = bucket->other;
1681
+ ncand = bucket->n_other;
1682
+ } else {
1683
+ /* #866: literal @attr='value' candidates — probe the value
1684
+ * index with each attribute of this element. */
1685
+ if (!bucket->pkeys) continue;
1686
+ size_t ai = (size_t)(part - 2);
1687
+ LeptrisAttribute a = leptris_element_first_attribute(node);
1688
+ for (size_t j = 0; a && j < ai; j++) a = leptris_attribute_next(a);
1689
+ if (!a) continue;
1690
+ const char* an = leptris_attribute_get_name(a);
1691
+ const char* av = leptris_attribute_get_value(node, a);
1692
+ if (!an || !av) continue;
1693
+ const struct xslt_pkey* pk =
1694
+ xslt_bucket_pred_key(bucket,
1695
+ nkey ? nkey->name
1696
+ : leptris_element_get_name(node),
1697
+ an, av);
1698
+ if (!pk) continue;
1699
+ cand = pk->list;
1700
+ ncand = pk->n;
1701
+ }
1702
+ for (size_t bi = 0; bi < ncand; bi++) {
1703
+ XsltTemplate* t = cand[bi];
1704
+ if (t->dispatch_stamp == gen) continue;
1705
+ t->dispatch_stamp = gen;
1706
+ size_t order = t->order;
1707
+ if (t == cur) continue;
1708
+ /* ONE pass over the alternatives (see xslt_select_template). */
1709
+ double pri = 0; int have = 0;
1710
+ if (t->fast_name && node_is_elem) {
1711
+ const char* fn = t->fast_name;
1712
+ if (!(fn[0] == '*' && fn[1] == 0)) {
1713
+ const char* nn = leptris_element_get_name(node);
1714
+ if (!nn || strcmp(nn, fn) != 0) continue;
1715
+ const char* nu = leptris_element_get_namespace_uri(node);
1716
+ if (nu && nu[0]) continue;
1717
+ }
1718
+ pri = t->fast_pri;
1719
+ have = 1;
1720
+ } else
1721
+ for (const XsltPattern* pa = t->matches; pa; pa = pa->next) {
1722
+ if (!xslt_pattern_matches(pa, node, ex->source, t->ns))
1723
+ continue;
1724
+ if (!have || pa->priority > pri) { pri = pa->priority; have = 1; }
1725
+ }
1726
+ if (!have) continue;
1727
+ /* t must be strictly worse than cur. */
1728
+ int worse;
1729
+ if (t->import_rank != cur->import_rank)
1730
+ worse = t->import_rank > cur->import_rank;
1731
+ else if (pri != cur_pri)
1732
+ worse = pri < cur_pri;
1733
+ else worse = order < cur_order;
1734
+ if (!worse) continue;
1735
+ int wins = 0;
1736
+ if (!best) wins = 1;
1737
+ else if (t->import_rank != best->import_rank)
1738
+ wins = t->import_rank < best->import_rank;
1739
+ else if (pri != best_pri) wins = pri > best_pri;
1740
+ else wins = order >= best_order;
1741
+ if (wins) { best = t; best_pri = pri; best_order = order; }
1742
+ }
1743
+ }
1744
+ return best;
1745
+ }
1746
+
1747
+ static int op_next_match(XsltExec* ex, const XsltInstr* in,
1748
+ LeptrisElement node) {
1749
+ const XsltTemplate* t = xslt_select_next_match(
1750
+ ex, node, ex->current_template ? ex->current_template->mode
1751
+ : NULL);
1752
+ if (!t) {
1753
+ /* No lower rule: the built-in applies (§6.6). */
1754
+ return op_apply_templates(
1755
+ ex,
1756
+ &(XsltInstr){ .kind = XSLT_INSTR_APPLY_TEMPLATES,
1757
+ .name = ex->current_template
1758
+ ? ex->current_template->mode : NULL },
1759
+ node);
1760
+ }
1761
+ (void)in;
1762
+ return xslt_invoke_template(ex, t, node, NULL);
1763
+ }
1764
+
1765
+
1766
+ static int op_try(XsltExec* ex, const XsltInstr* in,
1767
+ LeptrisElement node) {
1768
+ XsltInstr* catch_at = NULL;
1769
+ XsltInstr** link = NULL;
1770
+ for (XsltInstr* c = in->child; c; c = c->next) {
1771
+ if (c->kind == XSLT_INSTR_CATCH) {
1772
+ catch_at = c;
1773
+ for (link = (XsltInstr**)&in->child;
1774
+ link && *link != catch_at; link = &(*link)->next) {}
1775
+ break;
1776
+ }
1777
+ }
1778
+ if (link) *link = NULL; /* body ends before the catch */
1779
+
1780
+ int saved_err = ex->eval_error;
1781
+ char saved_msg[sizeof(ex->error)];
1782
+ memcpy(saved_msg, ex->error, sizeof(saved_msg));
1783
+ ex->eval_error = 0;
1784
+
1785
+ int rc = xslt_exec_instrs(ex, in->child, node);
1786
+
1787
+ if (ex->eval_error) {
1788
+ char msg[sizeof(ex->error)];
1789
+ memcpy(msg, ex->error, sizeof(msg));
1790
+ if (catch_at) {
1791
+ ex->eval_error = 0;
1792
+ ex->error[0] = '\0';
1793
+ XsltVar* scope = ex->vars;
1794
+ struct leptris_xpath_result* dv =
1795
+ xpath_result_new(XPATH_RESULT_STRING);
1796
+ if (dv) {
1797
+ dv->value.string_value = leptris_strdup(msg);
1798
+ xslt_push_var(ex, "err:description", dv);
1799
+ }
1800
+ rc = xslt_exec_instrs(ex, catch_at->child, node);
1801
+ xslt_pop_vars_to(ex, scope);
1802
+ }
1803
+ } else {
1804
+ ex->eval_error = saved_err;
1805
+ memcpy(ex->error, saved_msg, sizeof(saved_msg));
1806
+ }
1807
+
1808
+ if (link) *link = catch_at;
1809
+ return rc;
1810
+ }
1811
+
1812
+ /* §10 stable multi-key sort — caches each (item,sort-key) string,
1813
+ * compares by walking all sort keys in order (single comparator). */
1814
+ static void xslt_sort_items(XsltExec* ex, const XsltInstr* in,
1815
+ LeptrisElement* items, size_t n) {
1816
+ if (n < 2 || !in->sorts) return;
1817
+ size_t nsorts = 0;
1818
+ for (const XsltSort* s = in->sorts; s; s = s->next) nsorts++;
1819
+ char** keys = (char**)calloc(nsorts * n, sizeof(char*));
1820
+ for (size_t i = 0; i < n; i++) {
1821
+ const XsltSort* s = in->sorts;
1822
+ for (size_t k = 0; k < nsorts && s; k++, s = s->next) {
1823
+ char* kp = NULL;
1824
+ if (s->select) {
1825
+ struct leptris_xpath_result* r =
1826
+ xslt_eval(ex, s->select, items[i]);
1827
+ if (r) {
1828
+ kp = leptris_xpath_result_string(r);
1829
+ leptris_xpath_result_free(r);
1830
+ }
1831
+ } else {
1832
+ /* Synthetic sequence items carry no deep value —
1833
+ * their text IS the sort key (perform-sort on
1834
+ * atomic sequences). */
1835
+ extern char* get_node_text(void* n);
1836
+ kp = get_node_text(items[i]);
1837
+ if (!kp) kp = string_value_deep(items[i]);
1838
+ }
1839
+ keys[k * n + i] = kp;
1840
+ }
1841
+ }
1842
+ for (size_t i = 1; i < n; i++) {
1843
+ for (size_t j = i; j > 0; j--) {
1844
+ int cmp = 0;
1845
+ for (size_t k = 0; k < nsorts && !cmp; k++) {
1846
+ const char* a = keys[k * n + (j-1)];
1847
+ const char* b = keys[k * n + j];
1848
+ const XsltSort* s = in->sorts;
1849
+ for (size_t ki = 0; ki < k; ki++) s = s->next;
1850
+ const char* a0 = a ? a : "";
1851
+ const char* b0 = b ? b : "";
1852
+ if (s->numeric) {
1853
+ char *ea = NULL, *eb = NULL;
1854
+ double av = a0[0] ? strtod(a0, &ea) : (NAN);
1855
+ if (a0[0] && ea == a0) av = NAN;
1856
+ double bv = b0[0] ? strtod(b0, &eb) : (NAN);
1857
+ if (b0[0] && eb == b0) bv = NAN;
1858
+ int an = (av != av), bn = (bv != bv);
1859
+ if (an && bn) cmp = 0;
1860
+ else if (an) cmp = -1;
1861
+ else if (bn) cmp = 1;
1862
+ else cmp = (av < bv) ? -1 : (av > bv) ? 1 : 0;
1863
+ } else {
1864
+ cmp = (xslt_ci_eq(a0, b0) && !s->case_upper_first)
1865
+ ? -strcmp(a0, b0) : strcmp(a0, b0);
1866
+ }
1867
+ if (s->descending) cmp = -cmp;
1868
+ }
1869
+ if (cmp <= 0) break;
1870
+ LeptrisElement te = items[j-1]; items[j-1] = items[j]; items[j] = te;
1871
+ for (size_t k = 0; k < nsorts; k++) {
1872
+ char* tk = keys[k * n + (j-1)];
1873
+ keys[k * n + (j-1)] = keys[k * n + j];
1874
+ keys[k * n + j] = tk;
1875
+ }
1876
+ }
1877
+ }
1878
+ for (size_t i = 0; i < nsorts * n; i++) free(keys[i]);
1879
+ free(keys);
1880
+ }
1881
+
1882
+ static int op_for_each(XsltExec* ex, const XsltInstr* in,
1883
+ LeptrisElement node) {
1884
+ struct leptris_xpath_result* r = xslt_eval(ex, in->select, node);
1885
+ if (!r) return 0;
1886
+ size_t n = leptris_xpath_result_count(r);
1887
+ /* Collect the element handles first: sort swaps them, and the
1888
+ * result may be freed mid-iteration otherwise. */
1889
+ LeptrisElement* items = (n > 0)
1890
+ ? (LeptrisElement*)calloc(n, sizeof(LeptrisElement)) : NULL;
1891
+ if (items) {
1892
+ /* Node-typed: for-each bodies see text/comment/PI/namespace
1893
+ * nodes (the element-typed accessor nulls them). */
1894
+ for (size_t i = 0; i < n; i++) {
1895
+ items[i] = (LeptrisElement)leptris_xpath_result_get_node(r, i);
1896
+ }
1897
+ }
1898
+ /* r stays alive across the loop: synthetic namespace/attribute
1899
+ * result nodes are RESULT-OWNED — freeing early dangles them. */
1900
+ if (!items) { leptris_xpath_result_free(r); return n ? -1 : 0; }
1901
+
1902
+ if (in->sorts) xslt_sort_items(ex, in, items, n);
1903
+ int rc = 0;
1904
+ size_t saved_pos = ex->current_pos;
1905
+ size_t saved_size = ex->current_size;
1906
+ ex->current_size = n;
1907
+ for (size_t i = 0; i < n && rc == 0; i++) {
1908
+ ex->current_pos = i + 1;
1909
+ rc = xslt_exec_instrs(ex, in->child, items[i]);
1910
+ }
1911
+ ex->current_pos = saved_pos;
1912
+ ex->current_size = saved_size;
1913
+ free(items);
1914
+ leptris_xpath_result_free(r);
1915
+ return rc;
1916
+ }
1917
+
1918
+ /* xsl:iterate (3.0 §12.5): params chain free helper. */
1919
+ static struct leptris_xpath_result* xslt_capture_content(
1920
+ XsltExec* ex, const XsltInstr* child, LeptrisElement node);
1921
+
1922
+ static void iter_params_free(XsltVar* p) {
1923
+ while (p) {
1924
+ XsltVar* prev = p->prev;
1925
+ if (p->value) leptris_xpath_result_free(p->value);
1926
+ free(p);
1927
+ p = prev;
1928
+ }
1929
+ }
1930
+
1931
+ /* Per-iteration param binding: a clone whose nodeset BORROWS the
1932
+ * source's node pointers (the initial values outlive every pass —
1933
+ * they are freed only after the loop ends). */
1934
+ static struct leptris_xpath_result* result_clone_borrowed(
1935
+ const struct leptris_xpath_result* src) {
1936
+ if (!src) return NULL;
1937
+ struct leptris_xpath_result* out =
1938
+ xpath_result_new((XPathResultType)src->type);
1939
+ if (!out) return NULL;
1940
+ switch (src->type) {
1941
+ case XPATH_RESULT_STRING:
1942
+ out->value.string_value =
1943
+ leptris_strdup(src->value.string_value
1944
+ ? src->value.string_value : "");
1945
+ break;
1946
+ case XPATH_RESULT_NUMBER:
1947
+ out->value.number_value = src->value.number_value;
1948
+ break;
1949
+ case XPATH_RESULT_BOOLEAN:
1950
+ out->value.boolean_value = src->value.boolean_value;
1951
+ break;
1952
+ case XPATH_RESULT_NODESET: {
1953
+ /* Deep copy (#1066): an OWNING nodeset's synthetic text
1954
+ * members must not stay aliased — the source (an
1955
+ * xsl:iterate param) is freed on the next-iteration
1956
+ * frame rebuild while the pushed binding lives on, and
1957
+ * the variable-lookup deep-copy guard keys on
1958
+ * owns_synthetic_text (a borrowed clone clears it, so
1959
+ * accumulated sequence items dangled -> empty strings).
1960
+ * Document nodes are still borrowed; owned synthetics
1961
+ * are copied. */
1962
+ out->value.nodeset_value =
1963
+ xpath_nodeset_deep_copy(src->value.nodeset_value);
1964
+ break;
1965
+ }
1966
+ default: break;
1967
+ }
1968
+ return out;
1969
+ }
1970
+
1971
+ static int op_iterate(XsltExec* ex, const XsltInstr* in,
1972
+ LeptrisElement node) {
1973
+ struct leptris_xpath_result* r = xslt_eval(ex, in->select, node);
1974
+ if (!r) return 0;
1975
+ size_t n = leptris_xpath_result_count(r);
1976
+ LeptrisElement* items = (n > 0)
1977
+ ? (LeptrisElement*)calloc(n, sizeof(LeptrisElement)) : NULL;
1978
+ if (items) {
1979
+ for (size_t i = 0; i < n; i++)
1980
+ items[i] = (LeptrisElement)leptris_xpath_result_get_node(r, i);
1981
+ }
1982
+ if (!items) { leptris_xpath_result_free(r); return n ? -1 : 0; }
1983
+
1984
+ /* Initial param values evaluate ONCE, in the caller's scope
1985
+ * (§12.5: outside the iteration). */
1986
+ XsltVar* params = NULL;
1987
+ for (const XsltInstr* c = in->child; c; c = c->next) {
1988
+ if (c->kind != XSLT_INSTR_VARIABLE || !c->is_param) break;
1989
+ struct leptris_xpath_result* v = NULL;
1990
+ if (c->select) v = xslt_eval(ex, c->select, node);
1991
+ else if (c->child) v = xslt_capture_content(ex, c->child, node);
1992
+ XsltVar* pv = (XsltVar*)calloc(1, sizeof(*pv));
1993
+ if (!pv) { if (v) leptris_xpath_result_free(v); break; }
1994
+ pv->name = c->name;
1995
+ pv->value = v;
1996
+ pv->prev = params;
1997
+ params = pv;
1998
+ }
1999
+
2000
+ int rc = 0;
2001
+ size_t saved_pos = ex->current_pos;
2002
+ size_t saved_size = ex->current_size;
2003
+ ex->current_size = n;
2004
+ ex->iterate_depth++;
2005
+ for (size_t i = 0; i < n; i++) {
2006
+ ex->current_pos = i + 1;
2007
+ XsltVar* scope_mark = ex->vars;
2008
+ size_t nparams = 0;
2009
+ for (XsltVar* pv = params; pv; pv = pv->prev) {
2010
+ xslt_push_var(ex, pv->name, result_clone_borrowed(pv->value));
2011
+ nparams++;
2012
+ }
2013
+ ex->iterate_signal = 0;
2014
+ rc = xslt_exec_instrs(ex, in->child, items[i]);
2015
+ int sig = ex->iterate_signal;
2016
+ ex->iterate_signal = 0;
2017
+
2018
+ if (sig == 1) {
2019
+ /* Merge the with-param rebindings over the current
2020
+ * values; names not supplied keep their value. */
2021
+ XsltVar* np = ex->iter_params;
2022
+ while (np) {
2023
+ XsltVar* nx = np->prev;
2024
+ XsltVar* found = NULL;
2025
+ for (XsltVar* pv = params; pv && !found; pv = pv->prev)
2026
+ if (strcmp(pv->name, np->name) == 0) found = pv;
2027
+ if (found) {
2028
+ if (found->value)
2029
+ leptris_xpath_result_free(found->value);
2030
+ found->value = np->value;
2031
+ free(np);
2032
+ } else {
2033
+ np->prev = params;
2034
+ params = np;
2035
+ }
2036
+ np = nx;
2037
+ }
2038
+ ex->iter_params = NULL;
2039
+ }
2040
+ xslt_pop_vars_to(ex, scope_mark);
2041
+ if (nparams && ex->vars == scope_mark) { /* balanced */ }
2042
+ if (sig == 2) break;
2043
+ if (rc) break;
2044
+ }
2045
+ /* 3.0 §12.5: on-completion runs when the loop ENDED without
2046
+ * xsl:break (sig != 2 on the final pass), with the FINAL
2047
+ * iteration's parameter values in scope (#729). Its instruction
2048
+ * is skipped during the per-item walk (no registered op). */
2049
+ if (ex->iterate_signal != 2) {
2050
+ for (const XsltInstr* c = in->child; c; c = c->next) {
2051
+ if (c->kind != XSLT_INSTR_ON_COMPLETION) continue;
2052
+ XsltVar* oc_mark = ex->vars;
2053
+ for (XsltVar* pv = params; pv; pv = pv->prev)
2054
+ xslt_push_var(ex, pv->name,
2055
+ result_clone_borrowed(pv->value));
2056
+ rc = xslt_exec_instrs(ex, c->child, node);
2057
+ xslt_pop_vars_to(ex, oc_mark);
2058
+ break;
2059
+ }
2060
+ }
2061
+ ex->iterate_depth--;
2062
+ ex->iterate_signal = 0;
2063
+ iter_params_free(ex->iter_params);
2064
+ ex->iter_params = NULL;
2065
+ iter_params_free(params);
2066
+ ex->current_pos = saved_pos;
2067
+ ex->current_size = saved_size;
2068
+ free(items);
2069
+ leptris_xpath_result_free(r);
2070
+ return rc;
2071
+ }
2072
+
2073
+ static int op_next_iteration(XsltExec* ex, const XsltInstr* in,
2074
+ LeptrisElement node) {
2075
+ if (ex->iterate_depth <= 0) return 0; /* no enclosing iterate */
2076
+ iter_params_free(ex->iter_params);
2077
+ ex->iter_params = NULL;
2078
+ for (const XsltInstr* c = in->child; c; c = c->next) {
2079
+ if (c->kind != XSLT_INSTR_WITH_PARAM || !c->name) continue;
2080
+ struct leptris_xpath_result* v = NULL;
2081
+ if (c->select) v = xslt_eval(ex, c->select, node);
2082
+ else if (c->child) v = xslt_capture_content(ex, c->child, node);
2083
+ XsltVar* pv = (XsltVar*)calloc(1, sizeof(*pv));
2084
+ if (!pv) { if (v) leptris_xpath_result_free(v); continue; }
2085
+ pv->name = c->name;
2086
+ pv->value = v;
2087
+ pv->prev = ex->iter_params;
2088
+ ex->iter_params = pv;
2089
+ }
2090
+ ex->iterate_signal = 1;
2091
+ return 0;
2092
+ }
2093
+
2094
+ static int op_break(XsltExec* ex, const XsltInstr* in,
2095
+ LeptrisElement node) {
2096
+ if (ex->iterate_depth <= 0) return 0;
2097
+ if (in->child) xslt_exec_instrs(ex, in->child, node);
2098
+ ex->iterate_signal = 2;
2099
+ return 0;
2100
+ }
2101
+
2102
+ /* xsl:merge (3.0 §14.3): full outer join of every merge-source on
2103
+ * the composite merge-key. v1: @select sources (for-each-source is
2104
+ * TODO), string keys, and the FIRST key's @order governs the whole
2105
+ * composite. Sources' select results stay alive for the whole merge
2106
+ * (the entry list borrows their nodes). */
2107
+ typedef struct xslt_merge_entry {
2108
+ char* key; /* owned composite key */
2109
+ LeptrisNodeRef node; /* borrowed from the source result */
2110
+ size_t src; /* source index */
2111
+ size_t ord; /* selection order (stable tiebreak) */
2112
+ } XsltMergeEntry;
2113
+
2114
+ /* Merge sort direction flag for qsort (no context arg on MSVC). */
2115
+ #if defined(_MSC_VER)
2116
+ # define LEPTRIS_TLS __declspec(thread)
2117
+ #else
2118
+ # define LEPTRIS_TLS __thread
2119
+ #endif
2120
+ static LEPTRIS_TLS int g_merge_desc;
2121
+
2122
+ static int merge_entry_cmp(const void* a, const void* b) {
2123
+ const XsltMergeEntry* x = (const XsltMergeEntry*)a;
2124
+ const XsltMergeEntry* y = (const XsltMergeEntry*)b;
2125
+ int c = strcmp(x->key, y->key);
2126
+ if (g_merge_desc) c = -c;
2127
+ if (c == 0) c = (x->ord > y->ord) - (x->ord < y->ord);
2128
+ return c;
2129
+ }
2130
+
2131
+ static int op_merge(XsltExec* ex, const XsltInstr* in,
2132
+ LeptrisElement node) {
2133
+ const XsltInstr* action = NULL;
2134
+ const XsltInstr** srcs = NULL;
2135
+ struct leptris_xpath_result** sres = NULL;
2136
+ XsltMergeEntry* ents = NULL;
2137
+ XsltMergeSide* sides = NULL;
2138
+ size_t n_src = 0, n_ents = 0, ent_cap = 0;
2139
+ int rc = 0;
2140
+
2141
+ for (const XsltInstr* c = in->child; c; c = c->next) {
2142
+ if (c->kind == XSLT_INSTR_MERGE_SOURCE) n_src++;
2143
+ else if (c->kind == XSLT_INSTR_MERGE_ACTION) action = c;
2144
+ }
2145
+ if (!action || !n_src) return 0;
2146
+ srcs = (const XsltInstr**)calloc(n_src, sizeof(*srcs));
2147
+ sres = (struct leptris_xpath_result**)
2148
+ calloc(n_src, sizeof(*sres));
2149
+ if (!srcs || !sres) { free(srcs); free(sres); return 0; }
2150
+ size_t si = 0;
2151
+ for (const XsltInstr* c = in->child; c; c = c->next)
2152
+ if (c->kind == XSLT_INSTR_MERGE_SOURCE) srcs[si++] = c;
2153
+
2154
+ g_merge_desc = 0;
2155
+ size_t ord = 0;
2156
+ for (si = 0; si < n_src; si++) {
2157
+ const XsltInstr* s = srcs[si];
2158
+ if (!s->select) continue;
2159
+ struct leptris_xpath_result* r = xslt_eval(ex, s->select, node);
2160
+ if (!r) continue;
2161
+ sres[si] = r; /* stays alive: entries borrow its nodes */
2162
+ size_t cnt = leptris_xpath_result_count(r);
2163
+ for (size_t i = 0; i < cnt; i++) {
2164
+ LeptrisNodeRef nd = leptris_xpath_result_get_node(r, i);
2165
+ if (!nd) continue;
2166
+ /* Composite key: every merge-key child's string value,
2167
+ * '\x01'-joined (not in normal text, unlike '|'). Keys
2168
+ * live INSIDE the merge-source (REC grammar) or as direct
2169
+ * children of xsl:merge (accepted by Saxon-HE — #731:
2170
+ * sources without their own keys fell through with an
2171
+ * empty composite, collapsing every group). */
2172
+ const XsltInstr* skeys = NULL;
2173
+ for (const XsltInstr* k = s->child; k; k = k->next)
2174
+ if (k->kind == XSLT_INSTR_MERGE_KEY) { skeys = s->child; break; }
2175
+ if (!skeys) skeys = in->child; /* merge-level shared keys */
2176
+ size_t klen = 0, kcap = 16;
2177
+ char* key = (char*)malloc(kcap);
2178
+ if (!key) continue;
2179
+ for (const XsltInstr* k = skeys; k; k = k->next) {
2180
+ if (k->kind != XSLT_INSTR_MERGE_KEY || !k->select)
2181
+ continue;
2182
+ struct leptris_xpath_result* kr =
2183
+ xslt_eval(ex, k->select, (LeptrisElement)nd);
2184
+ char* ks = kr ? leptris_xpath_result_string(kr) : NULL;
2185
+ if (kr) leptris_xpath_result_free(kr);
2186
+ size_t add = (ks ? strlen(ks) : 0) + 1;
2187
+ if (klen + add + 1 > kcap) {
2188
+ kcap = (klen + add + 1) * 2;
2189
+ char* nk = (char*)realloc(key, kcap);
2190
+ if (!nk) { free(key); free(ks); key = NULL; break; }
2191
+ key = nk;
2192
+ }
2193
+ if (klen) key[klen++] = '\x01';
2194
+ if (ks) { memcpy(key + klen, ks, strlen(ks));
2195
+ klen += strlen(ks); }
2196
+ free(ks);
2197
+ if (skeys == k && !g_merge_desc && k->num_start_at)
2198
+ g_merge_desc = 1;
2199
+ }
2200
+ if (!key) continue;
2201
+ key[klen] = '\0';
2202
+ if (n_ents == ent_cap) {
2203
+ ent_cap = ent_cap ? ent_cap * 2 : 16;
2204
+ XsltMergeEntry* ne =
2205
+ (XsltMergeEntry*)realloc(ents, ent_cap * sizeof(*ne));
2206
+ if (!ne) { free(key); continue; }
2207
+ ents = ne;
2208
+ }
2209
+ ents[n_ents].key = key;
2210
+ ents[n_ents].node = nd;
2211
+ ents[n_ents].src = si;
2212
+ ents[n_ents].ord = ord++;
2213
+ n_ents++;
2214
+ }
2215
+ }
2216
+
2217
+ qsort(ents, n_ents, sizeof(*ents), merge_entry_cmp);
2218
+
2219
+ sides = (XsltMergeSide*)calloc(n_src, sizeof(*sides));
2220
+ if (sides)
2221
+ for (si = 0; si < n_src; si++) sides[si].name = srcs[si]->name;
2222
+
2223
+ char* saved_key = ex->merge_key;
2224
+ XsltMergeSide* saved_sides = ex->merge_sides;
2225
+ size_t saved_count = ex->merge_side_count;
2226
+
2227
+ size_t i = 0;
2228
+ while (i < n_ents && !rc) {
2229
+ size_t j = i;
2230
+ while (j < n_ents && strcmp(ents[j].key, ents[i].key) == 0) j++;
2231
+ for (si = 0; si < n_src; si++) sides[si].n = 0;
2232
+ for (size_t k = i; k < j; k++) {
2233
+ XsltMergeSide* sd = &sides[ents[k].src];
2234
+ if (sd->n == sd->cap) {
2235
+ sd->cap = sd->cap ? sd->cap * 2 : 4;
2236
+ LeptrisNodeRef* ni = (LeptrisNodeRef*)
2237
+ realloc(sd->items, sd->cap * sizeof(*ni));
2238
+ if (!ni) { sd->cap /= 2; continue; }
2239
+ sd->items = ni;
2240
+ }
2241
+ sd->items[sd->n++] = ents[k].node;
2242
+ }
2243
+ ex->merge_key = ents[i].key;
2244
+ ex->merge_sides = sides;
2245
+ ex->merge_side_count = n_src;
2246
+ LeptrisElement ctx = NULL;
2247
+ for (si = 0; si < n_src && !ctx; si++)
2248
+ if (sides[si].n) ctx = (LeptrisElement)sides[si].items[0];
2249
+ rc = xslt_exec_instrs(ex, action->child, ctx ? ctx : node);
2250
+ i = j;
2251
+ }
2252
+
2253
+ ex->merge_key = saved_key;
2254
+ ex->merge_sides = saved_sides;
2255
+ ex->merge_side_count = saved_count;
2256
+
2257
+ if (sides)
2258
+ for (si = 0; si < n_src; si++) free(sides[si].items);
2259
+ free(sides);
2260
+ for (i = 0; i < n_ents; i++) free(ents[i].key);
2261
+ free(ents);
2262
+ for (si = 0; si < n_src; si++)
2263
+ if (sres[si]) leptris_xpath_result_free(sres[si]);
2264
+ free(sres);
2265
+ free(srcs);
2266
+ return rc;
2267
+ }
2268
+
2269
+ /* xsl:for-each-group (3.0 §14). Groups in first-appearance order;
2270
+ * each group owns its member array (borrowed pointers out of the
2271
+ * select's result, which stays alive for the whole loop). */
2272
+ typedef struct xslt_feg_group {
2273
+ char* key; /* owned; NULL for pattern groups */
2274
+ LeptrisElement* items;
2275
+ size_t n, cap;
2276
+ } XsltFegGroup;
2277
+
2278
+ static int feg_group_push(XsltFegGroup* g, LeptrisElement it) {
2279
+ if (g->n == g->cap) {
2280
+ size_t cap = g->cap ? g->cap * 2 : 4;
2281
+ LeptrisElement* grown =
2282
+ (LeptrisElement*)realloc(g->items, cap * sizeof(*grown));
2283
+ if (!grown) return -1;
2284
+ g->items = grown;
2285
+ g->cap = cap;
2286
+ }
2287
+ g->items[g->n++] = it;
2288
+ return 0;
2289
+ }
2290
+
2291
+ static int op_for_each_group(XsltExec* ex, const XsltInstr* in,
2292
+ LeptrisElement node) {
2293
+ if (!in->group_by && !in->group_starting && !in->group_ending)
2294
+ return 0;
2295
+ struct leptris_xpath_result* r = xslt_eval(ex, in->select, node);
2296
+ if (!r) return 0;
2297
+ size_t n = leptris_xpath_result_count(r);
2298
+ LeptrisElement* items = (n > 0)
2299
+ ? (LeptrisElement*)calloc(n, sizeof(LeptrisElement)) : NULL;
2300
+ if (items) {
2301
+ for (size_t i = 0; i < n; i++)
2302
+ items[i] = (LeptrisElement)leptris_xpath_result_get_node(r, i);
2303
+ }
2304
+ if (!items) { leptris_xpath_result_free(r); return n ? -1 : 0; }
2305
+
2306
+ XsltFegGroup* groups = (n > 0)
2307
+ ? (XsltFegGroup*)calloc(n, sizeof(XsltFegGroup)) : NULL;
2308
+ size_t ngroups = 0;
2309
+ int cur_group_closed = 0; /* group-ending-with state */
2310
+ int rc = 0;
2311
+ if (!groups) { rc = -1; goto done; }
2312
+
2313
+ for (size_t i = 0; i < n; i++) {
2314
+ XsltFegGroup* g = NULL;
2315
+ if (in->group_by) {
2316
+ char* key = NULL;
2317
+ struct leptris_xpath_result* kv =
2318
+ xslt_eval(ex, in->group_by, items[i]);
2319
+ if (kv) {
2320
+ key = leptris_xpath_result_string(kv);
2321
+ leptris_xpath_result_free(kv);
2322
+ }
2323
+ if (in->group_adjacent) {
2324
+ /* group-adjacent: only the LAST group can absorb the
2325
+ * item; an equal earlier key does not re-open. */
2326
+ if (ngroups) {
2327
+ const char* a =
2328
+ groups[ngroups - 1].key ? groups[ngroups - 1].key : "";
2329
+ const char* b = key ? key : "";
2330
+ if (strcmp(a, b) == 0) g = &groups[ngroups - 1];
2331
+ }
2332
+ } else {
2333
+ for (size_t j = 0; j < ngroups; j++) {
2334
+ const char* a = groups[j].key ? groups[j].key : "";
2335
+ const char* b = key ? key : "";
2336
+ if (strcmp(a, b) == 0) { g = &groups[j]; break; }
2337
+ }
2338
+ }
2339
+ if (!g) {
2340
+ g = &groups[ngroups++];
2341
+ g->key = key;
2342
+ } else {
2343
+ free(key);
2344
+ }
2345
+ } else if (in->group_ending) {
2346
+ /* group-ending-with: items accumulate into the open
2347
+ * group; a match CLOSES it (the next item opens a fresh
2348
+ * one). Trailing non-matches form the final group. */
2349
+ if (cur_group_closed || ngroups == 0)
2350
+ g = &groups[ngroups++];
2351
+ else
2352
+ g = &groups[ngroups - 1];
2353
+ cur_group_closed = 0;
2354
+ } else {
2355
+ /* group-starting-with: a match opens a new group; the
2356
+ * implicit first group collects leading non-matches. */
2357
+ if (ngroups == 0 || xslt_pattern_matches(
2358
+ in->group_starting, items[i], ex->source, in->ns))
2359
+ g = &groups[ngroups++];
2360
+ else
2361
+ g = &groups[ngroups - 1];
2362
+ }
2363
+ if (feg_group_push(g, items[i])) { rc = -1; break; }
2364
+ if (in->group_ending && xslt_pattern_matches(
2365
+ in->group_ending, items[i], ex->source, in->ns))
2366
+ cur_group_closed = 1;
2367
+ }
2368
+
2369
+ {
2370
+ size_t saved_pos = ex->current_pos;
2371
+ size_t saved_size = ex->current_size;
2372
+ XPathNodeSet* saved_group = ex->cur_group;
2373
+ char* saved_key = ex->cur_group_key;
2374
+ ex->current_size = ngroups;
2375
+ for (size_t gi = 0; gi < ngroups && rc == 0; gi++) {
2376
+ if (groups[gi].n == 0) continue;
2377
+ ex->cur_group = xpath_nodeset_new();
2378
+ if (!ex->cur_group) { rc = -1; break; }
2379
+ for (size_t m = 0; m < groups[gi].n; m++)
2380
+ xpath_nodeset_add(ex->cur_group, groups[gi].items[m]);
2381
+ ex->cur_group_key =
2382
+ groups[gi].key ? leptris_strdup(groups[gi].key) : NULL;
2383
+ ex->current_pos = gi + 1;
2384
+ rc = xslt_exec_instrs(ex, in->child, groups[gi].items[0]);
2385
+ xpath_nodeset_free(ex->cur_group);
2386
+ free(ex->cur_group_key);
2387
+ ex->cur_group = NULL;
2388
+ ex->cur_group_key = NULL;
2389
+ }
2390
+ ex->cur_group = saved_group;
2391
+ ex->cur_group_key = saved_key;
2392
+ ex->current_pos = saved_pos;
2393
+ ex->current_size = saved_size;
2394
+ }
2395
+
2396
+ done:
2397
+ if (groups) {
2398
+ for (size_t j = 0; j < ngroups; j++) {
2399
+ free(groups[j].key);
2400
+ free(groups[j].items);
2401
+ }
2402
+ free(groups);
2403
+ }
2404
+ free(items);
2405
+ leptris_xpath_result_free(r);
2406
+ return rc;
2407
+ }
2408
+
2409
+ static int op_if(XsltExec* ex, const XsltInstr* in, LeptrisElement node) {
2410
+ struct leptris_xpath_result* r = xslt_eval(ex, in->test, node);
2411
+ int truth = r ? leptris_xpath_result_boolean(r) : 0;
2412
+ if (r) leptris_xpath_result_free(r);
2413
+ if (!truth) return 0;
2414
+ return xslt_exec_instrs(ex, in->child, node);
2415
+ }
2416
+
2417
+ static int copy_node_deep(XsltExec* ex, LeptrisElement node,
2418
+ LeptrisElement parent);
2419
+
2420
+ static int op_copy_of(XsltExec* ex, const XsltInstr* in,
2421
+ LeptrisElement node) {
2422
+ struct leptris_xpath_result* r = xslt_eval(ex, in->select, node);
2423
+ if (!r) return 0;
2424
+ if (leptris_xpath_result_count(r) > 0) {
2425
+ size_t n = leptris_xpath_result_count(r);
2426
+ for (size_t i = 0; i < n; i++) {
2427
+ LeptrisNodeRef cn = leptris_xpath_result_get_node(r, i);
2428
+ if (cn && leptris_node_get_type(cn) ==
2429
+ LEPTRIS_NODE_TYPE_DOCUMENT) {
2430
+ /* An RTF fragment root: copy its children (the
2431
+ * top-level nodes of the fragment). */
2432
+ struct leptris_document* fd =
2433
+ ((LeptrisDocumentNode*)cn)->doc;
2434
+ for (LeptrisNodeRef c =
2435
+ (LeptrisNodeRef)(fd->new_dom_root
2436
+ ? fd->new_dom_root : fd->root);
2437
+ c; c = leptris_node_next_sibling(c)) {
2438
+ if (leptris_node_get_type(c) ==
2439
+ LEPTRIS_NODE_TYPE_ELEMENT)
2440
+ copy_node_deep(ex, (LeptrisElement)c,
2441
+ ex->pending_parent);
2442
+ }
2443
+ } else if (cn && leptris_node_get_type(cn) ==
2444
+ LEPTRIS_NODE_TYPE_ELEMENT) {
2445
+ copy_node_deep(ex, (LeptrisElement)cn, ex->pending_parent);
2446
+ } else if (cn) {
2447
+ int cty = leptris_node_get_type(cn);
2448
+ if (cty == LEPTRIS_NODE_TYPE_COMMENT) {
2449
+ LeptrisNodeRef cm = leptris_comment_node_create(
2450
+ ex->result,
2451
+ leptris_comment_node_get_content(cn));
2452
+ if (cm) {
2453
+ if (ex->pending_parent)
2454
+ leptris_element_append_child_internal(
2455
+ ex->pending_parent, (LeptrisNode*)cm);
2456
+ else
2457
+ xslt_append_fragment_node(ex, cm);
2458
+ }
2459
+ } else if (cty == LEPTRIS_NODE_TYPE_PI) {
2460
+ LeptrisNodeRef pi = leptris_pi_node_create(
2461
+ ex->result,
2462
+ leptris_pi_node_get_target(cn),
2463
+ leptris_pi_node_get_data(cn));
2464
+ if (pi) {
2465
+ if (ex->pending_parent)
2466
+ leptris_element_append_child_internal(
2467
+ ex->pending_parent, (LeptrisNode*)pi);
2468
+ else
2469
+ xslt_append_fragment_node(ex, pi);
2470
+ }
2471
+ } else if (cty == LEPTRIS_NODE_TYPE_CDATA) {
2472
+ const char* ccd =
2473
+ leptris_text_get_content((LeptrisTextNode*)cn);
2474
+ LeptrisNodeRef cc = (LeptrisNodeRef)leptris_cdata_create(
2475
+ ccd, ccd ? strlen(ccd) : 0,
2476
+ ((struct leptris_document*)ex->result)->pool);
2477
+ if (cc) {
2478
+ if (ex->pending_parent)
2479
+ leptris_element_append_child_internal(
2480
+ ex->pending_parent, (LeptrisNode*)cc);
2481
+ else
2482
+ xslt_append_fragment_node(ex, cc);
2483
+ }
2484
+ } else if (cty == LEPTRIS_NODE_TYPE_TEXT) {
2485
+ const char* tc =
2486
+ leptris_text_get_content((LeptrisTextNode*)cn);
2487
+ if (tc) out_append_text(ex, ex->pending_parent, tc);
2488
+ } else if (cty == LEPTRIS_NODE_ATTRIBUTE) {
2489
+ /* §11.3: copy-of an attribute node adds the
2490
+ * name/value onto the pending parent (bug-3-:
2491
+ * previously masked by the copy auto-adding
2492
+ * attributes). */
2493
+ LeptrisAttributeNode* an = (LeptrisAttributeNode*)cn;
2494
+ if (ex->pending_parent && an->name)
2495
+ leptris_element_set_attribute(
2496
+ ex->pending_parent, an->name,
2497
+ an->value ? an->value : "");
2498
+ } else if (cty == LEPTRIS_NODE_NAMESPACE) {
2499
+ /* §7.5/§12.1: copying a namespace node adds the
2500
+ * declaration onto the pending parent element
2501
+ * (libxslt bug-38- — the op dropped ns nodes).
2502
+ * libxslt's copy: prefixed bindings only — the
2503
+ * implicit xml namespace and duplicates of
2504
+ * already-bound prefixes are skipped (bug-54). */
2505
+ LeptrisNamespaceNode* nn = (LeptrisNamespaceNode*)cn;
2506
+ LeptrisElement pp = ex->pending_parent;
2507
+ if (pp && nn->prefix && nn->prefix[0] && nn->uri) {
2508
+ if (strcmp(nn->prefix, "xml") == 0 &&
2509
+ strcmp(nn->uri,
2510
+ "http://www.w3.org/XML/1998/namespace")
2511
+ == 0)
2512
+ continue;
2513
+ const char* cur =
2514
+ leptris_element_namespace_for_prefix(
2515
+ pp, nn->prefix);
2516
+ if (cur && strcmp(cur, nn->uri) == 0) continue;
2517
+ leptris_element_add_namespace_definition(
2518
+ pp, nn->prefix, nn->uri);
2519
+ }
2520
+ }
2521
+ }
2522
+ }
2523
+ } else {
2524
+ char* sv = leptris_xpath_result_string(r);
2525
+ if (sv) { out_append_text(ex, ex->pending_parent, sv); free(sv); }
2526
+ }
2527
+ leptris_xpath_result_free(r);
2528
+ return 0;
2529
+ }
2530
+
2531
+ static int op_copy(XsltExec* ex, const XsltInstr* in, LeptrisElement node) {
2532
+ /* 3.0 §9.9.2: with @select the sequence constructor is ignored
2533
+ * and each selected item is copied — the same per-item rules as
2534
+ * copy-of (Saxon-HE 12.7 verified: attribute items rebind on
2535
+ * the pending parent, element items deep-copy). */
2536
+ if (in->select) return op_copy_of(ex, in, node);
2537
+ /* §7.5: copying an ATTRIBUTE (re)binds it on the pending
2538
+ * parent — later copies override earlier xsl:attribute values
2539
+ * (execution order wins, §7.1.3). */
2540
+ if (node && ((LeptrisNode*)node)->type == LEPTRIS_NODE_ATTRIBUTE) {
2541
+ LeptrisAttributeNode* a = (LeptrisAttributeNode*)node;
2542
+ if (ex->pending_parent && a->name)
2543
+ leptris_element_set_attribute(ex->pending_parent,
2544
+ a->name,
2545
+ a->value ? a->value : "");
2546
+ return 0;
2547
+ }
2548
+ /* §7.5: copy of a NAMESPACE node declares it on the pending
2549
+ * parent (the classic copy-the-namespaces idiom). */
2550
+ if (node && ((LeptrisNode*)node)->type == LEPTRIS_NODE_NAMESPACE) {
2551
+ LeptrisNamespaceNode* ns = (LeptrisNamespaceNode*)node;
2552
+ /* The implicit xml prefix is always in scope — copying it
2553
+ * would emit a redundant xmlns:xml (libxslt omits it). */
2554
+ if (ex->pending_parent && ns->uri && ns->prefix &&
2555
+ strcmp(ns->prefix, "xml") == 0)
2556
+ return 0;
2557
+ if (ex->pending_parent && ns->uri)
2558
+ leptris_element_add_namespace_definition(
2559
+ ex->pending_parent,
2560
+ ns->prefix ? ns->prefix : "", ns->uri);
2561
+ return 0;
2562
+ }
2563
+ /* §7.5: copy of a comment/PI node copies the node itself. */
2564
+ {
2565
+ int nty = leptris_node_get_type((LeptrisNodeRef)node);
2566
+ if (nty == LEPTRIS_NODE_TYPE_COMMENT) {
2567
+ LeptrisNodeRef cm = leptris_comment_node_create(
2568
+ ex->result, leptris_comment_node_get_content(
2569
+ (LeptrisNodeRef)node));
2570
+ if (cm && ex->pending_parent)
2571
+ leptris_element_append_child_internal(
2572
+ ex->pending_parent, (LeptrisNode*)cm);
2573
+ else if (cm)
2574
+ xslt_append_fragment_node(ex, cm);
2575
+ return 0;
2576
+ }
2577
+ if (nty == LEPTRIS_NODE_TYPE_PI) {
2578
+ LeptrisNodeRef pi = leptris_pi_node_create(
2579
+ ex->result,
2580
+ leptris_pi_node_get_target((LeptrisNodeRef)node),
2581
+ leptris_pi_node_get_data((LeptrisNodeRef)node));
2582
+ if (pi && ex->pending_parent)
2583
+ leptris_element_append_child_internal(
2584
+ ex->pending_parent, (LeptrisNode*)pi);
2585
+ else if (pi)
2586
+ xslt_append_fragment_node(ex, pi);
2587
+ return 0;
2588
+ }
2589
+ if (nty == LEPTRIS_NODE_TYPE_CDATA) {
2590
+ /* A copied CDATA section stays CDATA (§7.5). */
2591
+ const char* cc = leptris_text_node_get_content(
2592
+ (LeptrisNodeRef)node);
2593
+ LeptrisNodeRef cn = (LeptrisNodeRef)leptris_cdata_create(
2594
+ cc, cc ? strlen(cc) : 0,
2595
+ ((struct leptris_document*)ex->result)->pool);
2596
+ if (cn && ex->pending_parent)
2597
+ leptris_element_append_child_internal(
2598
+ ex->pending_parent, (LeptrisNode*)cn);
2599
+ else if (cn)
2600
+ xslt_append_fragment_node(ex, cn);
2601
+ return 0;
2602
+ }
2603
+ if (nty == LEPTRIS_NODE_TYPE_TEXT) {
2604
+ out_append_text(ex, ex->pending_parent,
2605
+ leptris_text_node_get_content(
2606
+ (LeptrisNodeRef)node));
2607
+ return 0;
2608
+ }
2609
+ }
2610
+ if (!leptris_element_get_name(node)) return 0;
2611
+ LeptrisElement e = out_copy_elem(ex, ex->pending_parent, node);
2612
+ if (!e) return -1;
2613
+ /* §7.5: copying an element copies its namespace nodes too —
2614
+ * the in-scope declarations travel with the copy (bug-122/124:
2615
+ * xmlns:* and default declarations on identity copies). */
2616
+ {
2617
+ /* §7.5: in-scope namespaces (innermost binding per prefix). */
2618
+ char seen_pfx[32][96];
2619
+ size_t seen = 0;
2620
+ for (LeptrisElement anc = node; anc && seen < 32;
2621
+ anc = leptris_node_parent((LeptrisNodeRef)anc)) {
2622
+ for (struct leptris_namespace* ns =
2623
+ leptris_elem_namespaces(anc);
2624
+ ns; ns = ns->next) {
2625
+ const char* pf = ns->prefix ? ns->prefix : "";
2626
+ int dup = 0;
2627
+ for (size_t k = 0; k < seen; k++)
2628
+ if (strcmp(seen_pfx[k], pf) == 0) { dup = 1; break; }
2629
+ if (dup) continue;
2630
+ if (seen < 32)
2631
+ snprintf(seen_pfx[seen++], 96, "%s", pf);
2632
+ if (ns->uri &&
2633
+ !result_ns_in_scope(e, pf, ns->uri))
2634
+ leptris_element_add_namespace_definition(e, pf, ns->uri);
2635
+ }
2636
+ }
2637
+ }
2638
+ /* §7.5: xsl:copy copies the element and its namespace nodes,
2639
+ * NOT its attributes — they reach the result only through
2640
+ * apply-templates/@* (libxslt bug-32-: match="@p:*" drop
2641
+ * templates never fired because the copy re-added them). */
2642
+ xslt_apply_attr_sets(ex, in, e, node);
2643
+ LeptrisElement saved = ex->pending_parent;
2644
+ ex->pending_parent = e;
2645
+ int rc = xslt_exec_instrs(ex, in->child, node);
2646
+ ex->pending_parent = saved;
2647
+ return rc;
2648
+ }
2649
+
2650
+ static int copy_node_deep(XsltExec* ex, LeptrisElement node,
2651
+ LeptrisElement parent) {
2652
+ const char* name = leptris_element_get_name(node);
2653
+ if (!name) return -1;
2654
+ LeptrisElement e = out_copy_elem(ex, parent, node);
2655
+ if (!e) return -1;
2656
+ /* Namespace fidelity (§7.5 + Names Rec): copy the element's
2657
+ * in-scope DECLARATIONS verbatim — a copy of <foo xmlns="u">
2658
+ * keeps xmlns="u" — and when the copy lands under a parent with
2659
+ * a default namespace the element does not have, emit xmlns=""
2660
+ * so it stays no-namespace. */
2661
+ {
2662
+ int copied_default = 0;
2663
+ /* §7.5: the copy carries the IN-SCOPE namespaces (ancestor
2664
+ * declarations, innermost binding per prefix wins). */
2665
+ char seen_pfx[32][96];
2666
+ size_t seen = 0;
2667
+ for (LeptrisElement anc = node; anc && seen < 32;
2668
+ anc = leptris_node_parent((LeptrisNodeRef)anc)) {
2669
+ for (struct leptris_namespace* ns =
2670
+ leptris_elem_namespaces(anc);
2671
+ ns; ns = ns->next) {
2672
+ const char* pf = ns->prefix ? ns->prefix : "";
2673
+ int dup = 0;
2674
+ for (size_t k = 0; k < seen; k++)
2675
+ if (strcmp(seen_pfx[k], pf) == 0) { dup = 1; break; }
2676
+ if (dup) continue;
2677
+ if (seen < 32)
2678
+ snprintf(seen_pfx[seen++], 96, "%s", pf);
2679
+ if (ns->uri &&
2680
+ !result_ns_in_scope(e, pf, ns->uri))
2681
+ leptris_element_add_namespace_definition(
2682
+ e, pf, ns->uri);
2683
+ if (!ns->prefix) copied_default = 1;
2684
+ }
2685
+ }
2686
+ if (!copied_default && parent) {
2687
+ const char* pdef = leptris_element_namespace_for_prefix(
2688
+ parent, NULL); /* NULL = the default namespace */
2689
+ if (pdef && *pdef && !leptris_element_get_namespace_uri(node))
2690
+ leptris_element_add_namespace_definition(e, "", "");
2691
+ }
2692
+ }
2693
+ size_t na = leptris_element_attribute_count(node);
2694
+ for (size_t i = 0; i < na; i++) {
2695
+ const char* an = leptris_element_attribute_name_at(node, i);
2696
+ const char* av = leptris_element_attribute_value_at(node, i);
2697
+ if (an && av) leptris_element_set_attribute(e, an, av);
2698
+ }
2699
+ /* §11.3 verbatim deep copy: every child kind in document order —
2700
+ * text/CDATA/comment/PI/element — not the concatenated
2701
+ * string-value ahead of the child elements (that duplicated
2702
+ * mixed content and dropped the tail whitespace). */
2703
+ for (LeptrisNodeRef c = leptris_node_first_child(
2704
+ leptris_element_as_node(node));
2705
+ c; c = leptris_node_next_sibling(c)) {
2706
+ int ty = leptris_node_get_type(c);
2707
+ if (ty == LEPTRIS_NODE_TYPE_ELEMENT) {
2708
+ copy_node_deep(ex, (LeptrisElement)c, e);
2709
+ } else if (ty == LEPTRIS_NODE_TYPE_CDATA) {
2710
+ const char* t =
2711
+ leptris_text_get_content((LeptrisTextNode*)c);
2712
+ LeptrisNodeRef cc = (LeptrisNodeRef)leptris_cdata_create(
2713
+ t, t ? strlen(t) : 0,
2714
+ ((struct leptris_document*)ex->result)->pool);
2715
+ if (cc) leptris_element_append_child_internal(e, (LeptrisNode*)cc);
2716
+ } else if (ty == LEPTRIS_NODE_TYPE_COMMENT) {
2717
+ LeptrisNodeRef cm = leptris_comment_node_create(
2718
+ ex->result, leptris_comment_node_get_content(c));
2719
+ if (cm) leptris_element_append_child_internal(e, (LeptrisNode*)cm);
2720
+ } else if (ty == LEPTRIS_NODE_TYPE_PI) {
2721
+ LeptrisNodeRef pi = leptris_pi_node_create(
2722
+ ex->result, leptris_pi_node_get_target(c),
2723
+ leptris_pi_node_get_data(c));
2724
+ if (pi) leptris_element_append_child_internal(e, (LeptrisNode*)pi);
2725
+ } else if (ty == LEPTRIS_NODE_TYPE_TEXT) {
2726
+ const char* t = leptris_text_get_content((LeptrisTextNode*)c);
2727
+ if (t && t[0]) out_append_text(ex, e, t);
2728
+ }
2729
+ }
2730
+ return 0;
2731
+ }
2732
+
2733
+ static struct leptris_xpath_result* xslt_capture_content(
2734
+ XsltExec* ex, const XsltInstr* child, LeptrisElement node);
2735
+
2736
+ /* 3.0 §18 xsl:map: build the value-level map (shared representation
2737
+ * through the functions_ext31 builder) from xsl:map-entry children. */
2738
+ static struct leptris_xpath_result* eval_xsl_map(XsltExec* ex,
2739
+ const XsltInstr* mi,
2740
+ LeptrisElement node) {
2741
+ void* b = xpath_map_builder_new();
2742
+ if (!b) return NULL;
2743
+ for (const XsltInstr* c = mi->child; c; c = c->next) {
2744
+ if (c->kind != XSLT_INSTR_MAP_ENTRY) continue;
2745
+ char* k = NULL;
2746
+ if (c->test) {
2747
+ struct leptris_xpath_result* kr =
2748
+ xslt_eval(ex, c->test, node);
2749
+ if (kr) {
2750
+ k = leptris_xpath_result_string(kr);
2751
+ leptris_xpath_result_free(kr);
2752
+ }
2753
+ }
2754
+ char* v = NULL;
2755
+ if (c->select) {
2756
+ struct leptris_xpath_result* vr =
2757
+ xslt_eval(ex, c->select, node);
2758
+ if (vr) {
2759
+ v = leptris_xpath_result_string(vr);
2760
+ leptris_xpath_result_free(vr);
2761
+ }
2762
+ } else if (c->child) {
2763
+ v = xslt_capture_children_text(ex, c->child, node);
2764
+ }
2765
+ if (k) xpath_map_builder_add(b, k, v ? v : "");
2766
+ free(k);
2767
+ free(v);
2768
+ }
2769
+ return xpath_map_builder_finish(b);
2770
+ }
2771
+
2772
+ static int op_variable(XsltExec* ex, const XsltInstr* in,
2773
+ LeptrisElement node) {
2774
+ if (!in->name) return 0;
2775
+ struct leptris_xpath_result* v = NULL;
2776
+ if (in->select) {
2777
+ v = xslt_eval(ex, in->select, node);
2778
+ } else if (in->child && in->child->kind == XSLT_INSTR_MAP &&
2779
+ !in->child->next) {
2780
+ /* §18: a variable whose content is a lone xsl:map binds the
2781
+ * map VALUE (the Saxon as="map(*)" shape). */
2782
+ v = eval_xsl_map(ex, in->child, node);
2783
+ } else if (in->child) {
2784
+ v = xslt_capture_content(ex, in->child, node);
2785
+ }
2786
+ xslt_push_var(ex, in->name, v);
2787
+ return 0;
2788
+ }
2789
+
2790
+ /* §11.1 RTF capture: build a with-param/variable CONTENT subtree
2791
+ * into a FRESH scratch document — never into the result tree, which
2792
+ * may carry a partially built element the instruction sits inside.
2793
+ * Returns the fragment as a nodeset (its document node) or, for
2794
+ * pure-text fragments, a string. */
2795
+ static struct leptris_xpath_result* xslt_capture_content(
2796
+ XsltExec* ex, const XsltInstr* child, LeptrisElement node) {
2797
+ struct leptris_xpath_result* v = NULL;
2798
+ LeptrisDocument main_result = ex->result;
2799
+ LeptrisElement saved = ex->pending_parent;
2800
+ ex->result = leptris_document_create();
2801
+ ex->pending_parent = NULL;
2802
+ /* Fresh buffer per capture (the xslt_capture_children_text
2803
+ * discipline): nested captures save/restore the outer length —
2804
+ * resetting only the length left stale bytes that later appends
2805
+ * resurrected (bug-72's second variable picked up the first's
2806
+ * fragment text). */
2807
+ size_t o_len = ex->rtf_text_len;
2808
+ char* o_buf = ex->rtf_text;
2809
+ size_t o_cap = ex->rtf_text_cap;
2810
+ int o_capt = ex->rtf_capturing;
2811
+ ex->rtf_capturing = 1;
2812
+ ex->rtf_text = (char*)calloc(1, 1);
2813
+ ex->rtf_text_len = 0;
2814
+ ex->rtf_text_cap = 1;
2815
+ xslt_exec_instrs(ex, child, node);
2816
+ ex->rtf_capturing = 0;
2817
+ ex->pending_parent = saved;
2818
+ char* frag_text = ex->rtf_text; /* owned by this block */
2819
+ size_t frag_len = ex->rtf_text_len;
2820
+ ex->rtf_text = o_buf;
2821
+ ex->rtf_text_len = o_len;
2822
+ ex->rtf_text_cap = o_cap;
2823
+ ex->rtf_capturing = o_capt;
2824
+ LeptrisDocument frag_doc = ex->result;
2825
+ ex->result = main_result;
2826
+ LeptrisElement rr = leptris_document_root(frag_doc);
2827
+ v = xpath_result_new(XPATH_RESULT_NODESET);
2828
+ if (v && rr) {
2829
+ v->value.nodeset_value = xpath_nodeset_new();
2830
+ if (v->value.nodeset_value) {
2831
+ /* §11.1: the value is the result tree FRAGMENT — bound
2832
+ * as its root (document) node. Relative paths
2833
+ * ($v/row/cell) and exsl:node-set() then see the
2834
+ * fragment as a tree. */
2835
+ LeptrisNodeRef dn = (LeptrisNodeRef)
2836
+ leptris_document_get_node(frag_doc);
2837
+ if (dn)
2838
+ xpath_nodeset_add(v->value.nodeset_value, dn);
2839
+ }
2840
+ } else if (v && !rr) {
2841
+ /* Pure-text RTF (bug-56): bind as the fragment's document
2842
+ * node — an EMPTY one too, which libxslt counts as 1 (the
2843
+ * node exists; its string-value is just ""). Non-empty
2844
+ * fragments get ONE text child spliced into the document's
2845
+ * chain so string($rtf) is the text. The earlier
2846
+ * string-binding regressed bug-72 via stale capture state;
2847
+ * the fresh-buffer capture discipline above is what makes
2848
+ * the nodeset binding safe now. */
2849
+ if (frag_text && frag_len) {
2850
+ LeptrisNodeRef tn =
2851
+ leptris_text_node_create(frag_doc, frag_text);
2852
+ if (tn) {
2853
+ struct leptris_document* fd =
2854
+ (struct leptris_document*)frag_doc;
2855
+ if (!fd->doc_children_head) {
2856
+ fd->doc_children_head = tn;
2857
+ fd->doc_children_tail = tn;
2858
+ } else {
2859
+ leptris_node_set_next_sibling(
2860
+ (LeptrisNodeRef)fd->doc_children_tail, tn);
2861
+ fd->doc_children_tail = tn;
2862
+ }
2863
+ }
2864
+ }
2865
+ /* Bind the document node — same shape as the element
2866
+ * fragment above. */
2867
+ v->value.nodeset_value = xpath_nodeset_new();
2868
+ if (v->value.nodeset_value) {
2869
+ LeptrisNodeRef dn = (LeptrisNodeRef)
2870
+ leptris_document_get_node(frag_doc);
2871
+ if (dn)
2872
+ xpath_nodeset_add(v->value.nodeset_value, dn);
2873
+ }
2874
+ }
2875
+ free(frag_text);
2876
+ /* The nodeset's node pointers live in the fragment document.
2877
+ * Move ownership into the exec's RTF chain so the nodes outlive
2878
+ * the variable's frame — for BOTH shapes: element-rooted
2879
+ * fragments and pure-text ones (their nodeset points at the
2880
+ * document node whose child is the text). */
2881
+ if (rr || (v && v->type == XPATH_RESULT_NODESET)) {
2882
+ struct xslt_rtf_entry* ent =
2883
+ (struct xslt_rtf_entry*)malloc(sizeof(*ent));
2884
+ if (ent) {
2885
+ ent->doc = frag_doc;
2886
+ ent->next = (struct xslt_rtf_entry*)ex->rtf_chain;
2887
+ ex->rtf_chain = ent;
2888
+ } else {
2889
+ leptris_document_free(frag_doc);
2890
+ }
2891
+ } else {
2892
+ leptris_document_free(frag_doc);
2893
+ }
2894
+ return v;
2895
+ }
2896
+
2897
+ static int xslt_invoke_template(XsltExec* ex, const XsltTemplate* t,
2898
+ LeptrisElement node,
2899
+ const XsltInstr* with_params);
2900
+
2901
+ static int op_call_template(XsltExec* ex, const XsltInstr* in,
2902
+ LeptrisElement node) {
2903
+ if (!in->name) return 0;
2904
+ /* Hash lookup (#682): the index keeps the LAST declaration per
2905
+ * name, the same §11.6 winner the linear scan selected. */
2906
+ const XsltTemplate* t = xslt_sheet_named(ex->sheet, in->name);
2907
+ if (!t) return 0;
2908
+ /* §11 scoping lives in xslt_invoke_template (shared with
2909
+ * apply-templates): globals + own locals, never caller locals. */
2910
+ return xslt_invoke_template(ex, t, node, in->child);
2911
+ }
2912
+
2913
+
2914
+
2915
+ /* ---- §3.4 whitespace stripping on the SOURCE tree ----
2916
+ *
2917
+ * Runs once per transform, before globals. A whitespace-only text
2918
+ * node survives when: its parent's name is in the preserve list
2919
+ * and NOT in the strip list (strip wins on overlap), OR any
2920
+ * ancestor carries xml:space="preserve". With no declarations the
2921
+ * preserve set is empty and every ws-only text node is stripped —
2922
+ * the XSLT 1.0 default. */
2923
+ static int ws_only(const char* t) {
2924
+ if (!t) return 1;
2925
+ for (const char* p = t; *p; p++) {
2926
+ if (*p != ' ' && *p != '\t' && *p != '\r' && *p != '\n') return 0;
2927
+ }
2928
+ return 1;
2929
+ }
2930
+
2931
+ static int ancestor_xml_space_preserve(LeptrisElement e) {
2932
+ for (LeptrisElement a = e; a;
2933
+ a = leptris_node_parent((LeptrisNodeRef)a)) {
2934
+ const char* xs = leptris_element_attribute(a, "xml:space");
2935
+ if (!xs) xs = leptris_element_attribute(a, "space");
2936
+ if (xs && strcmp(xs, "preserve") == 0) return 1;
2937
+ if (xs && strcmp(xs, "default") == 0) return 0;
2938
+ }
2939
+ return 0;
2940
+ }
2941
+
2942
+ /* §3.4 NameTest against a list entry: exact QName, "*", "p:*"
2943
+ * (any element in p's namespace), "p:name". The stylesheet root's
2944
+ * declarations resolve the prefixes. */
2945
+ static int strip_entry_matches(char** list, const char* entry,
2946
+ const char* local, const char* elem_uri,
2947
+ LeptrisElement sheet_root) {
2948
+ (void)list;
2949
+ if (!entry || !local) return 0;
2950
+ const char* colon = strchr(entry, ':');
2951
+ if (!colon) {
2952
+ /* Unprefixed: "*" matches every element; a plain name
2953
+ * matches NO-NAMESPACE elements only (bug-82: a same-local
2954
+ * element in a namespace is not stripped). */
2955
+ if (strcmp(entry, "*") == 0) return 1;
2956
+ if (elem_uri && *elem_uri) return 0;
2957
+ return strcmp(entry, local) == 0;
2958
+ }
2959
+ if (!sheet_root) return 0;
2960
+ size_t plen = (size_t)(colon - entry);
2961
+ const char* rest = colon + 1;
2962
+ /* Resolve the prefix through the stylesheet root's declarations. */
2963
+ const char* uri = NULL;
2964
+ for (int i = 0;; i++) {
2965
+ const char* p = leptris_element_namespace_decl_prefix(
2966
+ sheet_root, i);
2967
+ const char* u = leptris_element_namespace_decl_uri(
2968
+ sheet_root, i);
2969
+ if (!p || !u) break;
2970
+ if (strlen(p) == plen && strncmp(p, entry, plen) == 0) {
2971
+ uri = u;
2972
+ break;
2973
+ }
2974
+ }
2975
+ if (!uri) return 0;
2976
+ if (!elem_uri || strcmp(uri, elem_uri) != 0) return 0;
2977
+ return strcmp(rest, "*") == 0 || strcmp(rest, local) == 0;
2978
+ }
2979
+
2980
+ static void strip_source_whitespace(XsltExec* ex) {
2981
+ if (!ex || !ex->source || !ex->sheet->ws_strip) return;
2982
+ /* libxslt reference semantics: source whitespace is PRESERVED
2983
+ * by default; only names listed in xsl:strip-space (minus
2984
+ * preserve-space) strip, with xml:space="preserve" winning. */
2985
+ LeptrisElement sheet_root =
2986
+ ex->sheet_doc ? leptris_document_root(ex->sheet_doc) : NULL;
2987
+ for (LeptrisElement e = leptris_document_root(ex->source); e;
2988
+ e = xslt_next_doc_order(e)) {
2989
+ const char* name = leptris_element_name(e);
2990
+ if (!name) continue;
2991
+ const char* euri = leptris_element_get_namespace_uri(e);
2992
+ /* §3.4: the LAST matching declaration wins (bug-82:
2993
+ * preserve * then strip child strips child). */
2994
+ int strip = 0;
2995
+ for (size_t i = 0; i < ex->sheet->ws_rule_count; i++) {
2996
+ if (strip_entry_matches(ex->sheet->ws_rules,
2997
+ ex->sheet->ws_rules[i], name,
2998
+ euri, sheet_root)) {
2999
+ strip = !ex->sheet->ws_rule_preserve[i];
3000
+ }
3001
+ }
3002
+ if (!strip || ancestor_xml_space_preserve(e)) continue;
3003
+ for (LeptrisNodeRef c =
3004
+ leptris_node_first_child(leptris_element_as_node(e));
3005
+ c; c = leptris_node_next_sibling(c)) {
3006
+ if (leptris_node_get_type(c) != LEPTRIS_NODE_TYPE_TEXT) continue;
3007
+ const char* t = leptris_text_get_content((LeptrisTextNode*)c);
3008
+ if (!ws_only(t)) continue;
3009
+ /* Empty in place — never unlink (compact-parse text
3010
+ * nodes link via int32 offsets that unlinking can
3011
+ * orphan for following siblings) and never call
3012
+ * leptris_text_set_content: get_content may have
3013
+ * materialized the content into POOL memory which
3014
+ * set_content would free(). Direct field writes with
3015
+ * borrowed=1 + pool=NULL leave the node readable ("")
3016
+ * and safe from every free path. */
3017
+ LeptrisTextNode* tn = (LeptrisTextNode*)c;
3018
+ tn->content = (char*)"";
3019
+ tn->content_len = 0;
3020
+ tn->borrowed = 1;
3021
+ tn->pool = NULL;
3022
+ }
3023
+ }
3024
+ }
3025
+
3026
+ /* ---- §5.4/§5.5 template selection + invocation ----
3027
+ *
3028
+ * Selection resolves (import_rank, priority, declaration order):
3029
+ * lower rank wins; equal rank → higher priority; equal both → the
3030
+ * LAST declared (list append order). Per §5.5 the priority of a
3031
+ * union pattern is per-ALTERNATIVE — we take the max priority
3032
+ * among the alternatives that actually MATCH. min_rank excludes
3033
+ * the importing sheets' own rules for xsl:apply-imports (§5.6). */
3034
+
3035
+ /* Comment/PI nodes match only node()-kind tests; the element-cast
3036
+ * ladder is unsafe for them. Text-level alternative scan. */
3037
+ static int pattern_matches_nodekind(const XsltPattern* p,
3038
+ int node_type,
3039
+ const char* node_name) {
3040
+ for (const XsltPattern* alt = p; alt; alt = alt->next) {
3041
+ const char* e = leptris_xpath_compiled_text(alt->expr);
3042
+ if (!e) continue;
3043
+ int is_comment = node_type == LEPTRIS_NODE_TYPE_COMMENT;
3044
+ int is_pi = node_type == LEPTRIS_NODE_TYPE_PI;
3045
+ int is_text = node_type == LEPTRIS_NODE_TYPE_TEXT ||
3046
+ node_type == LEPTRIS_NODE_TYPE_CDATA;
3047
+ if (strstr(e, "node()")) return 1;
3048
+ if (is_comment && strstr(e, "comment()")) return 1;
3049
+ if (is_pi && strstr(e, "processing-instruction()")) return 1;
3050
+ if (is_text && strstr(e, "text()")) return 1;
3051
+ /* Attribute patterns: @* / @name (the only axis reaching
3052
+ * attribute nodes — a text-level scan suffices). */
3053
+ if (node_type == LEPTRIS_NODE_ATTRIBUTE) {
3054
+ const char* at = strchr(e, '@');
3055
+ if (at) {
3056
+ const char* nm = at + 1;
3057
+ if (nm[0] == '*' || !nm[0]) return 1;
3058
+ if (node_name && strncmp(nm, node_name,
3059
+ strlen(node_name)) == 0)
3060
+ return 1;
3061
+ }
3062
+ }
3063
+ }
3064
+ return 0;
3065
+ }
3066
+
3067
+ /* §5.2: every node kind matches through the FULL pattern ladder —
3068
+ * position predicates included. The old kind-only shortcut made
3069
+ * match="text()[2]" fire for every text node (libxslt bug-182). */
3070
+ static const XsltTemplate* xslt_select_template(
3071
+ const XsltExec* ex, LeptrisElement node, const char* mode,
3072
+ int min_rank) {
3073
+ const XsltTemplate* best = NULL;
3074
+ double best_pri = 0;
3075
+ size_t best_order = 0;
3076
+ /* Mode bucket (#682): same candidates in the same sheet order,
3077
+ * without the per-template mode comparison the full-list scan
3078
+ * paid on every dispatch. */
3079
+ const XsltModeBucket* bucket = xslt_sheet_mode(ex->sheet, mode);
3080
+ if (!bucket) return NULL;
3081
+ const int node_is_elem = leptris_node_get_type((LeptrisNodeRef)node) ==
3082
+ LEPTRIS_NODE_TYPE_ELEMENT;
3083
+ const XsltNameKey* nkey = NULL;
3084
+ if (node_is_elem) {
3085
+ const char* nn = leptris_element_get_name(node);
3086
+ if (nn) nkey = xslt_bucket_name_key(bucket, nn);
3087
+ }
3088
+ size_t nattrs = node_is_elem
3089
+ ? leptris_element_attribute_count(node) : 0;
3090
+ const unsigned gen = XSLT_DISPATCH_NEXT_GEN();
3091
+ for (int part = 0; part < 2 + (int)nattrs; part++) {
3092
+ XsltTemplate* const* cand = NULL;
3093
+ size_t ncand = 0;
3094
+ if (part == 0) {
3095
+ if (!nkey) continue;
3096
+ cand = nkey->list;
3097
+ ncand = nkey->n;
3098
+ } else if (part == 1) {
3099
+ cand = bucket->other;
3100
+ ncand = bucket->n_other;
3101
+ } else {
3102
+ /* #866: literal @attr='value' candidates — probe the value
3103
+ * index with each attribute of this element. */
3104
+ if (!bucket->pkeys) continue;
3105
+ size_t ai = (size_t)(part - 2);
3106
+ LeptrisAttribute a = leptris_element_first_attribute(node);
3107
+ for (size_t j = 0; a && j < ai; j++) a = leptris_attribute_next(a);
3108
+ if (!a) continue;
3109
+ const char* an = leptris_attribute_get_name(a);
3110
+ const char* av = leptris_attribute_get_value(node, a);
3111
+ if (!an || !av) continue;
3112
+ const struct xslt_pkey* pk =
3113
+ xslt_bucket_pred_key(bucket,
3114
+ nkey ? nkey->name
3115
+ : leptris_element_get_name(node),
3116
+ an, av);
3117
+ if (!pk) continue;
3118
+ cand = pk->list;
3119
+ ncand = pk->n;
3120
+ }
3121
+ for (size_t bi = 0; bi < ncand; bi++) {
3122
+ XsltTemplate* t = cand[bi];
3123
+ if (t->dispatch_stamp == gen) continue;
3124
+ t->dispatch_stamp = gen;
3125
+ size_t order = t->order;
3126
+ if (t->import_rank < min_rank) continue;
3127
+ /* ONE pass over the alternatives: each is matched exactly
3128
+ * once and the max priority rides the same walk (the old
3129
+ * shape matched the whole list first, then re-evaluated
3130
+ * every alternative for priority — 2x the pattern cost per
3131
+ * dispatch candidate). */
3132
+ double pri = 0; int have = 0;
3133
+ /* #682 fast path: a lone bare-Name alternative is
3134
+ * child::NAME — plain name + no-namespace check, no doc
3135
+ * climb, no ladder ("*" matches every element). */
3136
+ if (t->fast_name && node_is_elem) {
3137
+ const char* fn = t->fast_name;
3138
+ if (!(fn[0] == '*' && fn[1] == 0)) {
3139
+ const char* nn = leptris_element_get_name(node);
3140
+ if (!nn || strcmp(nn, fn) != 0) continue;
3141
+ const char* nu = leptris_element_get_namespace_uri(node);
3142
+ if (nu && nu[0]) continue;
3143
+ }
3144
+ pri = t->fast_pri;
3145
+ have = 1;
3146
+ } else
3147
+ for (const XsltPattern* pa = t->matches; pa; pa = pa->next) {
3148
+ if (!xslt_pattern_matches(pa, node, ex->source, t->ns))
3149
+ continue;
3150
+ if (!have || pa->priority > pri) { pri = pa->priority; have = 1; }
3151
+ }
3152
+ if (!have) continue;
3153
+ int wins = 0;
3154
+ if (!best) wins = 1;
3155
+ else if (t->import_rank != best->import_rank)
3156
+ wins = t->import_rank < best->import_rank;
3157
+ else if (pri != best_pri) wins = pri > best_pri;
3158
+ else wins = order >= best_order; /* tie: last declared */
3159
+ if (wins) { best = t; best_pri = pri; best_order = order; }
3160
+ }
3161
+ }
3162
+ return best;
3163
+ }
3164
+
3165
+ /* §11.6: evaluate xsl:param defaults for names the caller did not
3166
+ * bind (leading is_param children of the template body). Returns
3167
+ * the number of frames pushed. */
3168
+ /* Deep result copy (frame-bindable): scalars duplicate; nodesets
3169
+ * copy the array (synthetic members are duplicated so the copy
3170
+ * outlives the source's storage). */
3171
+ static struct leptris_xpath_result* tunnel_result_copy(
3172
+ const struct leptris_xpath_result* r) {
3173
+ if (!r) return NULL;
3174
+ struct leptris_xpath_result* c = xpath_result_new(r->type);
3175
+ if (!c) return NULL;
3176
+ switch (r->type) {
3177
+ case XPATH_RESULT_BOOLEAN:
3178
+ c->value.boolean_value = r->value.boolean_value; break;
3179
+ case XPATH_RESULT_NUMBER:
3180
+ c->value.number_value = r->value.number_value; break;
3181
+ case XPATH_RESULT_STRING:
3182
+ c->value.string_value = leptris_strdup(
3183
+ r->value.string_value ? r->value.string_value : "");
3184
+ if (!c->value.string_value) {
3185
+ leptris_xpath_result_free(c); return NULL; }
3186
+ break;
3187
+ case XPATH_RESULT_NODESET: {
3188
+ XPathNodeSet* src = r->value.nodeset_value;
3189
+ c->value.nodeset_value = xpath_nodeset_new();
3190
+ if (!c->value.nodeset_value) {
3191
+ leptris_xpath_result_free(c); return NULL; }
3192
+ if (src) {
3193
+ if (src->owns_synthetic_text)
3194
+ c->value.nodeset_value->owns_synthetic_text = 1;
3195
+ c->value.nodeset_value->is_sequence = src->is_sequence;
3196
+ for (size_t i = 0; i < src->count; i++) {
3197
+ void* n = src->nodes[i];
3198
+ if (src->owns_synthetic_text && n &&
3199
+ leptris_node_get_type(n) == LEPTRIS_NODE_TYPE_TEXT) {
3200
+ char* t = get_node_text(n);
3201
+ size_t tl = t ? strlen(t) : 0;
3202
+ XPathNodeSet* one = xpath_nodeset_new();
3203
+ if (one) {
3204
+ xpath_nodeset_add(one, n);
3205
+ /* synth via evaluator export */
3206
+ extern XPathTextNode* xpath_synth_text(
3207
+ const char*, size_t);
3208
+ XPathTextNode* tn =
3209
+ xpath_synth_text(t ? t : "", tl);
3210
+ free(t);
3211
+ xpath_nodeset_free(one);
3212
+ if (tn) xpath_nodeset_add(
3213
+ c->value.nodeset_value, tn);
3214
+ }
3215
+ } else {
3216
+ xpath_nodeset_add(c->value.nodeset_value, n);
3217
+ }
3218
+ }
3219
+ }
3220
+ break;
3221
+ }
3222
+ default: break;
3223
+ }
3224
+ return c;
3225
+ }
3226
+
3227
+ static int xslt_bind_param_defaults(XsltExec* ex, const XsltInstr* body,
3228
+ LeptrisElement node) {
3229
+ int pushed = 0;
3230
+ for (const XsltInstr* p = body; p; p = p->next) {
3231
+ if (p->kind != XSLT_INSTR_VARIABLE || !p->is_param) break;
3232
+ if (!p->name) continue;
3233
+ int bound = 0;
3234
+ for (XsltVar* v = ex->vars; v; v = v->prev) {
3235
+ if (v->name && strcmp(v->name, p->name) == 0) { bound = 1; break; }
3236
+ }
3237
+ if (bound) continue;
3238
+ if (p->tunnel) {
3239
+ /* §11.7: bind from the tunnel chain (innermost wins);
3240
+ * absent names fall through to the declared default. */
3241
+ int hit = 0;
3242
+ for (XsltVar* tv = ex->tunnel_vars; tv; tv = tv->prev) {
3243
+ if (tv->name && strcmp(tv->name, p->name) == 0) {
3244
+ struct leptris_xpath_result* v =
3245
+ tunnel_result_copy(tv->value);
3246
+ if (v) {
3247
+ xslt_push_var(ex, p->name, v);
3248
+ pushed++;
3249
+ }
3250
+ hit = 1;
3251
+ break;
3252
+ }
3253
+ }
3254
+ if (hit) continue;
3255
+ }
3256
+ struct leptris_xpath_result* v = NULL;
3257
+ if (p->num_count) {
3258
+ /* 4.0 @default expression takes precedence. */
3259
+ v = xslt_eval(ex, p->num_count, node);
3260
+ } else if (p->select) {
3261
+ v = xslt_eval(ex, p->select, node);
3262
+ } else if (p->child) {
3263
+ /* Content default: build the RTF like op_variable. */
3264
+ LeptrisElement saved = ex->pending_parent;
3265
+ ex->pending_parent = NULL;
3266
+ xslt_exec_instrs(ex, p->child, node);
3267
+ ex->pending_parent = saved;
3268
+ LeptrisElement rr = leptris_document_root(ex->result);
3269
+ v = xpath_result_new(XPATH_RESULT_NODESET);
3270
+ if (v && rr) {
3271
+ v->value.nodeset_value = xpath_nodeset_new();
3272
+ if (v->value.nodeset_value)
3273
+ for (LeptrisElement c = rr; c;
3274
+ c = leptris_element_next_sibling_any(c))
3275
+ xpath_nodeset_add(v->value.nodeset_value,
3276
+ (LeptrisNodeRef)c);
3277
+ }
3278
+ if (rr) {
3279
+ struct xslt_rtf_entry* ent =
3280
+ (struct xslt_rtf_entry*)malloc(sizeof(*ent));
3281
+ if (ent) {
3282
+ ent->doc = ex->result;
3283
+ ent->next = (struct xslt_rtf_entry*)ex->rtf_chain;
3284
+ ex->rtf_chain = ent;
3285
+ } else {
3286
+ leptris_document_free(ex->result);
3287
+ }
3288
+ ex->result = leptris_document_create();
3289
+ }
3290
+ }
3291
+ xslt_push_var(ex, p->name, v);
3292
+ pushed++;
3293
+ }
3294
+ return pushed;
3295
+ }
3296
+
3297
+ /* Execute a template rule body: current-template tracking (§5.6
3298
+ * apply-imports), with-param scope, param defaults. */
3299
+ static int xslt_invoke_template(XsltExec* ex, const XsltTemplate* t,
3300
+ LeptrisElement node,
3301
+ const XsltInstr* with_params) {
3302
+ const XsltTemplate* saved_t = ex->current_template;
3303
+ ex->current_template = t;
3304
+ /* §11: with-param expressions evaluate in the CALLER's scope;
3305
+ * the body runs on globals + its own params/locals — the
3306
+ * caller's local frames are not visible (bug-40-/42-). */
3307
+ struct leptris_xpath_result* vals[16];
3308
+ const char* names[16];
3309
+ size_t nv = 0;
3310
+ /* §11.6: a with-param binds only names the callee DECLARES as
3311
+ * xsl:param (leading is_param children) — others are ignored
3312
+ * and the callee sees the global (libxslt bugs 41-/43-). */
3313
+ for (const XsltInstr* wp = with_params; wp && nv < 16; wp = wp->next) {
3314
+ if (wp->kind != XSLT_INSTR_WITH_PARAM || !wp->name) continue;
3315
+ if (wp->tunnel) {
3316
+ /* §11.7: tunnel with-params ride the exec chain for the
3317
+ * whole subtree, independent of the callee's
3318
+ * declarations. */
3319
+ struct leptris_xpath_result* tv = NULL;
3320
+ if (wp->select) tv = xslt_eval(ex, wp->select, node);
3321
+ else if (wp->child) tv = xslt_capture_content(ex, wp->child, node);
3322
+ if (tv) {
3323
+ XsltVar* pv = (XsltVar*)calloc(1, sizeof(*pv));
3324
+ if (pv) {
3325
+ pv->name = wp->name;
3326
+ pv->value = tv;
3327
+ pv->prev = ex->tunnel_vars;
3328
+ ex->tunnel_vars = pv;
3329
+ } else {
3330
+ leptris_xpath_result_free(tv);
3331
+ }
3332
+ }
3333
+ continue;
3334
+ }
3335
+ int declared = 0;
3336
+ for (const XsltInstr* b = t->body; b; b = b->next) {
3337
+ if (b->kind != XSLT_INSTR_VARIABLE || !b->is_param) break;
3338
+ if (b->name && strcmp(b->name, wp->name) == 0) {
3339
+ declared = 1;
3340
+ break;
3341
+ }
3342
+ }
3343
+ if (!declared) continue;
3344
+ vals[nv] = wp->select
3345
+ ? xslt_eval(ex, wp->select, node)
3346
+ : (wp->child
3347
+ ? xslt_capture_content(ex, wp->child, node)
3348
+ : NULL);
3349
+ names[nv] = wp->name;
3350
+ nv++;
3351
+ }
3352
+ XsltVar* caller = ex->vars;
3353
+ XsltVar* mark = ex->global_vars;
3354
+ ex->vars = mark;
3355
+ for (size_t i = 0; i < nv; i++)
3356
+ xslt_push_var(ex, names[i], vals[i]);
3357
+ xslt_bind_param_defaults(ex, t->body, node);
3358
+ int rc = xslt_exec_instrs(ex, t->body, node);
3359
+ ex->current_template = saved_t;
3360
+ xslt_pop_vars_to(ex, mark);
3361
+ ex->vars = caller;
3362
+ return rc;
3363
+ }
3364
+
3365
+ /* §5.6 xsl:apply-imports: select the best matching rule from the
3366
+ * stylesheets IMPORTED by (i.e. lower precedence than) the one
3367
+ * containing the currently executing rule. */
3368
+ static int op_apply_templates(XsltExec* ex, const XsltInstr* in,
3369
+ LeptrisElement node);
3370
+
3371
+ /* §6.7 on-no-match of the unnamed mode, for a node NO template
3372
+ * matched. Returns -1 to defer to the legacy 1.0 built-in walk
3373
+ * (unspecified 1.0 sheets and text-only-copy — the existing
3374
+ * behavior); otherwise the walker rc. Only the unnamed mode has a
3375
+ * captured declaration (named modes are not parsed yet). */
3376
+ static int builtin_no_match(XsltExec* ex, const char* mode,
3377
+ LeptrisElement node) {
3378
+ if (mode && *mode) return -1;
3379
+ int v = ex->sheet->mode_on_no_match;
3380
+ if (!v) {
3381
+ if (ex->sheet->version_major >= 3) v = 3; /* shallow-copy */
3382
+ else return -1; /* 1.0: the text built-ins */
3383
+ }
3384
+ if (v == 6) return -1; /* text-only-copy: legacy */
3385
+ if (v == 5) return 0; /* deep-skip: nothing */
3386
+ if (v == 7) { /* fail: XTDE0500 */
3387
+ const char* nn =
3388
+ leptris_node_get_type((LeptrisNodeRef)node) ==
3389
+ LEPTRIS_NODE_TYPE_ELEMENT
3390
+ ? leptris_element_get_name(node) : "node";
3391
+ ex->eval_error = 1;
3392
+ snprintf(ex->error, sizeof(ex->error),
3393
+ "XTDE0500: no template rule matches %s in the "
3394
+ "unnamed mode (on-no-match=fail)",
3395
+ nn ? nn : "node");
3396
+ return 1;
3397
+ }
3398
+ if (leptris_node_get_type((LeptrisNodeRef)node) !=
3399
+ LEPTRIS_NODE_TYPE_ELEMENT)
3400
+ return -1;
3401
+ if (v == 2) { /* deep-copy: verbatim */
3402
+ copy_node_deep(ex, node, ex->pending_parent);
3403
+ return 0;
3404
+ }
3405
+ /* shallow-copy: copy the element, dispatch attributes (they
3406
+ * are NOT copied raw — a matching rule runs), then children
3407
+ * via the standard no-select walk. shallow-skip: no copy,
3408
+ * dispatch attributes and ELEMENT children only (text skipped
3409
+ * — Saxon ground truth). */
3410
+ LeptrisElement e = NULL;
3411
+ LeptrisElement saved_parent = NULL;
3412
+ int rc = 0;
3413
+ if (v == 3) {
3414
+ const char* nn = leptris_element_get_name(node);
3415
+ saved_parent = ex->pending_parent;
3416
+ e = nn ? out_append_elem(ex, ex->pending_parent, nn, NULL) : NULL;
3417
+ if (!e) { return 0; }
3418
+ ex->pending_parent = e;
3419
+ }
3420
+ if (!e) saved_parent = ex->pending_parent;
3421
+ /* Attributes dispatch through the XPath attribute AXIS — its
3422
+ * synthetic nodes are what pattern identity (owner, name) and
3423
+ * the attribute templates operate on; the element's raw
3424
+ * attribute records do not share that layout. */
3425
+ {
3426
+ LeptrisXPathCompiled at = leptris_xpath_compile("@*");
3427
+ if (at) {
3428
+ struct leptris_xpath_result* ar = xslt_eval(ex, at, node);
3429
+ size_t an = ar ? leptris_xpath_result_count(ar) : 0;
3430
+ for (size_t ai = 0; ai < an && rc == 0; ai++) {
3431
+ LeptrisElement a = (LeptrisElement)
3432
+ leptris_xpath_result_get_node(ar, ai);
3433
+ const XsltTemplate* best =
3434
+ xslt_select_template(ex, a, mode, 0);
3435
+ if (best)
3436
+ rc = xslt_invoke_template(ex, best, a, NULL);
3437
+ }
3438
+ if (ar) leptris_xpath_result_free(ar);
3439
+ leptris_xpath_compiled_free(at);
3440
+ }
3441
+ }
3442
+ if (rc) return rc;
3443
+ if (v == 4) {
3444
+ /* shallow-skip: element children, recursive skip. */
3445
+ for (LeptrisNodeRef c =
3446
+ leptris_node_first_child(leptris_element_as_node(node));
3447
+ c && rc == 0; c = leptris_node_next_sibling(c)) {
3448
+ if (leptris_node_get_type(c) != LEPTRIS_NODE_TYPE_ELEMENT)
3449
+ continue;
3450
+ const XsltTemplate* best =
3451
+ xslt_select_template(ex, (LeptrisElement)c, mode, 0);
3452
+ if (best) {
3453
+ rc = xslt_invoke_template(ex, best, (LeptrisElement)c, NULL);
3454
+ } else {
3455
+ int br = builtin_no_match(ex, mode, (LeptrisElement)c);
3456
+ if (br >= 0) rc = br;
3457
+ else
3458
+ rc = op_apply_templates(
3459
+ ex,
3460
+ &(XsltInstr){ .kind = XSLT_INSTR_APPLY_TEMPLATES,
3461
+ .name = mode },
3462
+ (LeptrisElement)c);
3463
+ }
3464
+ }
3465
+ return rc;
3466
+ }
3467
+ /* shallow-copy: children through the standard walk under e. */
3468
+ rc = op_apply_templates(
3469
+ ex,
3470
+ &(XsltInstr){ .kind = XSLT_INSTR_APPLY_TEMPLATES, .name = mode },
3471
+ node);
3472
+ ex->pending_parent = saved_parent;
3473
+ return rc;
3474
+ }
3475
+
3476
+ static int op_apply_imports(XsltExec* ex, const XsltInstr* in,
3477
+ LeptrisElement node) {
3478
+ (void)in;
3479
+ int min_rank = ex->current_template
3480
+ ? ex->current_template->import_rank + 1 : 1;
3481
+ const XsltTemplate* t = xslt_select_template(
3482
+ ex, node, ex->current_template ? ex->current_template->mode : NULL,
3483
+ min_rank);
3484
+ if (t) return xslt_invoke_template(ex, t, node, NULL);
3485
+ /* No imported candidate: libxslt applies the BUILT-IN rule for
3486
+ * the node (the element rule re-enters selection for the
3487
+ * children — bug-193's <result> gets "passed"). */
3488
+ return op_apply_templates(
3489
+ ex,
3490
+ &(XsltInstr){ .kind = XSLT_INSTR_APPLY_IMPORTS,
3491
+ .name = ex->current_template
3492
+ ? ex->current_template->mode : NULL },
3493
+ node);
3494
+ }
3495
+
3496
+ /* §15 fallback for unknown xsl: instructions (forward-compatible
3497
+ * containers): execute the xsl:fallback children, skip the rest. */
3498
+ static int op_unknown_xsl(XsltExec* ex, const XsltInstr* in,
3499
+ LeptrisElement node) {
3500
+ (void)node;
3501
+ if (!in->child) return 0;
3502
+ return xslt_exec_instrs(ex, in->child, node);
3503
+ }
3504
+
3505
+ static int op_apply_templates(XsltExec* ex, const XsltInstr* in,
3506
+ LeptrisElement node) {
3507
+ int rc = 0;
3508
+ struct leptris_xpath_result* r = in->select
3509
+ ? xslt_eval(ex, in->select, node)
3510
+ : NULL;
3511
+ size_t n = 0;
3512
+ LeptrisElement* items = NULL;
3513
+ if (r) {
3514
+ n = leptris_xpath_result_count(r);
3515
+ if (n) {
3516
+ items = (LeptrisElement*)calloc(n, sizeof(LeptrisElement));
3517
+ if (items) {
3518
+ /* Node-typed accessor: selections may carry text/
3519
+ * comment/PI nodes (identity transforms) — the
3520
+ * element-typed result_get nulls them. */
3521
+ for (size_t i = 0; i < n; i++)
3522
+ items[i] = (LeptrisElement)
3523
+ leptris_xpath_result_get_node(r, i);
3524
+ }
3525
+ }
3526
+ /* NOT freed here: synthetic attr/namespace items are
3527
+ * result-owned; freed after the loop below. */
3528
+ } else {
3529
+ /* No-select apply-templates ON a text item (built-in TEXT
3530
+ * rule via the items loop, §5.8): copy the text itself —
3531
+ * the child walk below would enumerate a text node's
3532
+ * (nonexistent) children and drop it (bug-161). */
3533
+ int sel_ty = node
3534
+ ? leptris_node_get_type((LeptrisNodeRef)node) : 0;
3535
+ if (sel_ty == LEPTRIS_NODE_TYPE_TEXT ||
3536
+ sel_ty == LEPTRIS_NODE_TYPE_CDATA) {
3537
+ const char* t =
3538
+ leptris_text_get_content((LeptrisTextNode*)node);
3539
+ if (ex->pending_parent) {
3540
+ out_append_text(ex, ex->pending_parent, t ? t : "");
3541
+ } else if (t) {
3542
+ char* v = escape_fragment_text(
3543
+ t, ex->sheet->out_method_text);
3544
+ out_append_text(ex, NULL, v);
3545
+ if (v != t) free(v);
3546
+ }
3547
+ if (r) leptris_xpath_result_free(r);
3548
+ return 0;
3549
+ }
3550
+ /* Document-node context (§5.4): the children ARE the root
3551
+ * element (this engine's document model — top-level
3552
+ * comments/PIs live outside the XPath tree), so template
3553
+ * selection runs FOR it — not an enumeration of its
3554
+ * children. No match → the built-in element rule. */
3555
+ if (node &&
3556
+ leptris_node_get_type((LeptrisNodeRef)node) ==
3557
+ LEPTRIS_NODE_TYPE_DOCUMENT) {
3558
+ /* The document node carries its OWN document — foreign
3559
+ * docs (document(), RTFs) must not resolve through
3560
+ * ex->source (that looped document-inclusion forever). */
3561
+ struct leptris_document* nd =
3562
+ ((LeptrisDocumentNode*)node)->doc;
3563
+ LeptrisElement doc_root =
3564
+ (LeptrisElement)(nd ? nd->new_dom_root : NULL);
3565
+ if (!doc_root && nd) doc_root = nd->root;
3566
+ if (!doc_root) return 0;
3567
+ /* Document children in order: the document child chain
3568
+ * (prolog top comments/PIs), then the root element — of
3569
+ * THIS node's document (nd), never ex->source: a foreign
3570
+ * doc node (document(), RTF) walking the source's chain
3571
+ * applied templates to the SOURCE's nodes (bug-65). */
3572
+ int rc = 0;
3573
+ LeptrisNodeRef rootn = leptris_element_as_node(doc_root);
3574
+ for (LeptrisNodeRef n = (LeptrisNodeRef)nd->doc_children_head;
3575
+ n && n != rootn && rc == 0;
3576
+ n = leptris_node_next_sibling(n)) {
3577
+ const XsltTemplate* best =
3578
+ xslt_select_template(ex, (LeptrisElement)n,
3579
+ in->name, 0);
3580
+ if (best) {
3581
+ rc = xslt_invoke_template(ex, best,
3582
+ (LeptrisElement)n, in->child);
3583
+ }
3584
+ }
3585
+ if (rc) return rc;
3586
+ int root_rc;
3587
+ {
3588
+ const XsltTemplate* best =
3589
+ xslt_select_template(ex, doc_root, in->name, 0);
3590
+ root_rc = best
3591
+ ? xslt_invoke_template(ex, best, doc_root, in->child)
3592
+ : (builtin_no_match(ex, in->name, doc_root) >= 0
3593
+ ? 0
3594
+ : op_apply_templates(
3595
+ ex,
3596
+ &(XsltInstr){
3597
+ .kind = XSLT_INSTR_APPLY_TEMPLATES,
3598
+ .name = in->name },
3599
+ doc_root));
3600
+ }
3601
+ if (root_rc) return root_rc;
3602
+ /* The after-root chain (top comments/PIs following the
3603
+ * root element) completes document order. */
3604
+ for (LeptrisNodeRef n = leptris_node_next_sibling(rootn);
3605
+ n && rc == 0; n = leptris_node_next_sibling(n)) {
3606
+ const XsltTemplate* best =
3607
+ xslt_select_template(ex, (LeptrisElement)n,
3608
+ in->name, 0);
3609
+ if (best)
3610
+ rc = xslt_invoke_template(ex, best,
3611
+ (LeptrisElement)n, in->child);
3612
+ }
3613
+ return rc;
3614
+ }
3615
+ /* Default (§5.4): child nodes in DOCUMENT ORDER — text
3616
+ * copies inline (built-in text rule, §5.8), elements select
3617
+ * and invoke their template AS ENCOUNTERED so output order
3618
+ * matches the source (the old batch-then-loop broke
3619
+ * interleaving). The node-list being processed here is the
3620
+ * child axis — position() counts every child, all kinds.
3621
+ * A zero-length text child is a stripped §3.4 node (parse
3622
+ * never creates empty text nodes) — it is gone. */
3623
+ size_t saved_cpos = ex->current_pos;
3624
+ size_t saved_csize = ex->current_size;
3625
+ size_t cpos = 0;
3626
+ /* last() needs the SAME node-list position() counts — every
3627
+ * non-stripped child, all kinds (issue 628). */
3628
+ for (LeptrisNodeRef pc =
3629
+ leptris_node_first_child(leptris_element_as_node(node));
3630
+ pc; pc = leptris_node_next_sibling(pc)) {
3631
+ if (pc->type == LEPTRIS_NODE_TYPE_TEXT &&
3632
+ leptris_text_node_get_content(pc)[0] == '\0')
3633
+ continue;
3634
+ cpos++;
3635
+ }
3636
+ ex->current_size = cpos;
3637
+ cpos = 0;
3638
+ for (LeptrisNodeRef c =
3639
+ leptris_node_first_child(leptris_element_as_node(node));
3640
+ c && rc == 0; c = leptris_node_next_sibling(c)) {
3641
+ int ty = leptris_node_get_type(c);
3642
+ if (ty == LEPTRIS_NODE_TYPE_TEXT &&
3643
+ leptris_text_node_get_content(c)[0] == '\0')
3644
+ continue;
3645
+ ex->current_pos = ++cpos;
3646
+ if (ty == LEPTRIS_NODE_TYPE_TEXT ||
3647
+ ty == LEPTRIS_NODE_TYPE_CDATA) {
3648
+ /* §5.4: text children route through template
3649
+ * selection like every other kind — a user
3650
+ * match="text()" overrides the built-in copy rule
3651
+ * (bug-171: match="text()"/ was ignored here). */
3652
+ LeptrisElement item = (LeptrisElement)c;
3653
+ const XsltTemplate* best =
3654
+ xslt_select_template(ex, item, in->name, 0);
3655
+ if (best) {
3656
+ rc = xslt_invoke_template(ex, best, item,
3657
+ in->child);
3658
+ continue;
3659
+ }
3660
+ const char* t = leptris_text_get_content(
3661
+ (LeptrisTextNode*)c);
3662
+ if (ex->pending_parent) {
3663
+ out_append_text(ex, ex->pending_parent, t ? t : "");
3664
+ } else if (t) {
3665
+ char* v = escape_fragment_text(
3666
+ t, ex->sheet->out_method_text);
3667
+ out_append_text(ex, NULL, v);
3668
+ if (v != t) free(v);
3669
+ }
3670
+ continue;
3671
+ }
3672
+ if (ty == LEPTRIS_NODE_TYPE_COMMENT ||
3673
+ ty == LEPTRIS_NODE_TYPE_PI) {
3674
+ /* Comments/PIs go through template selection too
3675
+ * (§5.4); the built-in rule for them is a no-op, but
3676
+ * match='node()'/comment()/processing-instruction()
3677
+ * templates MUST see them (the identity transform). */
3678
+ LeptrisElement item = (LeptrisElement)c;
3679
+ const XsltTemplate* best =
3680
+ xslt_select_template(ex, item, in->name, 0);
3681
+ if (best)
3682
+ rc = xslt_invoke_template(ex, best, item, in->child);
3683
+ continue;
3684
+ }
3685
+ if (ty != LEPTRIS_NODE_TYPE_ELEMENT) continue;
3686
+ {
3687
+ LeptrisElement item = (LeptrisElement)c;
3688
+ const XsltTemplate* best =
3689
+ xslt_select_template(ex, item, in->name, 0);
3690
+ if (best) {
3691
+ rc = xslt_invoke_template(ex, best, item, in->child);
3692
+ } else {
3693
+ int br = builtin_no_match(ex, in->name, item);
3694
+ if (br >= 0)
3695
+ rc = br;
3696
+ else
3697
+ rc = op_apply_templates(
3698
+ ex,
3699
+ &(XsltInstr){ .kind =
3700
+ XSLT_INSTR_APPLY_TEMPLATES,
3701
+ .name = in->name },
3702
+ item);
3703
+ }
3704
+ }
3705
+ }
3706
+ ex->current_pos = saved_cpos;
3707
+ ex->current_size = saved_csize;
3708
+ }
3709
+ if (!items) {
3710
+ /* Early exit must not strand the selection (Linux LSan —
3711
+ * attr/namespace nodesets are result-owned either way). */
3712
+ if (r) leptris_xpath_result_free(r);
3713
+ return n ? -1 : 0;
3714
+ }
3715
+
3716
+ /* §10: xsl:sort children order the selection. */
3717
+ if (in->sorts) xslt_sort_items(ex, in, items, n);
3718
+
3719
+ /* with-params bind per invocation (xslt_invoke_template). */
3720
+ const char* mode = in->name; /* mode attr parsed into ->name */
3721
+ size_t saved_pos = ex->current_pos;
3722
+ size_t saved_size2 = ex->current_size;
3723
+ ex->current_size = n;
3724
+ for (size_t i = 0; i < n && rc == 0; i++) {
3725
+ ex->current_pos = i + 1;
3726
+ const XsltTemplate* best =
3727
+ xslt_select_template(ex, items[i], mode, 0);
3728
+ if (best) {
3729
+ rc = xslt_invoke_template(ex, best, items[i], in->child);
3730
+ } else {
3731
+ /* Unmatched node: tunnel with-params of THIS apply still
3732
+ * flow (§11.7 — processing continues down the tree). */
3733
+ for (const XsltInstr* wp = in->child; wp; wp = wp->next) {
3734
+ if (wp->kind != XSLT_INSTR_WITH_PARAM || !wp->name ||
3735
+ !wp->tunnel)
3736
+ continue;
3737
+ struct leptris_xpath_result* tv =
3738
+ wp->select ? xslt_eval(ex, wp->select, items[i]) : NULL;
3739
+ XsltVar* pv = (XsltVar*)calloc(1, sizeof(*pv));
3740
+ if (pv) {
3741
+ pv->name = wp->name;
3742
+ pv->value = tv;
3743
+ pv->prev = ex->tunnel_vars;
3744
+ ex->tunnel_vars = pv;
3745
+ } else if (tv) {
3746
+ leptris_xpath_result_free(tv);
3747
+ }
3748
+ }
3749
+ /* Built-in template rules (§5.8/§6.7): on-no-match
3750
+ * variants first, then the 1.0 walk. */
3751
+ int br = builtin_no_match(ex, mode, items[i]);
3752
+ if (br >= 0)
3753
+ rc = br;
3754
+ else
3755
+ rc = op_apply_templates(
3756
+ ex,
3757
+ &(XsltInstr){ .kind = XSLT_INSTR_APPLY_TEMPLATES,
3758
+ .name = in->name },
3759
+ items[i]);
3760
+ }
3761
+ }
3762
+ ex->current_pos = saved_pos;
3763
+ ex->current_size = saved_size2;
3764
+ free(items);
3765
+ if (r) leptris_xpath_result_free(r);
3766
+ return rc;
3767
+ }
3768
+
3769
+ static int op_element(XsltExec* ex, const XsltInstr* in,
3770
+ LeptrisElement node) {
3771
+ char* name = NULL;
3772
+ if (in->select) {
3773
+ struct leptris_xpath_result* r = xslt_eval(ex, in->select, node);
3774
+ if (r) name = leptris_xpath_result_string(r);
3775
+ if (r) leptris_xpath_result_free(r);
3776
+ } else if (in->name) {
3777
+ /* §7.1.1: the name is an AVT — {local-name()},
3778
+ * {concat('a','b')}, prefix:{...}, {$var} (bug-117/179/35-). */
3779
+ name = strchr(in->name, '{')
3780
+ ? eval_avt(ex, in->name, node)
3781
+ : leptris_strdup(in->name);
3782
+ }
3783
+ if (!name) return 0;
3784
+ /* §7.1.1 namespace attribute: an AVT; non-empty binds the
3785
+ * element (or its prefix) to the URI via an xmlns declaration. */
3786
+ char* ns_avt = in->ns_uri && in->ns_uri[0]
3787
+ ? eval_avt(ex, in->ns_uri, node) : NULL;
3788
+ if (ns_avt && !ns_avt[0]) { free(ns_avt); ns_avt = NULL; }
3789
+ char* pfx_ns = NULL;
3790
+ if (!ns_avt) {
3791
+ /* A literal-prefixed name binds through the instruction's
3792
+ * ns context (7.1.1) — the declaration follows the element,
3793
+ * not the whole in-scope set (bug-92 vs bug-117/179). */
3794
+ const char* nc = strchr(name, ':');
3795
+ if (nc && nc != name && in->ns) {
3796
+ const char* u = leptris_xpath_ns_lookup(
3797
+ (const struct leptris_xpath_ns_map*)in->ns, name,
3798
+ (size_t)(nc - name));
3799
+ if (u) pfx_ns = leptris_strdup(u);
3800
+ }
3801
+ }
3802
+ LeptrisElement e = out_append_elem(ex, ex->pending_parent, name,
3803
+ ns_avt ? ns_avt : pfx_ns);
3804
+ if (pfx_ns) {
3805
+ /* The created element carries its prefix (QName split at
3806
+ * creation, #846) — no re-parse of the name. */
3807
+ const char* p2 = leptris_element_get_prefix(e);
3808
+ if (p2 && !result_ns_in_scope(e, p2, pfx_ns))
3809
+ leptris_element_add_namespace_definition(e, p2, pfx_ns);
3810
+ free(pfx_ns);
3811
+ }
3812
+ free(name);
3813
+ if (!e) { free(ns_avt); return -1; }
3814
+ if (ns_avt) {
3815
+ /* Skip the declaration when the result ancestors already
3816
+ * bind the prefix (or default) to the same URI — libxslt
3817
+ * relies on inheritance (bug-179). The prefix comes from
3818
+ * the created element (QName split at creation, #846). */
3819
+ const char* dpfx = leptris_element_get_prefix(e);
3820
+ if (!dpfx) dpfx = "";
3821
+ if (!result_ns_in_scope(e, dpfx, ns_avt))
3822
+ leptris_element_add_namespace_definition(e, dpfx, ns_avt);
3823
+ free(ns_avt);
3824
+ }
3825
+ /* §7.1.1: xsl:element does NOT copy the instruction's
3826
+ * in-scope declarations — only literal result elements do
3827
+ * (libxslt bug-92). The element's own namespace (name prefix
3828
+ * + namespace attribute) is declared above. */
3829
+ xslt_apply_attr_sets(ex, in, e, node);
3830
+ LeptrisElement saved = ex->pending_parent;
3831
+ ex->pending_parent = e;
3832
+ int rc = xslt_exec_instrs(ex, in->child, node);
3833
+ ex->pending_parent = saved;
3834
+ return rc;
3835
+ }
3836
+
3837
+ static int op_attribute(XsltExec* ex, const XsltInstr* in,
3838
+ LeptrisElement node) {
3839
+ if (!in->name || !ex->pending_parent) return 0;
3840
+ /* §7.1.3: the name is an ATTRIBUTE VALUE TEMPLATE; the content
3841
+ * is the string-value of ALL child instructions (the shared
3842
+ * capture — value-of, xsl:number, xsl:text all contribute). */
3843
+ char* nm = strchr(in->name, '{')
3844
+ ? eval_avt(ex, in->name, node)
3845
+ : leptris_strdup(in->name);
3846
+ /* §7.1.3 namespace attribute: an AVT naming the attribute's
3847
+ * namespace. The XML namespace maps to the reserved xml:
3848
+ * prefix (bug-177); any OTHER namespace on an unprefixed name
3849
+ * mints a generated ns_N prefix — attributes never take the
3850
+ * default namespace (libxslt bug-99). */
3851
+ char* ans_uri = in->ns_uri && in->ns_uri[0]
3852
+ ? eval_avt(ex, in->ns_uri, node) : NULL;
3853
+ if (ans_uri && !ans_uri[0]) { free(ans_uri); ans_uri = NULL; }
3854
+ char* final_nm = nm;
3855
+ if (nm && ans_uri) {
3856
+ const char* nc = strchr(nm, ':');
3857
+ if (!nc) {
3858
+ if (strcmp(ans_uri,
3859
+ "http://www.w3.org/XML/1998/namespace") == 0) {
3860
+ size_t l = strlen(nm);
3861
+ final_nm = (char*)malloc(l + 5);
3862
+ if (final_nm) snprintf(final_nm, l + 5, "xml:%s", nm);
3863
+ } else {
3864
+ int n = 1;
3865
+ char pbuf[32];
3866
+ for (;;) {
3867
+ snprintf(pbuf, sizeof(pbuf), "ns_%d", n);
3868
+ const char* cur =
3869
+ leptris_element_namespace_for_prefix(
3870
+ ex->pending_parent, pbuf);
3871
+ if (!cur) break;
3872
+ if (++n > 999) break;
3873
+ }
3874
+ size_t l = strlen(nm);
3875
+ final_nm = (char*)malloc(l + strlen(pbuf) + 2);
3876
+ if (final_nm)
3877
+ snprintf(final_nm, l + strlen(pbuf) + 2,
3878
+ "%s:%s", pbuf, nm);
3879
+ if (final_nm)
3880
+ leptris_element_add_namespace_definition(
3881
+ ex->pending_parent, pbuf, ans_uri);
3882
+ }
3883
+ } else {
3884
+ /* Prefixed name + namespace attribute: the declaration
3885
+ * follows the given URI (rebinding the prefix). */
3886
+ size_t pl = (size_t)(nc - nm);
3887
+ char pbuf[80];
3888
+ if (pl < sizeof(pbuf)) {
3889
+ memcpy(pbuf, nm, pl);
3890
+ pbuf[pl] = 0;
3891
+ leptris_element_add_namespace_definition(
3892
+ ex->pending_parent, pbuf, ans_uri);
3893
+ }
3894
+ }
3895
+ }
3896
+ char* acc = xslt_capture_children_text(ex, in->child, node);
3897
+ if (final_nm && acc)
3898
+ leptris_element_set_attribute(ex->pending_parent, final_nm,
3899
+ acc);
3900
+ if (final_nm != nm) free(final_nm);
3901
+ free(ans_uri);
3902
+ free(nm);
3903
+ free(acc);
3904
+ return 0;
3905
+ }
3906
+
3907
+ /* Run instruction children capturing their string-value (the
3908
+ * xsl:comment / xsl:processing-instruction content model, §7.4).
3909
+ * Returns a malloc'd accumulation; caller frees. The caller's
3910
+ * rtf-capture state and pending parent are preserved. */
3911
+ static char* xslt_capture_children_text(XsltExec* ex,
3912
+ const XsltInstr* child,
3913
+ LeptrisElement node) {
3914
+ size_t saved_len = ex->rtf_text_len;
3915
+ char* saved_buf = ex->rtf_text;
3916
+ size_t saved_cap = ex->rtf_text_cap;
3917
+ int saved_capturing = ex->rtf_capturing;
3918
+ ex->rtf_capturing = 1;
3919
+ ex->rtf_text = (char*)calloc(1, 1);
3920
+ ex->rtf_text_len = 0;
3921
+ ex->rtf_text_cap = 1; /* MUST match the fresh 1-byte buffer —
3922
+ * a stale outer cap skips the grow and
3923
+ * overflows (ASAN, nested captures). */
3924
+ LeptrisElement saved_pp = ex->pending_parent;
3925
+ ex->pending_parent = NULL; /* children emit text, not nodes */
3926
+ xslt_exec_instrs(ex, child, node);
3927
+ ex->pending_parent = saved_pp;
3928
+ char* acc = ex->rtf_text ? ex->rtf_text : (char*)calloc(1, 1);
3929
+ ex->rtf_text = saved_buf;
3930
+ ex->rtf_text_len = saved_len;
3931
+ ex->rtf_text_cap = saved_cap;
3932
+ ex->rtf_capturing = saved_capturing;
3933
+ return acc;
3934
+ }
3935
+
3936
+ static int op_comment(XsltExec* ex, const XsltInstr* in,
3937
+ LeptrisElement node) {
3938
+ /* Literal comment (template content): in->text carries the
3939
+ * content verbatim — no instruction children. */
3940
+ if (ex->streaming && !in->child && in->text) {
3941
+ buffer_append(ex->sbuf, "<!--");
3942
+ buffer_append(ex->sbuf, in->text);
3943
+ buffer_append(ex->sbuf, "-->");
3944
+ return 0;
3945
+ }
3946
+ if (!in->child && in->text) {
3947
+ LeptrisNodeRef cm = leptris_comment_node_create(ex->result,
3948
+ in->text);
3949
+ if (cm && ex->pending_parent)
3950
+ out_append_child(ex, ex->pending_parent, cm);
3951
+ else if (cm)
3952
+ xslt_append_fragment_node(ex, cm);
3953
+ return 0;
3954
+ }
3955
+ char* acc = xslt_capture_children_text(ex, in->child, node);
3956
+ LeptrisNodeRef cm = leptris_comment_node_create(ex->result, acc);
3957
+ if (cm && ex->pending_parent)
3958
+ leptris_element_append_child_internal(
3959
+ ex->pending_parent, (LeptrisNode*)cm);
3960
+ else if (cm)
3961
+ xslt_append_fragment_node(ex, cm);
3962
+ free(acc);
3963
+ return 0;
3964
+ }
3965
+
3966
+ static int op_pi(XsltExec* ex, const XsltInstr* in, LeptrisElement node) {
3967
+ /* §7.3: the name is an attribute value template. */
3968
+ char* nm = in->name && strchr(in->name, '{')
3969
+ ? eval_avt(ex, in->name, node)
3970
+ : (in->name ? leptris_strdup(in->name) : NULL);
3971
+ if (ex->streaming && !in->child && nm) {
3972
+ buffer_append(ex->sbuf, "<?");
3973
+ buffer_append(ex->sbuf, nm);
3974
+ if (in->text && *in->text) {
3975
+ buffer_append_char(ex->sbuf, ' ');
3976
+ buffer_append(ex->sbuf, in->text);
3977
+ }
3978
+ buffer_append(ex->sbuf, "?>");
3979
+ free(nm);
3980
+ return 0;
3981
+ }
3982
+ /* Literal PI (template content). */
3983
+ if (!in->child && nm) {
3984
+ LeptrisNodeRef pi = leptris_pi_node_create(
3985
+ ex->result, nm, in->text ? in->text : "");
3986
+ if (pi && ex->pending_parent)
3987
+ leptris_element_append_child_internal(
3988
+ ex->pending_parent, (LeptrisNode*)pi);
3989
+ else if (pi)
3990
+ xslt_append_fragment_node(ex, pi);
3991
+ free(nm);
3992
+ return 0;
3993
+ }
3994
+ char* acc = xslt_capture_children_text(ex, in->child, node);
3995
+ LeptrisNodeRef pi = nm ? leptris_pi_node_create(ex->result, nm, acc)
3996
+ : NULL;
3997
+ if (pi && ex->pending_parent)
3998
+ leptris_element_append_child_internal(
3999
+ ex->pending_parent, (LeptrisNode*)pi);
4000
+ else if (pi)
4001
+ xslt_append_fragment_node(ex, pi);
4002
+ free(acc);
4003
+ free(nm);
4004
+ return 0;
4005
+ }
4006
+
4007
+ static int op_message(XsltExec* ex, const XsltInstr* in,
4008
+ LeptrisElement node) {
4009
+ char* acc = (char*)calloc(1, 1);
4010
+ size_t len = 0;
4011
+ for (const XsltInstr* c = in->child; c; c = c->next) {
4012
+ if (c->kind == XSLT_INSTR_TEXT && c->text) {
4013
+ size_t tl = strlen(c->text);
4014
+ acc = (char*)realloc(acc, len + tl + 1);
4015
+ memcpy(acc + len, c->text, tl);
4016
+ len += tl;
4017
+ acc[len] = 0;
4018
+ }
4019
+ }
4020
+ fprintf(stderr, "xslt:message: %s\n", acc);
4021
+ free(acc);
4022
+ if (in->terminate) ex->terminated = 1;
4023
+ return 0;
4024
+ }
4025
+
4026
+ /* Format a positive integer per XSLT number formats (1, 01, a, A,
4027
+ * i, I with format tokens). */
4028
+ static void format_number_token(unsigned long long v, char spec,
4029
+ char* out, size_t outsz) {
4030
+ static const char* lower = "abcdefghijklmnopqrstuvwxyz";
4031
+ switch (spec) {
4032
+ case 'a': {
4033
+ if (v == 0) { snprintf(out, outsz, "a"); break; }
4034
+ size_t o = 0;
4035
+ unsigned long long x = v;
4036
+ char tmp[16];
4037
+ int ti = 0;
4038
+ while (x && ti < 15) {
4039
+ tmp[ti++] = lower[(x - 1) % 26];
4040
+ x = (x - 1) / 26;
4041
+ }
4042
+ while (ti-- > 0 && o < outsz - 1) out[o++] = tmp[ti];
4043
+ out[o] = 0;
4044
+ break;
4045
+ }
4046
+ case 'A': {
4047
+ format_number_token(v, 'a', out, outsz);
4048
+ for (char* p = out; *p; p++) *p = (char)toupper((unsigned char)*p);
4049
+ break;
4050
+ }
4051
+ case 'i':
4052
+ case 'I': {
4053
+ if (v > 3999) {
4054
+ /* Beyond roman capacity libxslt prints the digits. */
4055
+ snprintf(out, outsz, "%llu", v);
4056
+ break;
4057
+ }
4058
+ /* Subtractive algorithm (the 50-entry table only covered
4059
+ * the first roman numerals). */
4060
+ static const unsigned val[] = {1000, 900, 500, 400, 100, 90,
4061
+ 50, 40, 10, 9, 5, 4, 1};
4062
+ static const char* sym[] = {"m", "cm", "d", "cd", "c", "xc",
4063
+ "l", "xl", "x", "ix", "v", "iv", "i"};
4064
+ size_t o = 0;
4065
+ unsigned long long x = v;
4066
+ for (int k = 0; k < 13 && x; k++) {
4067
+ while (x >= val[k] && o + 3 < outsz) {
4068
+ size_t sl = strlen(sym[k]);
4069
+ memcpy(out + o, sym[k], sl);
4070
+ o += sl;
4071
+ x -= val[k];
4072
+ }
4073
+ }
4074
+ out[o] = 0;
4075
+ if (spec == 'I')
4076
+ for (char* p = out; *p; p++)
4077
+ *p = (char)toupper((unsigned char)*p);
4078
+ break;
4079
+ }
4080
+ default:
4081
+ snprintf(out, outsz, "%llu", v);
4082
+ break;
4083
+ }
4084
+ }
4085
+
4086
+ /* ---- xsl:number counting (§7.7) ----
4087
+ * Correctness first: the any-level walk is O(document); the pattern
4088
+ * fast paths from template matching (expr_name) do not apply here
4089
+ * because count/from are arbitrary patterns. */
4090
+
4091
+ LeptrisElement xslt_next_doc_order(LeptrisElement e) {
4092
+ LeptrisElement c = leptris_element_first_child_any(e);
4093
+ if (c) return c;
4094
+ while (e) {
4095
+ LeptrisElement n = leptris_element_next_sibling_any(e);
4096
+ if (n) return n;
4097
+ e = leptris_node_parent((LeptrisNodeRef)e);
4098
+ }
4099
+ return NULL;
4100
+ }
4101
+
4102
+ /* Walk children for parent-relative ladder — the count_matches /
4103
+ * from_matches helpers build a stack-side XsltPattern and reuse the
4104
+ * same matcher the template engine uses. */
4105
+
4106
+ /* Eval hook for count/from patterns: xslt_eval routes through the
4107
+ * exec's variable frame and ns map, so patterns like
4108
+ * count="node()[@type = $type]" resolve their variables (bug-214). */
4109
+ static struct leptris_xpath_result* pattern_eval_with_vars(
4110
+ void* ud, LeptrisXPathCompiled c, LeptrisDocument doc,
4111
+ LeptrisElement node) {
4112
+ (void)doc;
4113
+ return xslt_eval((XsltExec*)ud, c, node);
4114
+ }
4115
+
4116
+ /* §7.7 default count: same node KIND, and where the kind carries an
4117
+ * expanded-name, the same name (element qname, attribute name,
4118
+ * namespace prefix). */
4119
+ static int count_matches_default(LeptrisNodeRef cand, LeptrisNodeRef ref) {
4120
+ if (leptris_node_get_type(cand) != leptris_node_get_type(ref))
4121
+ return 0;
4122
+ switch (leptris_node_get_type(ref)) {
4123
+ case LEPTRIS_NODE_TYPE_ELEMENT: {
4124
+ const char* a = leptris_element_get_name((LeptrisElement)cand);
4125
+ const char* b = leptris_element_get_name((LeptrisElement)ref);
4126
+ return a && b && strcmp(a, b) == 0;
4127
+ }
4128
+ case LEPTRIS_NODE_ATTRIBUTE: {
4129
+ const char* a = ((LeptrisAttributeNode*)cand)->name;
4130
+ const char* b = ((LeptrisAttributeNode*)ref)->name;
4131
+ return a && b && strcmp(a, b) == 0;
4132
+ }
4133
+ case LEPTRIS_NODE_NAMESPACE: {
4134
+ const char* a = ((LeptrisNamespaceNode*)cand)->prefix;
4135
+ const char* b = ((LeptrisNamespaceNode*)ref)->prefix;
4136
+ if (!a || !b) return !a && !b;
4137
+ return strcmp(a, b) == 0;
4138
+ }
4139
+ default:
4140
+ return 1; /* text/comment: kind only (§7.7) */
4141
+ }
4142
+ }
4143
+
4144
+ /* Count predicate: the count pattern, or (default) the same kind +
4145
+ * expanded name as the node being numbered. */
4146
+ static int count_matches(const XsltInstr* in, LeptrisElement cand,
4147
+ LeptrisElement ref, LeptrisDocument doc,
4148
+ XsltExec* ex) {
4149
+ if (in->num_count) {
4150
+ XsltPattern pat;
4151
+ memset(&pat, 0, sizeof(pat));
4152
+ pat.expr = in->num_count;
4153
+ /* Pattern prefixes AND $vars resolve in the declaring
4154
+ * instruction's context. */
4155
+ LeptrisXPathNsSet saved = ex->current_ns;
4156
+ if (in->ns) ex->current_ns = (LeptrisXPathNsSet)in->ns;
4157
+ int m = xslt_pattern_matches_ex(&pat, cand, doc,
4158
+ (LeptrisXPathNsSet)in->ns,
4159
+ pattern_eval_with_vars, ex);
4160
+ ex->current_ns = saved;
4161
+ return m;
4162
+ }
4163
+ return count_matches_default((LeptrisNodeRef)cand,
4164
+ (LeptrisNodeRef)ref);
4165
+ }
4166
+
4167
+ static int from_matches(const XsltInstr* in, LeptrisElement cand,
4168
+ LeptrisDocument doc, XsltExec* ex) {
4169
+ if (!in->num_from) return 0;
4170
+ XsltPattern pat;
4171
+ memset(&pat, 0, sizeof(pat));
4172
+ pat.expr = in->num_from;
4173
+ LeptrisXPathNsSet saved = ex->current_ns;
4174
+ if (in->ns) ex->current_ns = (LeptrisXPathNsSet)in->ns;
4175
+ int m = xslt_pattern_matches_ex(&pat, cand, doc,
4176
+ (LeptrisXPathNsSet)in->ns,
4177
+ pattern_eval_with_vars, ex);
4178
+ ex->current_ns = saved;
4179
+ return m;
4180
+ }
4181
+
4182
+ /* Position of `target` among preceding siblings matching count. */
4183
+ static unsigned long long sibling_number(const XsltInstr* in,
4184
+ LeptrisElement target,
4185
+ LeptrisDocument doc, XsltExec* ex) {
4186
+ int tty = leptris_node_get_type((LeptrisNodeRef)target);
4187
+ if (tty == LEPTRIS_NODE_ATTRIBUTE) {
4188
+ /* Attributes number within the OWNER's attribute list. The
4189
+ * list holds each name once, so the default count (same
4190
+ * kind + name) numbers by list position. */
4191
+ LeptrisAttributeNode* a = (LeptrisAttributeNode*)target;
4192
+ LeptrisElement owner = (LeptrisElement)a->owner;
4193
+ size_t na = owner ? leptris_element_attribute_count(owner) : 0;
4194
+ for (size_t i = 0; i < na; i++) {
4195
+ const char* cn =
4196
+ leptris_element_attribute_name_at(owner, i);
4197
+ if (cn && a->name && strcmp(cn, a->name) == 0)
4198
+ return (unsigned long long)(i + 1);
4199
+ }
4200
+ return 1;
4201
+ }
4202
+ if (tty == LEPTRIS_NODE_NAMESPACE) {
4203
+ /* Namespace nodes have no sibling chain — the in-scope list
4204
+ * dedups prefixes, so the default count (same kind +
4205
+ * prefix) always numbers 1, and XPath 1.0 patterns cannot
4206
+ * name namespace nodes for an explicit count. */
4207
+ return 1;
4208
+ }
4209
+ unsigned long long pos = 1;
4210
+ LeptrisElement parent = leptris_node_parent((LeptrisNodeRef)target);
4211
+ for (LeptrisElement c = leptris_element_first_child_any(parent); c;
4212
+ c = leptris_element_next_sibling_any(c)) {
4213
+ if (c == target) return pos;
4214
+ if (count_matches(in, c, target, doc, ex)) pos++;
4215
+ }
4216
+ return pos;
4217
+ }
4218
+
4219
+ static unsigned long long any_number(const XsltInstr* in, LeptrisElement node,
4220
+ LeptrisDocument doc, XsltExec* ex);
4221
+
4222
+ /* any: how many matching nodes precede `node` in document order. */
4223
+ /* Any-kind document-order walk (comments/PIs count too — §7.7). */
4224
+ static LeptrisNodeRef next_node_doc_order(LeptrisNodeRef n) {
4225
+ LeptrisNodeRef c = leptris_node_first_child(n);
4226
+ if (c) return c;
4227
+ while (n) {
4228
+ LeptrisNodeRef s = leptris_node_next_sibling(n);
4229
+ if (s) return s;
4230
+ /* musl GCC rejects the implicit LeptrisElement store (#582). */
4231
+ n = (LeptrisNodeRef)leptris_node_parent(n);
4232
+ }
4233
+ return NULL;
4234
+ }
4235
+
4236
+ static unsigned long long any_number(const XsltInstr* in, LeptrisElement node,
4237
+ LeptrisDocument doc, XsltExec* ex) {
4238
+ /* Namespace nodes are synthetic — outside the document-order
4239
+ * walk. libxslt numbers them through the OWNER element: the
4240
+ * matching nodes before the owner (inclusive) decide the value
4241
+ * (bug-199). */
4242
+ if (leptris_node_get_type((LeptrisNodeRef)node) ==
4243
+ LEPTRIS_NODE_NAMESPACE) {
4244
+ LeptrisElement owner =
4245
+ (LeptrisElement)((LeptrisNamespaceNode*)node)->owner;
4246
+ return owner ? any_number(in, owner, doc, ex) : 0;
4247
+ }
4248
+ /* Attributes number within their OWNER's attribute list (the
4249
+ * libxslt level=any rule — the tree walk never enters attrs). */
4250
+ if (leptris_node_get_type((LeptrisNodeRef)node) ==
4251
+ LEPTRIS_NODE_ATTRIBUTE) {
4252
+ LeptrisAttributeNode* a = (LeptrisAttributeNode*)node;
4253
+ LeptrisElement owner = (LeptrisElement)a->owner;
4254
+ size_t na = owner ? leptris_element_attribute_count(owner) : 0;
4255
+ for (size_t i = 0; i < na; i++) {
4256
+ const char* cn =
4257
+ leptris_element_attribute_name_at(owner, i);
4258
+ if (cn && a->name && strcmp(cn, a->name) == 0)
4259
+ return (unsigned long long)(i + 1);
4260
+ }
4261
+ return 1;
4262
+ }
4263
+ unsigned long long pos = 1;
4264
+ LeptrisNodeRef target = (LeptrisNodeRef)node;
4265
+ struct leptris_document* sd = (struct leptris_document*)doc;
4266
+ LeptrisNodeRef start =
4267
+ (LeptrisNodeRef)sd->doc_children_head;
4268
+ if (!start)
4269
+ start = leptris_element_as_node(leptris_document_root(doc));
4270
+ for (LeptrisNodeRef n = start; n; n = next_node_doc_order(n)) {
4271
+ if (n == target) return pos;
4272
+ int m;
4273
+ {
4274
+ int nty = leptris_node_get_type(n);
4275
+ if (nty == LEPTRIS_NODE_TYPE_ELEMENT) {
4276
+ m = count_matches(in, (LeptrisElement)n, node, doc, ex);
4277
+ } else if (in->num_count) {
4278
+ XsltPattern pat;
4279
+ memset(&pat, 0, sizeof(pat));
4280
+ pat.expr = in->num_count;
4281
+ m = pattern_matches_nodekind(&pat, nty, NULL);
4282
+ } else {
4283
+ /* §7.7 default count: the node's own kind. */
4284
+ m = (nty == leptris_node_get_type(target));
4285
+ }
4286
+ }
4287
+ if (m) pos++;
4288
+ }
4289
+ return 0; /* detached node: §7.7 says nothing is emitted */
4290
+ }
4291
+
4292
+ static void emit_number_chunk(unsigned long long v, char spec,
4293
+ int group_size, char group_sep,
4294
+ char* out, size_t outsz) {
4295
+ char raw[64];
4296
+ format_number_token(v, spec, raw, sizeof(raw));
4297
+ if (group_size > 0 && group_sep) {
4298
+ size_t gl = strlen(raw), o = 0, cnt = 0;
4299
+ char rev[128];
4300
+ for (size_t i = gl; i-- > 0 && o < sizeof(rev) - 2;) {
4301
+ rev[o++] = raw[i];
4302
+ if (++cnt % (size_t)group_size == 0 && i > 0)
4303
+ rev[o++] = group_sep;
4304
+ }
4305
+ size_t n = o < outsz - 1 ? o : outsz - 1;
4306
+ for (size_t i = 0; i < n; i++) out[i] = rev[o - 1 - i];
4307
+ out[n] = 0;
4308
+ } else {
4309
+ snprintf(out, outsz, "%s", raw);
4310
+ }
4311
+ }
4312
+
4313
+ /* Non-ASCII decimal-digit (Nd) tokens in format strings — the
4314
+ * numbering uses the token's script digits, zero-padded to the
4315
+ * token length (bug-219's Arabic-Indic ٠١). Returns the digit VALUE
4316
+ * (0-9) for a codepoint, or -1 when it is not a covered Nd digit. */
4317
+ static int nd_digit_value(unsigned cp) {
4318
+ static const struct { unsigned lo, hi; } k_nd[] = {
4319
+ {0x0660, 0x0669}, {0x06F0, 0x06F9}, {0x0966, 0x096F},
4320
+ {0x09E6, 0x09EF}, {0x0A66, 0x0A6F}, {0x0AE6, 0x0AEF},
4321
+ {0x0B66, 0x0B6F}, {0x0C66, 0x0C6F}, {0x0CE6, 0x0CEF},
4322
+ {0x0D66, 0x0D6F}, {0x0E50, 0x0E59}, {0x0ED0, 0x0ED9},
4323
+ {0x0F20, 0x0F29}, {0xFF10, 0xFF19},
4324
+ };
4325
+ for (size_t i = 0; i < sizeof(k_nd) / sizeof(k_nd[0]); i++)
4326
+ if (cp >= k_nd[i].lo && cp <= k_nd[i].hi)
4327
+ return (int)(cp - k_nd[i].lo);
4328
+ return -1;
4329
+ }
4330
+
4331
+ /* Decode one UTF-8 codepoint at *pp; advances. */
4332
+ static unsigned utf8_next(const char** pp) {
4333
+ const unsigned char* q = (const unsigned char*)*pp;
4334
+ unsigned cp;
4335
+ if (q[0] < 0x80) { cp = q[0]; *pp += 1; }
4336
+ else if ((q[0] & 0xE0) == 0xC0) {
4337
+ cp = (unsigned)(q[0] & 0x1F) << 6 | (q[1] & 0x3F);
4338
+ *pp += 2;
4339
+ } else if ((q[0] & 0xF0) == 0xE0) {
4340
+ cp = (unsigned)(q[0] & 0x0F) << 12 | (q[1] & 0x3F) << 6 |
4341
+ (q[2] & 0x3F);
4342
+ *pp += 3;
4343
+ } else {
4344
+ cp = (unsigned)(q[0] & 0x07) << 18 | (q[1] & 0x3F) << 12 |
4345
+ (q[2] & 0x3F) << 6 | (q[3] & 0x3F);
4346
+ *pp += 4;
4347
+ }
4348
+ return cp;
4349
+ }
4350
+
4351
+ static size_t utf8_encode(unsigned cp, char* buf) {
4352
+ if (cp < 0x80) { buf[0] = (char)cp; return 1; }
4353
+ if (cp < 0x800) {
4354
+ buf[0] = (char)(0xC0 | cp >> 6);
4355
+ buf[1] = (char)(0x80 | (cp & 0x3F));
4356
+ return 2;
4357
+ }
4358
+ buf[0] = (char)(0xE0 | cp >> 12);
4359
+ buf[1] = (char)(0x80 | ((cp >> 6) & 0x3F));
4360
+ buf[2] = (char)(0x80 | (cp & 0x3F));
4361
+ return 3;
4362
+ }
4363
+
4364
+ static int fmt_char_is_token(unsigned char c, const char* p) {
4365
+ if (c == '1' || c == 'a' || c == 'A' || c == 'i' || c == 'I')
4366
+ return 1;
4367
+ if (c >= 0x80) {
4368
+ const char* q = p;
4369
+ return nd_digit_value(utf8_next(&q)) >= 0;
4370
+ }
4371
+ return 0;
4372
+ }
4373
+
4374
+ /* §7.7.1: number tokens in the format string map to numbers in
4375
+ * order — the LAST token repeats for extra numbers; literal runs are
4376
+ * the prefix (before the first token), separators (between tokens),
4377
+ * and suffix (after the last, emitted only when the last token was
4378
+ * used). */
4379
+ static void emit_formatted_numbers(const unsigned long long* values, int nv,
4380
+ const char* fmt, const XsltInstr* in,
4381
+ char* out, size_t outsz) {
4382
+ char specs[32];
4383
+ char sepbuf[32][48];
4384
+ char prefixbuf[48];
4385
+ size_t prefix_len = 0;
4386
+ int ns = 0;
4387
+ const char* p = fmt;
4388
+
4389
+ while (*p && !fmt_char_is_token((unsigned char)*p, p)) {
4390
+ if (prefix_len + 1 < sizeof(prefixbuf))
4391
+ prefixbuf[prefix_len++] = *p;
4392
+ p++;
4393
+ }
4394
+ prefixbuf[prefix_len] = 0;
4395
+
4396
+ unsigned nd_zero[32];
4397
+ int nd_width[32];
4398
+ while (*p && ns < 32) {
4399
+ if ((unsigned char)*p >= 0x80 &&
4400
+ nd_digit_value(0) >= 0 /* unreachable guard */) {}
4401
+ if ((unsigned char)*p >= 0x80) {
4402
+ /* Nd digit run: one token, script digits, width = run
4403
+ * length (bug-219). */
4404
+ const char* q = p;
4405
+ unsigned first_cp = utf8_next(&q);
4406
+ int v = nd_digit_value(first_cp);
4407
+ unsigned zero_cp = first_cp - (unsigned)v;
4408
+ int width = 1;
4409
+ p = q;
4410
+ while ((unsigned char)*p >= 0x80) {
4411
+ const char* q2 = p;
4412
+ unsigned cp = utf8_next(&q2);
4413
+ if (nd_digit_value(cp) < 0) break;
4414
+ width++;
4415
+ p = q2;
4416
+ }
4417
+ specs[ns] = 'D';
4418
+ nd_zero[ns] = zero_cp;
4419
+ nd_width[ns] = width;
4420
+ ns++;
4421
+ } else {
4422
+ specs[ns++] = *p++;
4423
+ }
4424
+ size_t sl = 0;
4425
+ while (*p && sl + 1 < sizeof(sepbuf[0]) &&
4426
+ !fmt_char_is_token((unsigned char)*p, p)) {
4427
+ sepbuf[ns - 1][sl++] = *p++;
4428
+ }
4429
+ sepbuf[ns - 1][sl] = 0;
4430
+ }
4431
+ if (ns == 0) {
4432
+ specs[0] = '1'; /* junk format: default is "1" */
4433
+ sepbuf[0][0] = 0;
4434
+ ns = 1;
4435
+ }
4436
+
4437
+ size_t o = 0;
4438
+ for (const char* s = prefixbuf; *s && o < outsz - 1; s++) out[o++] = *s;
4439
+ for (int i = 0; i < nv && o < outsz - 1; i++) {
4440
+ if (i > 0) {
4441
+ /* §7.7.1: once the format tokens are exhausted the last
4442
+ * token repeats; the join separator is "." (libxslt's
4443
+ * default when the format has a single token). */
4444
+ const char* sep = (ns > 1)
4445
+ ? sepbuf[i - 1 <= ns - 2 ? i - 1 : ns - 2]
4446
+ : ".";
4447
+ for (const char* s = sep; *s && o < outsz - 1; s++) out[o++] = *s;
4448
+ }
4449
+ char chunk[128];
4450
+ char spec = specs[i < ns ? i : ns - 1];
4451
+ if (spec == 'D') {
4452
+ /* Nd token: decimal digits in the token's script,
4453
+ * zero-padded to the token width. */
4454
+ unsigned zcp = nd_zero[i < ns ? i : ns - 1];
4455
+ int wdt = nd_width[i < ns ? i : ns - 1];
4456
+ char dec[48];
4457
+ snprintf(dec, sizeof(dec), "%lu", values[i]);
4458
+ size_t dl = strlen(dec);
4459
+ size_t pad = (dl < (size_t)wdt) ? (size_t)wdt - dl : 0;
4460
+ size_t co = 0;
4461
+ for (size_t z = 0; z < pad && co + 4 < sizeof(chunk); z++)
4462
+ co += utf8_encode(zcp, chunk + co);
4463
+ for (size_t z = 0; z < dl && co + 4 < sizeof(chunk); z++)
4464
+ co += utf8_encode(zcp + (unsigned)(dec[z] - '0'),
4465
+ chunk + co);
4466
+ chunk[co] = 0;
4467
+ } else if (values[i] == 0 &&
4468
+ (spec == 'a' || spec == 'A' || spec == 'i' || spec == 'I')) {
4469
+ snprintf(chunk, sizeof(chunk), "0"); /* no zeroth letter */
4470
+ } else {
4471
+ emit_number_chunk(values[i], spec, in->num_group_size,
4472
+ in->num_group_sep, chunk, sizeof(chunk));
4473
+ }
4474
+ for (const char* s = chunk; *s && o < outsz - 1; s++) out[o++] = *s;
4475
+ }
4476
+ if (nv >= ns) { /* the last token was used → its tail is the suffix */
4477
+ for (const char* s = sepbuf[ns - 1]; *s && o < outsz - 1; s++)
4478
+ out[o++] = *s;
4479
+ }
4480
+ out[o] = 0;
4481
+ }
4482
+
4483
+ static int op_number(XsltExec* ex, const XsltInstr* in,
4484
+ LeptrisElement node) {
4485
+ unsigned long long values[64];
4486
+ int nv = 0;
4487
+
4488
+ if (in->num_value) {
4489
+ struct leptris_xpath_result* r =
4490
+ xslt_eval(ex, in->num_value, node);
4491
+ if (r) {
4492
+ double d = leptris_xpath_result_number(r);
4493
+ leptris_xpath_result_free(r);
4494
+ if (!(d == d)) {
4495
+ op_text(ex, &(XsltInstr){ .kind = XSLT_INSTR_TEXT,
4496
+ .text = "NaN" }, node);
4497
+ return 0;
4498
+ }
4499
+ if (d < 0) {
4500
+ /* libxslt: a negative value emits the literal "0"
4501
+ * (never NaN, never token-formatted). */
4502
+ op_text(ex, &(XsltInstr){ .kind = XSLT_INSTR_TEXT,
4503
+ .text = "0" }, node);
4504
+ return 0;
4505
+ }
4506
+ values[0] = (unsigned long long)(d + 0.5);
4507
+ } else {
4508
+ values[0] = 1;
4509
+ }
4510
+ nv = 1;
4511
+ } else if (in->num_level == 2) {
4512
+ values[0] = any_number(in, node, ex->source, ex);
4513
+ if (!values[0]) return 0;
4514
+ if (in->num_start_at) values[0] += (unsigned long long)(in->num_start_at - 1);
4515
+ nv = 1;
4516
+ } else if (in->num_level == 1) {
4517
+ /* multiple: every ancestor-or-self matching count, outermost
4518
+ * first, stopping above the nearest `from` match. */
4519
+ unsigned long long rev[64];
4520
+ int nr = 0;
4521
+ for (LeptrisElement a = node; a && nr < 64;
4522
+ a = leptris_node_parent((LeptrisNodeRef)a)) {
4523
+ if (count_matches(in, a, node, ex->source, ex))
4524
+ rev[nr++] = sibling_number(in, a, ex->source, ex) +
4525
+ (in->num_start_at
4526
+ ? (unsigned long long)(in->num_start_at - 1)
4527
+ : 0);
4528
+ if (from_matches(in, a, ex->source, ex)) break;
4529
+ }
4530
+ for (int i = 0; i < nr; i++) values[i] = rev[nr - 1 - i];
4531
+ nv = nr;
4532
+ } else {
4533
+ /* single: nearest ancestor-or-self matching count. */
4534
+ LeptrisElement target = NULL;
4535
+ for (LeptrisElement a = node; a;
4536
+ a = leptris_node_parent((LeptrisNodeRef)a)) {
4537
+ if (count_matches(in, a, node, ex->source, ex)) {
4538
+ target = a; break;
4539
+ }
4540
+ if (from_matches(in, a, ex->source, ex)) break;
4541
+ }
4542
+ if (!target) return 0; /* §7.7: no match → nothing emitted */
4543
+ values[0] = sibling_number(in, target, ex->source, ex) +
4544
+ (in->num_start_at
4545
+ ? (unsigned long long)(in->num_start_at - 1) : 0);
4546
+ nv = 1;
4547
+ }
4548
+
4549
+ /* §7.7 letter-value disambiguator: with an alphabetic token
4550
+ * that could mean either, "alphabetic" forces a/A; the default
4551
+ * heuristic keeps format-driven behavior. */
4552
+ char* fmt_avt = in->num_format && strchr(in->num_format, '{')
4553
+ ? eval_avt(ex, in->num_format, node) : NULL;
4554
+ char fmtbuf[128];
4555
+ const char* fmt_use = fmt_avt ? fmt_avt
4556
+ : (in->num_format ? in->num_format : "1");
4557
+ if (fmt_avt && strlen(fmt_avt) < sizeof(fmtbuf)) {
4558
+ snprintf(fmtbuf, sizeof(fmtbuf), "%s", fmt_avt);
4559
+ fmt_use = fmtbuf;
4560
+ }
4561
+ if (in->letter_value &&
4562
+ strcmp(in->letter_value, "alphabetic") == 0 &&
4563
+ strchr(fmt_use, 'i')) {
4564
+ /* Replace roman tokens with alphabetic on a copy. */
4565
+ snprintf(fmtbuf, sizeof(fmtbuf), "%s", fmt_use);
4566
+ for (char* q = fmtbuf; *q; q++) {
4567
+ if (*q == 'i') *q = 'a';
4568
+ if (*q == 'I') *q = 'A';
4569
+ }
4570
+ fmt_use = fmtbuf;
4571
+ }
4572
+ char out[512];
4573
+ emit_formatted_numbers(values, nv, fmt_use, in, out, sizeof(out));
4574
+ free(fmt_avt);
4575
+ op_text(ex, &(XsltInstr){ .kind = XSLT_INSTR_TEXT, .text = out }, node);
4576
+ return 0;
4577
+ }
4578
+
4579
+ static int op_choose(XsltExec* ex, const XsltInstr* in,
4580
+ LeptrisElement node) {
4581
+ /* Arms are WHEN (with test) / OTHERWISE children in order. */
4582
+ for (const XsltInstr* arm = in->child; arm; arm = arm->next) {
4583
+ if (arm->kind == XSLT_INSTR_WHEN && arm->test) {
4584
+ struct leptris_xpath_result* r = xslt_eval(ex, arm->test, node);
4585
+ int truth = r ? leptris_xpath_result_boolean(r) : 0;
4586
+ if (r) leptris_xpath_result_free(r);
4587
+ if (truth) return xslt_exec_instrs(ex, arm->child, node);
4588
+ } else if (arm->kind == XSLT_INSTR_OTHERWISE) {
4589
+ return xslt_exec_instrs(ex, arm->child, node);
4590
+ }
4591
+ }
4592
+ return 0;
4593
+ }
4594
+
4595
+ /* EXSLT func:result: store the user function's return value and
4596
+ * unwind the body walker (the function call reads ex->fn_result).
4597
+ * select → that value verbatim; content → the RTF's string value
4598
+ * (EXSLT: content results are strings). */
4599
+ static int op_func_result(XsltExec* ex, const XsltInstr* in,
4600
+ LeptrisElement node) {
4601
+ if (ex->fn_result) {
4602
+ leptris_xpath_result_free(ex->fn_result);
4603
+ ex->fn_result = NULL;
4604
+ }
4605
+ if (in->select) {
4606
+ ex->fn_result = xslt_eval(ex, in->select, node);
4607
+ } else if (in->child) {
4608
+ /* RTF capture (the op_variable pattern). Content results
4609
+ * are NODE-SETS (the fragment's document node) — value-of
4610
+ * contexts see the string value, copy-of copies the nodes
4611
+ * (EXSLT: bug-209 <result/>, bug-212 'a'). */
4612
+ LeptrisDocument main_result = ex->result;
4613
+ LeptrisElement saved = ex->pending_parent;
4614
+ ex->result = leptris_document_create();
4615
+ ex->pending_parent = NULL;
4616
+ ex->rtf_capturing = 1;
4617
+ ex->rtf_text_len = 0;
4618
+ xslt_exec_instrs(ex, in->child, node);
4619
+ ex->rtf_capturing = 0;
4620
+ ex->pending_parent = saved;
4621
+ LeptrisDocument frag_doc = ex->result;
4622
+ ex->result = main_result;
4623
+ LeptrisElement rr = leptris_document_root(frag_doc);
4624
+ if (!rr && ex->rtf_text && ex->rtf_text_len) {
4625
+ /* Pure-text RTF: the value is the string. */
4626
+ ex->fn_result = xpath_result_new(XPATH_RESULT_STRING);
4627
+ if (ex->fn_result)
4628
+ ex->fn_result->value.string_value =
4629
+ leptris_strdup(ex->rtf_text);
4630
+ leptris_document_free(frag_doc);
4631
+ } else {
4632
+ ex->fn_result = xpath_result_new(XPATH_RESULT_NODESET);
4633
+ if (ex->fn_result && rr) {
4634
+ ex->fn_result->value.nodeset_value = xpath_nodeset_new();
4635
+ if (ex->fn_result->value.nodeset_value) {
4636
+ LeptrisNodeRef dn = (LeptrisNodeRef)
4637
+ leptris_document_get_node(frag_doc);
4638
+ if (dn)
4639
+ xpath_nodeset_add(
4640
+ ex->fn_result->value.nodeset_value, dn);
4641
+ }
4642
+ }
4643
+ /* The nodeset's nodes live in frag_doc — move it into
4644
+ * the exec's RTF chain so they outlive the call. */
4645
+ if (rr) {
4646
+ struct xslt_rtf_entry* ent =
4647
+ (struct xslt_rtf_entry*)malloc(sizeof(*ent));
4648
+ if (ent) {
4649
+ ent->doc = frag_doc;
4650
+ ent->next = (struct xslt_rtf_entry*)ex->rtf_chain;
4651
+ ex->rtf_chain = ent;
4652
+ } else {
4653
+ leptris_document_free(frag_doc);
4654
+ }
4655
+ } else {
4656
+ leptris_document_free(frag_doc);
4657
+ }
4658
+ }
4659
+ }
4660
+ ex->fn_yield = 1;
4661
+ return 0;
4662
+ }
4663
+
4664
+ /* ---- The walker ---- */
4665
+
4666
+ int xslt_exec_instrs(XsltExec* ex, const XsltInstr* list,
4667
+ LeptrisElement node) {
4668
+ if (ex->terminated) return -1;
4669
+ if (ex->eval_error) return -1;
4670
+ /* §11 block scope: variables pushed while executing this
4671
+ * sequence pop when the sequence ends. Re-entrancy: nested
4672
+ * sequences snapshot their own mark. */
4673
+ XsltVar* scope_mark = ex->vars;
4674
+ int rc = 0;
4675
+ for (const XsltInstr* in = list; in; in = in->next) {
4676
+ if (ex->fn_yield) break; /* func:result unwinds to the call */
4677
+ if (ex->iterate_signal) break; /* next-iteration/break unwind
4678
+ * to the enclosing iterate */
4679
+ if (ex->eval_error) { rc = -1; break; }
4680
+ /* §11.6: xsl:param declarations are consumed by the invoker
4681
+ * (with-param binding or default evaluation) — not executed
4682
+ * as ordinary variables on the walk. */
4683
+ if (in->kind == XSLT_INSTR_VARIABLE && in->is_param) continue;
4684
+ LeptrisXPathNsSet saved_ns = ex->current_ns;
4685
+ ex->current_ns = in->ns;
4686
+ XsltInstrFn fn = g_ops[in->kind];
4687
+ if (fn) {
4688
+ rc = fn(ex, in, node);
4689
+ if (rc) { ex->current_ns = saved_ns; break; }
4690
+ } else if (in->kind == XSLT_INSTR_VARIABLE) {
4691
+ rc = op_variable(ex, in, node);
4692
+ if (rc) { ex->current_ns = saved_ns; break; }
4693
+ }
4694
+ ex->current_ns = saved_ns;
4695
+ }
4696
+ xslt_pop_vars_to(ex, scope_mark);
4697
+ return rc;
4698
+ }
4699
+
4700
+ /* CHOOSE execution needs its own scan; simplest correct wiring:
4701
+ * expose it through a WHEN handler that consults its siblings via
4702
+ * the walker order (see xslt_exec_choose below). */
4703
+
4704
+ static void register_ops(void) {
4705
+ static int done = 0;
4706
+ if (done) return;
4707
+ done = 1;
4708
+ g_ops[XSLT_INSTR_RESULT_ELEM] = op_result_elem;
4709
+ g_ops[XSLT_INSTR_TEXT] = op_text;
4710
+ g_ops[XSLT_INSTR_VALUE_OF] = op_value_of;
4711
+ g_ops[XSLT_INSTR_SEQUENCE] = op_sequence;
4712
+ g_ops[XSLT_INSTR_ON_NON_EMPTY] = op_on_non_empty;
4713
+ g_ops[XSLT_INSTR_WHERE_POPULATED] = op_where_populated;
4714
+ g_ops[XSLT_INSTR_NEXT_MATCH] = op_next_match;
4715
+ g_ops[XSLT_INSTR_FORK] = op_fork;
4716
+ g_ops[XSLT_INSTR_NAMESPACE] = op_namespace;
4717
+ g_ops[XSLT_INSTR_DOCUMENT] = op_document;
4718
+ g_ops[XSLT_INSTR_MERGE] = op_merge;
4719
+ g_ops[XSLT_INSTR_RESULT_DOCUMENT] = op_result_document;
4720
+ g_ops[XSLT_INSTR_FOR_EACH] = op_for_each;
4721
+ g_ops[XSLT_INSTR_ITERATE] = op_iterate;
4722
+ g_ops[XSLT_INSTR_NEXT_ITERATION] = op_next_iteration;
4723
+ g_ops[XSLT_INSTR_BREAK] = op_break;
4724
+ g_ops[XSLT_INSTR_FOR_EACH_GROUP] = op_for_each_group;
4725
+ g_ops[XSLT_INSTR_EVALUATE] = op_evaluate;
4726
+ g_ops[XSLT_INSTR_ANALYZE_STRING] = op_analyze_string;
4727
+ g_ops[XSLT_INSTR_TRY] = op_try;
4728
+ g_ops[XSLT_INSTR_IF] = op_if;
4729
+ g_ops[XSLT_INSTR_APPLY_TEMPLATES] = op_apply_templates;
4730
+ g_ops[XSLT_INSTR_CALL_TEMPLATE] = op_call_template;
4731
+ g_ops[XSLT_INSTR_COPY_OF] = op_copy_of;
4732
+ g_ops[XSLT_INSTR_COPY] = op_copy;
4733
+ g_ops[XSLT_INSTR_ELEMENT] = op_element;
4734
+ g_ops[XSLT_INSTR_ATTRIBUTE] = op_attribute;
4735
+ g_ops[XSLT_INSTR_COMMENT] = op_comment;
4736
+ g_ops[XSLT_INSTR_PI] = op_pi;
4737
+ g_ops[XSLT_INSTR_MESSAGE] = op_message;
4738
+ g_ops[XSLT_INSTR_NUMBER] = op_number;
4739
+ g_ops[XSLT_INSTR_CHOOSE] = op_choose;
4740
+ g_ops[XSLT_INSTR_ATTR_SET_REF] = op_attr_set_ref;
4741
+ g_ops[XSLT_INSTR_APPLY_IMPORTS] = op_apply_imports;
4742
+ g_ops[XSLT_INSTR_UNKNOWN_XSL] = op_unknown_xsl;
4743
+ g_ops[XSLT_INSTR_FUNC_RESULT] = op_func_result;
4744
+ }
4745
+
4746
+ /* ---- Public transform ---- */
4747
+
4748
+ void xslt_exec_free(XsltExec* ex) {
4749
+ if (!ex) return;
4750
+ if (ex->cache_owner_set) {
4751
+ xpath_ast_cache_owner_end(ex->cache_owner_prev);
4752
+ ex->cache_owner_set = 0;
4753
+ }
4754
+ if (ex->sbuf) { buffer_free(ex->sbuf); ex->sbuf = NULL; }
4755
+ xslt_keys_free(ex);
4756
+ xslt_accs_free(ex);
4757
+ xslt_docs_free(ex);
4758
+ xslt_bridge_free(ex);
4759
+ xslt_ufn_free(ex);
4760
+ xslt_gids_free(ex);
4761
+ xslt_avt_free(ex);
4762
+ if (ex->fn_result) leptris_xpath_result_free(ex->fn_result);
4763
+ while (ex->vars) xslt_pop_var(ex, NULL);
4764
+ while (ex->tunnel_vars) {
4765
+ XsltVar* t = ex->tunnel_vars;
4766
+ ex->tunnel_vars = t->prev;
4767
+ if (t->value) leptris_xpath_result_free(t->value);
4768
+ free(t);
4769
+ }
4770
+ while (ex->frag_nodes) {
4771
+ XsltFragNode* f = (XsltFragNode*)ex->frag_nodes;
4772
+ ex->frag_nodes = f->next;
4773
+ free(f);
4774
+ }
4775
+ free(ex->rtf_text);
4776
+ if (ex->varset) xpath_variable_set_free(ex->varset);
4777
+ while (ex->rtf_chain) {
4778
+ struct xslt_rtf_entry* ent = (struct xslt_rtf_entry*)ex->rtf_chain;
4779
+ ex->rtf_chain = ent->next;
4780
+ if (ent->doc) leptris_document_free(ent->doc);
4781
+ free(ent);
4782
+ }
4783
+ if (ex->scratch) leptris_document_free(ex->scratch);
4784
+ if (ex->result) leptris_document_free(ex->result);
4785
+ free(ex->message);
4786
+ free(ex);
4787
+ }
4788
+
4789
+ XsltExec* xslt_transform_doc(const XsltStylesheet* sheet,
4790
+ LeptrisDocument sheet_doc,
4791
+ LeptrisDocument source) {
4792
+ if (!sheet || !source) return NULL;
4793
+ register_ops();
4794
+
4795
+ XsltExec* ex = (XsltExec*)calloc(1, sizeof(*ex));
4796
+ if (!ex) return NULL;
4797
+ ex->sheet = sheet;
4798
+ ex->sheet_doc = sheet_doc; /* set BEFORE the body: document('') */
4799
+ ex->source = source;
4800
+ ex->current_pos = 1; /* §12.4: position() default context position */
4801
+ ex->current_size = 1; /* last() default context size */
4802
+ ex->result = leptris_document_create();
4803
+ if (!ex->result) { xslt_exec_free(ex); return NULL; }
4804
+ if (sheet->can_stream) {
4805
+ ex->sbuf = buffer_create(0);
4806
+ if (ex->sbuf) ex->streaming = 1;
4807
+ }
4808
+ /* #682 Phase 2: a single in-flight transform is single-threaded
4809
+ * — claim the XPath AST cache so per-eval get/release skip the
4810
+ * mutex (the heaviest hot-path pair in dispatch). */
4811
+ ex->cache_owner_prev = xpath_ast_cache_owner_begin();
4812
+ ex->cache_owner_set = 1;
4813
+
4814
+ /* Install the function-bridge state on the SOURCE document for
4815
+ * the transform's duration: every XPath eval on this doc (both
4816
+ * the VM path and the AST-interpreter path) builds its registry
4817
+ * through leptris_xpath_build_custom_registry, which registers
4818
+ * key()/current()/format-number()/... with `ex` as user_data
4819
+ * while xslt_state is set. Save/restore makes nesting safe.
4820
+ * The state pointer keys the doc's cached registry — drop the
4821
+ * cache so it rebuilds for this exec (and again on restore). */
4822
+ struct leptris_document* src_doc = (struct leptris_document*)source;
4823
+ void* saved_xslt_state = src_doc->xslt_state;
4824
+ leptris_xpath_invalidate_fn_registry(src_doc);
4825
+ src_doc->xslt_state = ex;
4826
+
4827
+
4828
+ /* §3.4: strip source whitespace before any template sees it. */
4829
+ /* Issue #606: libxslt's document loader applies ATTLIST defaults
4830
+ * (XML_PARSE_DTDATTR is on by default there), so stylesheet
4831
+ * processing always sees defaulted attributes — apply them at
4832
+ * the transform boundary regardless of how the caller parsed. */
4833
+ leptris_dtd_apply_attribute_defaults((struct leptris_document*)source);
4834
+
4835
+ strip_source_whitespace(ex);
4836
+
4837
+ /* Globals — each with its DECLARING element's namespace
4838
+ * context (included sheets bind their own prefixes, bug-36-).
4839
+ * §11: the select expression evaluates with the source
4840
+ * DOCUMENT node as context (relative paths resolve against the
4841
+ * source, bug-224). */
4842
+ LeptrisElement globals_ctx = (LeptrisElement)
4843
+ leptris_document_get_node((struct leptris_document*)source);
4844
+ for (const XsltInstr* g = sheet->globals; g; g = g->next) {
4845
+ if (g->kind == XSLT_INSTR_VARIABLE) {
4846
+ LeptrisXPathNsSet saved_gns = ex->current_ns;
4847
+ ex->current_ns = g->ns;
4848
+ op_variable(ex, g, globals_ctx);
4849
+ ex->current_ns = saved_gns;
4850
+ /* §11: a named template invoked while later globals are
4851
+ * still evaluating (bug-192: $template-value calls
4852
+ * get-dummy mid-loop) must see the globals bound so far —
4853
+ * keep the call-template reset point current instead of
4854
+ * leaving it NULL until the loop ends. */
4855
+ ex->global_vars = ex->vars;
4856
+ }
4857
+ }
4858
+ ex->global_vars = ex->vars; /* §11: the call-template reset point */
4859
+ if (!ex->terminated) {
4860
+
4861
+ /* Root invocation (§5.1): the context is the DOCUMENT node —
4862
+ * patterns match it via "/" only; other patterns never match
4863
+ * the root. No match → the built-in root rule (apply-templates
4864
+ * over the document's children). */
4865
+ {
4866
+ LeptrisElement dnode = (LeptrisElement)leptris_document_get_node(
4867
+ (struct leptris_document*)source);
4868
+ if (dnode) {
4869
+ const XsltTemplate* root_t =
4870
+ xslt_select_template(ex, dnode, NULL, 0);
4871
+ if (root_t) {
4872
+ xslt_invoke_template(ex, root_t, dnode, NULL);
4873
+ } else {
4874
+ op_apply_templates(
4875
+ ex,
4876
+ &(XsltInstr){ .kind = XSLT_INSTR_APPLY_TEMPLATES },
4877
+ dnode);
4878
+ }
4879
+ }
4880
+ }
4881
+ } /* !terminated */
4882
+
4883
+ src_doc->xslt_state = saved_xslt_state;
4884
+ leptris_xpath_invalidate_fn_registry(src_doc);
4885
+ return ex;
4886
+ }
4887
+