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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +23 -0
- data/Rakefile +52 -12
- data/ext/leptris/native/extconf.rb +85 -0
- data/ext/leptris/native/native.c +1 -1
- data/lib/leptris/version.rb +1 -1
- data/lib/leptris/xml/ffi.rb +13 -0
- data/lib/leptris/xml/native.so +0 -0
- data/vendor-src/libleptris/CHANGELOG.md +8080 -0
- data/vendor-src/libleptris/CLAUDE.md +150 -0
- data/vendor-src/libleptris/CMakeLists.txt +379 -0
- data/vendor-src/libleptris/CMakePresets.json +61 -0
- data/vendor-src/libleptris/CODE_OF_CONDUCT.md +132 -0
- data/vendor-src/libleptris/CONTEXT.md +49 -0
- data/vendor-src/libleptris/LICENSE.md +33 -0
- data/vendor-src/libleptris/README.adoc +1197 -0
- data/vendor-src/libleptris/TODO.assemble/README.md +16 -0
- data/vendor-src/libleptris/TODO.bindings/01-mutation-construction.md +18 -0
- data/vendor-src/libleptris/TODO.bindings/02-incremental-iterparse.md +15 -0
- data/vendor-src/libleptris/TODO.bindings/03-compiled-xpath.md +15 -0
- data/vendor-src/libleptris/TODO.bindings/04-pull-stax-api.md +14 -0
- data/vendor-src/libleptris/TODO.bindings/05-per-parse-options.md +17 -0
- data/vendor-src/libleptris/TODO.bindings/06-serialize-encoding-guarantees.md +14 -0
- data/vendor-src/libleptris/TODO.bindings/README.md +36 -0
- data/vendor-src/libleptris/TODO.concurrency/01-thread-safe-errors.md +19 -0
- data/vendor-src/libleptris/TODO.concurrency/02-export-surface-gate.md +24 -0
- data/vendor-src/libleptris/TODO.concurrency/03-mixed-nodeset-batch.md +14 -0
- data/vendor-src/libleptris/TODO.concurrency/04-canonical-status-message.md +13 -0
- data/vendor-src/libleptris/TODO.concurrency/05-windows-dll-name.md +10 -0
- data/vendor-src/libleptris/TODO.concurrency/06-exslt-pack.md +26 -0
- data/vendor-src/libleptris/TODO.concurrency/07-ns-set-pairs.md +11 -0
- data/vendor-src/libleptris/TODO.concurrency/08-threading-contract.md +45 -0
- data/vendor-src/libleptris/TODO.engine/01-file-sources.md +11 -0
- data/vendor-src/libleptris/TODO.engine/02-compiled-contexts.md +10 -0
- data/vendor-src/libleptris/TODO.engine/03-rust-publish.md +9 -0
- data/vendor-src/libleptris/TODO.engine/04-ruby-release-input.md +8 -0
- data/vendor-src/libleptris/TODO.engine/05-todo-md-refresh.md +7 -0
- data/vendor-src/libleptris/TODO.engine/README.md +16 -0
- data/vendor-src/libleptris/TODO.hygiene/README.md +15 -0
- data/vendor-src/libleptris/TODO.max-perf/00-INDEX.md +22 -0
- data/vendor-src/libleptris/TODO.max-perf/1-simd-html-scanner.md +15 -0
- data/vendor-src/libleptris/TODO.max-perf/10-moxml-plan-followups.md +9 -0
- data/vendor-src/libleptris/TODO.max-perf/2-compiled-dispatch-tokenizer.md +8 -0
- data/vendor-src/libleptris/TODO.max-perf/3-iterparse-fixed-cost.md +5 -0
- data/vendor-src/libleptris/TODO.max-perf/4-compact-node-micro-opts.md +17 -0
- data/vendor-src/libleptris/TODO.max-perf/5-xslt-bench-profiling-rounds.md +13 -0
- data/vendor-src/libleptris/TODO.max-perf/6-language-tails.md +9 -0
- data/vendor-src/libleptris/TODO.max-perf/7-validate-bindings.md +6 -0
- data/vendor-src/libleptris/TODO.max-perf/8-native-xml-diff-consumer.md +5 -0
- data/vendor-src/libleptris/TODO.max-perf/9-prebuilt-gem-matrix.md +14 -0
- data/vendor-src/libleptris/TODO.md +33 -0
- data/vendor-src/libleptris/TODO.transform/README.md +39 -0
- data/vendor-src/libleptris/TODO.validate/README.md +32 -0
- data/vendor-src/libleptris/TODO.xpath2/README.md +91 -0
- data/vendor-src/libleptris/TODO.xslt-full/01-xpath-fn-sequences.md +27 -0
- data/vendor-src/libleptris/TODO.xslt-full/02-xpath-fn-regex.md +13 -0
- data/vendor-src/libleptris/TODO.xslt-full/03-xpath-fn-math.md +10 -0
- data/vendor-src/libleptris/TODO.xslt-full/04-xpath-fn-strings-qname-uri.md +97 -0
- data/vendor-src/libleptris/TODO.xslt-full/05-xpath-fn-dates.md +30 -0
- data/vendor-src/libleptris/TODO.xslt-full/06-xpath-grammar-3x.md +83 -0
- data/vendor-src/libleptris/TODO.xslt-full/07-xpath-function-items.md +124 -0
- data/vendor-src/libleptris/TODO.xslt-full/08-xpath-maps-arrays.md +79 -0
- data/vendor-src/libleptris/TODO.xslt-full/09-xslt-noop-fillins.md +35 -0
- data/vendor-src/libleptris/TODO.xslt-full/10-xslt-tunnel-params.md +9 -0
- data/vendor-src/libleptris/TODO.xslt-full/11-xquery-core.md +119 -0
- data/vendor-src/libleptris/TODO.xslt-full/12-xquery-31.md +65 -0
- data/vendor-src/libleptris/TODO.xslt-full/13-perf-inprocess.md +425 -0
- data/vendor-src/libleptris/TODO.xslt-full/14-html-mode.md +803 -0
- data/vendor-src/libleptris/TODO.xslt-full/15-binding-entries.md +19 -0
- data/vendor-src/libleptris/TODO.xslt-full/16-schematron.md +156 -0
- data/vendor-src/libleptris/TODO.xslt-full/17-xml-diff.md +52 -0
- data/vendor-src/libleptris/TODO.xslt-full/18-compact-nodes.md +278 -0
- data/vendor-src/libleptris/TODO.xslt-full/README.md +26 -0
- data/vendor-src/libleptris/TODO.xslt-full/REMAINING.md +163 -0
- data/vendor-src/libleptris/TODO.xslt-full/legacy-v19/00-triage.md +171 -0
- data/vendor-src/libleptris/TODO.xslt-full/legacy-v19/01-fragment-nodes.md +19 -0
- data/vendor-src/libleptris/TODO.xslt-full/legacy-v19/02-root-node-semantics.md +34 -0
- data/vendor-src/libleptris/TODO.xslt-full/legacy-v19/03-crashes.md +15 -0
- data/vendor-src/libleptris/TODO.xslt-full/legacy-v19/04-namespaces.md +14 -0
- data/vendor-src/libleptris/TODO.xslt-full/legacy-v19/05-number-attrset-sort.md +13 -0
- data/vendor-src/libleptris/TODO.xslt-full/legacy-v19/06-document-chains.md +10 -0
- data/vendor-src/libleptris/TODO.xslt-full/legacy-v19/07-charef-serializer.md +9 -0
- data/vendor-src/libleptris/TODO.xslt-full/legacy-v19/08-perf-gate.md +8 -0
- data/vendor-src/libleptris/TODO.xslt-full/legacy-v19/09-release.md +14 -0
- data/vendor-src/libleptris/VALIDATION.md +151 -0
- data/vendor-src/libleptris/benchmarks/CMakeLists.txt +259 -0
- data/vendor-src/libleptris/benchmarks/README.adoc +228 -0
- data/vendor-src/libleptris/benchmarks/README.md +212 -0
- data/vendor-src/libleptris/benchmarks/common/benchmark.c +252 -0
- data/vendor-src/libleptris/benchmarks/common/benchmark.h +77 -0
- data/vendor-src/libleptris/benchmarks/common/test_data.c +415 -0
- data/vendor-src/libleptris/benchmarks/common/test_data.h +18 -0
- data/vendor-src/libleptris/benchmarks/comprehensive/CMakeLists.txt +184 -0
- data/vendor-src/libleptris/benchmarks/comprehensive/benchmark_decomp.cpp +110 -0
- data/vendor-src/libleptris/benchmarks/comprehensive/benchmark_first_access.cpp +261 -0
- data/vendor-src/libleptris/benchmarks/comprehensive/benchmark_many_attrs.cpp +150 -0
- data/vendor-src/libleptris/benchmarks/comprehensive/benchmark_memory.cpp +185 -0
- data/vendor-src/libleptris/benchmarks/comprehensive/benchmark_parse.cpp +270 -0
- data/vendor-src/libleptris/benchmarks/comprehensive/benchmark_parse_ops.cpp +392 -0
- data/vendor-src/libleptris/benchmarks/comprehensive/benchmark_sax.c +106 -0
- data/vendor-src/libleptris/benchmarks/comprehensive/benchmark_write.cpp +351 -0
- data/vendor-src/libleptris/benchmarks/data/attrs.xml +303 -0
- data/vendor-src/libleptris/benchmarks/data/cdata_test.xml +13 -0
- data/vendor-src/libleptris/benchmarks/data/comment_test.xml +15 -0
- data/vendor-src/libleptris/benchmarks/data/deep.xml +205 -0
- data/vendor-src/libleptris/benchmarks/data/generate_attrs.rb +22 -0
- data/vendor-src/libleptris/benchmarks/data/generate_deep.rb +25 -0
- data/vendor-src/libleptris/benchmarks/data/generate_large.rb +33 -0
- data/vendor-src/libleptris/benchmarks/data/generate_wide.rb +18 -0
- data/vendor-src/libleptris/benchmarks/data/large.xml +21003 -0
- data/vendor-src/libleptris/benchmarks/data/large_workflow.xml +4003 -0
- data/vendor-src/libleptris/benchmarks/data/medium.xml +67 -0
- data/vendor-src/libleptris/benchmarks/data/medium_workflow.xml +353 -0
- data/vendor-src/libleptris/benchmarks/data/pi_test.xml +9 -0
- data/vendor-src/libleptris/benchmarks/data/small.xml +10 -0
- data/vendor-src/libleptris/benchmarks/data/small_workflow.xml +36 -0
- data/vendor-src/libleptris/benchmarks/data/wide.xml +5003 -0
- data/vendor-src/libleptris/benchmarks/dom/bench_document_lifecycle.c +69 -0
- data/vendor-src/libleptris/benchmarks/dom/bench_leptris.c +184 -0
- data/vendor-src/libleptris/benchmarks/dom/bench_libxml2.c +176 -0
- data/vendor-src/libleptris/benchmarks/dom/bench_text_borrowed.c +74 -0
- data/vendor-src/libleptris/benchmarks/dom/dom_benchmark_v2.cpp +314 -0
- data/vendor-src/libleptris/benchmarks/fixtures/large.xml +4003 -0
- data/vendor-src/libleptris/benchmarks/fixtures/large_catalog.xml +50003 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2/eve.xml +6 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2/slashdot.rdf +66 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2/wap.xml +27 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/4rects.xml +11 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/a-valid.xml +10 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/a-wf.xml +9 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/bike.xml +41 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/circle.xml +11 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/defs.xml +14 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/desc.xml +14 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/ellipse.xml +10 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/flower2.xml +44 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/gradient.xml +16 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/group01.xml +15 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/group02.xml +13 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/group03.xml +13 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/image-valid.xml +11 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/image-wf.xml +11 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/lin-gradient.xml +16 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/marker.xml +28 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/mask.xml +13 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/mathswitch.xml +32 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/parentns.xml +12 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/path01.xml +5 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/path02.xml +10 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/patternfill.xml +12 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/polyline.xml +9 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/private.xml +19 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/rad-gradient.xml +17 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/rectangle.xml +10 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/richdesc.xml +12 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/script.xml +13 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/structure01.xml +10 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/style.xml +11 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/switch.xml +21 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/symbol-use.xml +28 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/template.xml +9 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/text01.xml +12 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/text02.xml +17 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/text03.xml +8 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/toap01.xml +10 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/toap02.xml +33 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/transform.xml +26 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/trivial.xml +6 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/twin-gradients.xml +19 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/v-template.xml +9 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/viewport-nest.xml +13 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/viewport-transform.xml +46 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/viewport.xml +11 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_svg/wf-template.xml +7 -0
- data/vendor-src/libleptris/benchmarks/fixtures/libxml2_xsdtest.xml +5286 -0
- data/vendor-src/libleptris/benchmarks/fixtures/medium.xml +403 -0
- data/vendor-src/libleptris/benchmarks/fixtures/medium_catalog.xml +3003 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml/empty.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml/large.xml +1 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml/latintest_latin1.xml +1 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml/latintest_utf8.xml +1 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml/multiline.xml +3 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml/small.xml +1 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml/truncation.xml +19 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf16_be.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf16_be_bom.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf16_be_clean.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf16_be_nodecl.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf16_le.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf16_le_bom.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf16_le_clean.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf16_le_nodecl.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf32_be.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf32_be_bom.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf32_be_clean.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf32_be_nodecl.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf32_le.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf32_le_bom.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf32_le_clean.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf32_le_nodecl.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf8.xml +87 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf8_bom.xml +87 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf8_clean.xml +84 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml/utftest_utf8_nodecl.xml +86 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml//321/202/320/265/321/201/321/202.xml +1 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/empty.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/large.xml +1 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/latintest_latin1.xml +1 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/latintest_utf8.xml +1 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/multiline.xml +3 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/small.xml +1 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/truncation.xml +19 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf16_be.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf16_be_bom.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf16_be_clean.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf16_be_nodecl.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf16_le.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf16_le_bom.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf16_le_clean.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf16_le_nodecl.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf32_be.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf32_be_bom.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf32_be_clean.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf32_be_nodecl.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf32_le.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf32_le_bom.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf32_le_clean.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf32_le_nodecl.xml +0 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf8.xml +87 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf8_bom.xml +87 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf8_clean.xml +84 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests/utftest_utf8_nodecl.xml +86 -0
- data/vendor-src/libleptris/benchmarks/fixtures/pugixml_tests//321/202/320/265/321/201/321/202.xml +1 -0
- data/vendor-src/libleptris/benchmarks/fixtures/small.xml +38 -0
- data/vendor-src/libleptris/benchmarks/html/bench_html_parse.c +111 -0
- data/vendor-src/libleptris/benchmarks/html/gen_nokogiri_reference.rb +112 -0
- data/vendor-src/libleptris/benchmarks/html/nokogiri_html_parse.rb +64 -0
- data/vendor-src/libleptris/benchmarks/matrix/README.md +71 -0
- data/vendor-src/libleptris/benchmarks/matrix/bench2html.rb +316 -0
- data/vendor-src/libleptris/benchmarks/matrix/bench_matrix.cpp +724 -0
- data/vendor-src/libleptris/benchmarks/modification/bench_leptris_modify.c +211 -0
- data/vendor-src/libleptris/benchmarks/modification/bench_node_creation.c +130 -0
- data/vendor-src/libleptris/benchmarks/results/BENCHMARK_REPORT.md +226 -0
- data/vendor-src/libleptris/benchmarks/results/baseline_report.md +219 -0
- data/vendor-src/libleptris/benchmarks/results/benchmark_20251223_134550.json +13 -0
- data/vendor-src/libleptris/benchmarks/results/benchmark_20260129_225844.json +13 -0
- data/vendor-src/libleptris/benchmarks/results/leptris_dom_output.txt +24 -0
- data/vendor-src/libleptris/benchmarks/results/leptris_modify.json +36 -0
- data/vendor-src/libleptris/benchmarks/results/leptris_modify_optimized.json +36 -0
- data/vendor-src/libleptris/benchmarks/results/leptris_modify_session1.json +36 -0
- data/vendor-src/libleptris/benchmarks/results/leptris_modify_session2.json +36 -0
- data/vendor-src/libleptris/benchmarks/results/leptris_serialize.json +34 -0
- data/vendor-src/libleptris/benchmarks/results/leptris_xpath_output.txt +24 -0
- data/vendor-src/libleptris/benchmarks/results/libxml2_dom_output.txt +24 -0
- data/vendor-src/libleptris/benchmarks/results/libxml2_xpath_output.txt +24 -0
- data/vendor-src/libleptris/benchmarks/results/phase16_session2.json +21 -0
- data/vendor-src/libleptris/benchmarks/results/phase17.5_session1.json +30 -0
- data/vendor-src/libleptris/benchmarks/results/phase17_session1.json +30 -0
- data/vendor-src/libleptris/benchmarks/results/pugixml_dom_output.txt +51 -0
- data/vendor-src/libleptris/benchmarks/results/xpath_axes_leptris.json +318 -0
- data/vendor-src/libleptris/benchmarks/results/xpath_axes_libxml2.json +318 -0
- data/vendor-src/libleptris/benchmarks/results/xpath_functions_leptris.json +222 -0
- data/vendor-src/libleptris/benchmarks/results/xpath_functions_libxml2.json +222 -0
- data/vendor-src/libleptris/benchmarks/sax/bench_iterparse.c +115 -0
- data/vendor-src/libleptris/benchmarks/sax/bench_leptris.c +124 -0
- data/vendor-src/libleptris/benchmarks/sax/bench_libxml2.c +115 -0
- data/vendor-src/libleptris/benchmarks/serialization/bench_leptris_serialize.c +198 -0
- data/vendor-src/libleptris/benchmarks/src/benchmark_base.h +175 -0
- data/vendor-src/libleptris/benchmarks/twins/mutation_leptris.c +37 -0
- data/vendor-src/libleptris/benchmarks/twins/mutation_pugixml.cpp +28 -0
- data/vendor-src/libleptris/benchmarks/twins/parse_leptris.c +35 -0
- data/vendor-src/libleptris/benchmarks/twins/parse_pugixml.cpp +35 -0
- data/vendor-src/libleptris/benchmarks/utils.c +171 -0
- data/vendor-src/libleptris/benchmarks/utils.h +70 -0
- data/vendor-src/libleptris/benchmarks/workflows/bench_dom_modify.c +325 -0
- data/vendor-src/libleptris/benchmarks/workflows/bench_end_to_end.c +529 -0
- data/vendor-src/libleptris/benchmarks/xpath/bench_axes.c +411 -0
- data/vendor-src/libleptris/benchmarks/xpath/bench_axes_libxml2.c +108 -0
- data/vendor-src/libleptris/benchmarks/xpath/bench_diagnostic.c +431 -0
- data/vendor-src/libleptris/benchmarks/xpath/bench_functions.c +271 -0
- data/vendor-src/libleptris/benchmarks/xpath/bench_functions_libxml2.c +123 -0
- data/vendor-src/libleptris/benchmarks/xpath/bench_leptris.c +78 -0
- data/vendor-src/libleptris/benchmarks/xpath/bench_libxml2.c +98 -0
- data/vendor-src/libleptris/benchmarks/xpath/bench_pugixml.cpp +117 -0
- data/vendor-src/libleptris/benchmarks/xpath/bench_scalar_eval.c +86 -0
- data/vendor-src/libleptris/benchmarks/xpath/bench_scalar_eval_libxml2.c +70 -0
- data/vendor-src/libleptris/benchmarks/xpath/bench_xslt_transform.c +48 -0
- data/vendor-src/libleptris/benchmarks/xslt/bench_dispatch.c +52 -0
- data/vendor-src/libleptris/benchmarks/xslt/bench_dispatch_heavy.c +82 -0
- data/vendor-src/libleptris/benchmarks/xslt/bench_dispatch_pred.c +34 -0
- data/vendor-src/libleptris/benchmarks/xslt/bench_subtree_copy.c +55 -0
- data/vendor-src/libleptris/benchmarks/xslt/bench_valueof.c +46 -0
- data/vendor-src/libleptris/benchmarks/xslt/heavy_lxml.py +48 -0
- data/vendor-src/libleptris/benchmarks/xslt/scorecard_lxml.py +169 -0
- data/vendor-src/libleptris/bindings/ruby/leptris.gemspec +22 -0
- data/vendor-src/libleptris/bindings/ruby/lib/leptris/document.rb +60 -0
- data/vendor-src/libleptris/bindings/ruby/lib/leptris/element.rb +86 -0
- data/vendor-src/libleptris/bindings/ruby/lib/leptris/error.rb +6 -0
- data/vendor-src/libleptris/bindings/ruby/lib/leptris/node.rb +73 -0
- data/vendor-src/libleptris/bindings/ruby/lib/leptris/sax.rb +189 -0
- data/vendor-src/libleptris/bindings/ruby/lib/leptris/xpath.rb +44 -0
- data/vendor-src/libleptris/bindings/ruby/lib/leptris.rb +137 -0
- data/vendor-src/libleptris/bindings/ruby/spec/leptris_spec.rb +113 -0
- data/vendor-src/libleptris/bindings/ruby/spec/sax_spec.rb +141 -0
- data/vendor-src/libleptris/bindings/ruby/spec/spec_helper.rb +7 -0
- data/vendor-src/libleptris/bindings/ruby/test_full.rb +21 -0
- data/vendor-src/libleptris/bindings/rust/Cargo.lock +7 -0
- data/vendor-src/libleptris/bindings/rust/Cargo.toml +13 -0
- data/vendor-src/libleptris/bindings/rust/README.md +61 -0
- data/vendor-src/libleptris/bindings/rust/build.rs +74 -0
- data/vendor-src/libleptris/bindings/rust/src/ffi.rs +204 -0
- data/vendor-src/libleptris/bindings/rust/src/lib.rs +580 -0
- data/vendor-src/libleptris/bindings/rust/tests/integration.rs +156 -0
- data/vendor-src/libleptris/cli/ARCHITECTURE_REVIEW.md +514 -0
- data/vendor-src/libleptris/cli/CLI_ARCHITECTURE.md +851 -0
- data/vendor-src/libleptris/cli/CMakeLists.txt +46 -0
- data/vendor-src/libleptris/cli/cli.c +115 -0
- data/vendor-src/libleptris/cli/cli.h +232 -0
- data/vendor-src/libleptris/cli/commands/diff.c +208 -0
- data/vendor-src/libleptris/cli/commands/format.c +379 -0
- data/vendor-src/libleptris/cli/commands/parse.c +343 -0
- data/vendor-src/libleptris/cli/commands/validate.c +284 -0
- data/vendor-src/libleptris/cli/commands/version.c +49 -0
- data/vendor-src/libleptris/cli/commands/xpath.c +428 -0
- data/vendor-src/libleptris/cli/commands/xquery.c +188 -0
- data/vendor-src/libleptris/cli/completion/leptris.bash +86 -0
- data/vendor-src/libleptris/cli/completion/leptris.zsh +74 -0
- data/vendor-src/libleptris/cli/error.c +394 -0
- data/vendor-src/libleptris/cli/error.h +360 -0
- data/vendor-src/libleptris/cli/leptris +0 -0
- data/vendor-src/libleptris/cli/main.c +127 -0
- data/vendor-src/libleptris/cli/man/leptris-format.1.adoc +226 -0
- data/vendor-src/libleptris/cli/man/leptris-parse.1.adoc +213 -0
- data/vendor-src/libleptris/cli/man/leptris-xpath.1.adoc +479 -0
- data/vendor-src/libleptris/cli/man/leptris.1.adoc +192 -0
- data/vendor-src/libleptris/cli/options.c +451 -0
- data/vendor-src/libleptris/cli/options.h +378 -0
- data/vendor-src/libleptris/cli/output.c +841 -0
- data/vendor-src/libleptris/cli/output.h +361 -0
- data/vendor-src/libleptris/cmake/FindUtf8proc.cmake +56 -0
- data/vendor-src/libleptris/cmake/leptris-config.cmake.in +14 -0
- data/vendor-src/libleptris/cmake/leptris.pc.in +11 -0
- data/vendor-src/libleptris/cmake/modules/AdocMan.cmake +132 -0
- data/vendor-src/libleptris/docs/ARCHITECTURE_REVIEW.md +280 -0
- data/vendor-src/libleptris/docs/Doxyfile +47 -0
- data/vendor-src/libleptris/docs/FFI.md +165 -0
- data/vendor-src/libleptris/docs/README.md +47 -0
- data/vendor-src/libleptris/docs/ROADMAP-SAXON-PARITY.md +194 -0
- data/vendor-src/libleptris/docs/guide/building.md +199 -0
- data/vendor-src/libleptris/docs/guide/getting-started.md +134 -0
- data/vendor-src/libleptris/docs/guide/parsing.md +315 -0
- data/vendor-src/libleptris/docs/guide/xpath-queries.md +444 -0
- data/vendor-src/libleptris/examples/c/CMakeLists.txt +58 -0
- data/vendor-src/libleptris/examples/c/README.md +345 -0
- data/vendor-src/libleptris/examples/c/basic_example.c +80 -0
- data/vendor-src/libleptris/examples/c/dom_traversal_example.c +58 -0
- data/vendor-src/libleptris/examples/c/error_handling_example.c +121 -0
- data/vendor-src/libleptris/examples/c/namespace_example.c +49 -0
- data/vendor-src/libleptris/examples/c/xpath_example.c +74 -0
- data/vendor-src/libleptris/ports/leptris/portfile.cmake +41 -0
- data/vendor-src/libleptris/ports/leptris/usage +28 -0
- data/vendor-src/libleptris/scripts/check_dll_exports.py +54 -0
- data/vendor-src/libleptris/scripts/check_export_surface.py +84 -0
- data/vendor-src/libleptris/scripts/check_ffi_mirrors.py +163 -0
- data/vendor-src/libleptris/scripts/check_formatting.sh +30 -0
- data/vendor-src/libleptris/scripts/check_shared_exports.sh +120 -0
- data/vendor-src/libleptris/scripts/check_trailing_whitespace.sh +18 -0
- data/vendor-src/libleptris/scripts/gen-api-docs.sh +31 -0
- data/vendor-src/libleptris/scripts/run_static_analysis.sh +16 -0
- data/vendor-src/libleptris/scripts/validate.sh +199 -0
- data/vendor-src/libleptris/scripts/xslt_triage.sh +72 -0
- data/vendor-src/libleptris/src/CMakeLists.txt +597 -0
- data/vendor-src/libleptris/src/include/leptris/descriptor.h +178 -0
- data/vendor-src/libleptris/src/include/leptris/dom/document.h +213 -0
- data/vendor-src/libleptris/src/include/leptris/dom/element.h +435 -0
- data/vendor-src/libleptris/src/include/leptris/dom/serialize.h +133 -0
- data/vendor-src/libleptris/src/include/leptris/dtd.h +178 -0
- data/vendor-src/libleptris/src/include/leptris/error.h +97 -0
- data/vendor-src/libleptris/src/include/leptris/sax/sax.h +584 -0
- data/vendor-src/libleptris/src/include/leptris/types.h +386 -0
- data/vendor-src/libleptris/src/include/leptris/xpath/xpath.h +250 -0
- data/vendor-src/libleptris/src/include/leptris/xquery/xquery.h +80 -0
- data/vendor-src/libleptris/src/include/leptris.h +3701 -0
- data/vendor-src/libleptris/src/leptris/chartype.h +124 -0
- data/vendor-src/libleptris/src/leptris/common/chartype.c +90 -0
- data/vendor-src/libleptris/src/leptris/common/chartype.h +44 -0
- data/vendor-src/libleptris/src/leptris/common/cpu.c +40 -0
- data/vendor-src/libleptris/src/leptris/common/cpu.h +63 -0
- data/vendor-src/libleptris/src/leptris/common/entities.c +329 -0
- data/vendor-src/libleptris/src/leptris/common/entities.h +79 -0
- data/vendor-src/libleptris/src/leptris/common/format_number.c +273 -0
- data/vendor-src/libleptris/src/leptris/common/format_number.h +29 -0
- data/vendor-src/libleptris/src/leptris/common/port.h +171 -0
- data/vendor-src/libleptris/src/leptris/common/simd_text.c +237 -0
- data/vendor-src/libleptris/src/leptris/common/simd_text.h +104 -0
- data/vendor-src/libleptris/src/leptris/common/simd_text_avx2.c +105 -0
- data/vendor-src/libleptris/src/leptris/common/simd_text_neon.c +280 -0
- data/vendor-src/libleptris/src/leptris/common/string_view.c +204 -0
- data/vendor-src/libleptris/src/leptris/common/string_view.h +68 -0
- data/vendor-src/libleptris/src/leptris/common/types_internal.h +31 -0
- data/vendor-src/libleptris/src/leptris/core.c +201 -0
- data/vendor-src/libleptris/src/leptris/descriptor/plan.c +527 -0
- data/vendor-src/libleptris/src/leptris/diff/diff.c +491 -0
- data/vendor-src/libleptris/src/leptris/dom/cdata.c +47 -0
- data/vendor-src/libleptris/src/leptris/dom/cdata.h +73 -0
- data/vendor-src/libleptris/src/leptris/dom/comment.c +48 -0
- data/vendor-src/libleptris/src/leptris/dom/comment.h +74 -0
- data/vendor-src/libleptris/src/leptris/dom/compact.c +397 -0
- data/vendor-src/libleptris/src/leptris/dom/compact.h +307 -0
- data/vendor-src/libleptris/src/leptris/dom/diag.c +58 -0
- data/vendor-src/libleptris/src/leptris/dom/diag.h +75 -0
- data/vendor-src/libleptris/src/leptris/dom/digest.c +255 -0
- data/vendor-src/libleptris/src/leptris/dom/doctype.c +137 -0
- data/vendor-src/libleptris/src/leptris/dom/doctype.h +52 -0
- data/vendor-src/libleptris/src/leptris/dom/document_node.c +13 -0
- data/vendor-src/libleptris/src/leptris/dom/document_node.h +21 -0
- data/vendor-src/libleptris/src/leptris/dom/edges.h +60 -0
- data/vendor-src/libleptris/src/leptris/dom/element.c +1114 -0
- data/vendor-src/libleptris/src/leptris/dom/element.h +1109 -0
- data/vendor-src/libleptris/src/leptris/dom/element_index.c +444 -0
- data/vendor-src/libleptris/src/leptris/dom/element_index.h +135 -0
- data/vendor-src/libleptris/src/leptris/dom/element_modify.c +2185 -0
- data/vendor-src/libleptris/src/leptris/dom/element_query.c +1468 -0
- data/vendor-src/libleptris/src/leptris/dom/entity_ref.c +57 -0
- data/vendor-src/libleptris/src/leptris/dom/entity_ref.h +70 -0
- data/vendor-src/libleptris/src/leptris/dom/node.c +420 -0
- data/vendor-src/libleptris/src/leptris/dom/node.h +170 -0
- data/vendor-src/libleptris/src/leptris/dom/node_public.c +937 -0
- data/vendor-src/libleptris/src/leptris/dom/node_vtable.c +138 -0
- data/vendor-src/libleptris/src/leptris/dom/pi.c +70 -0
- data/vendor-src/libleptris/src/leptris/dom/pi.h +80 -0
- data/vendor-src/libleptris/src/leptris/dom/root_doc_map.c +310 -0
- data/vendor-src/libleptris/src/leptris/dom/root_doc_map.h +30 -0
- data/vendor-src/libleptris/src/leptris/dom/text.c +157 -0
- data/vendor-src/libleptris/src/leptris/dom/text.h +119 -0
- data/vendor-src/libleptris/src/leptris/dtd/content_check.c +300 -0
- data/vendor-src/libleptris/src/leptris/dtd/model.c +533 -0
- data/vendor-src/libleptris/src/leptris/dtd/model.h +354 -0
- data/vendor-src/libleptris/src/leptris/dtd/parser.c +827 -0
- data/vendor-src/libleptris/src/leptris/dtd/resolver.c +354 -0
- data/vendor-src/libleptris/src/leptris/dtd/validator.c +668 -0
- data/vendor-src/libleptris/src/leptris/encoding/encoders.c +346 -0
- data/vendor-src/libleptris/src/leptris/encoding/encoders.h +61 -0
- data/vendor-src/libleptris/src/leptris/encoding/encoding.c +451 -0
- data/vendor-src/libleptris/src/leptris/encoding/encoding.h +118 -0
- data/vendor-src/libleptris/src/leptris/encoding/unicode.c +317 -0
- data/vendor-src/libleptris/src/leptris/encoding/unicode.h +64 -0
- data/vendor-src/libleptris/src/leptris/encoding/utf16.c +204 -0
- data/vendor-src/libleptris/src/leptris/encoding/utf16.h +78 -0
- data/vendor-src/libleptris/src/leptris/encoding/wrapper.c +243 -0
- data/vendor-src/libleptris/src/leptris/error.c +134 -0
- data/vendor-src/libleptris/src/leptris/flat/direct_parse.c +1935 -0
- data/vendor-src/libleptris/src/leptris/flat/direct_parse.h +41 -0
- data/vendor-src/libleptris/src/leptris/html/html_parse.c +8040 -0
- data/vendor-src/libleptris/src/leptris/leptris.c +1264 -0
- data/vendor-src/libleptris/src/leptris/leptris_internal.h +910 -0
- data/vendor-src/libleptris/src/leptris/leptris_memory.c +179 -0
- data/vendor-src/libleptris/src/leptris/leptris_memory.h +180 -0
- data/vendor-src/libleptris/src/leptris/leptris_parse.h +195 -0
- data/vendor-src/libleptris/src/leptris/memory/arena.c +243 -0
- data/vendor-src/libleptris/src/leptris/memory/arena.h +93 -0
- data/vendor-src/libleptris/src/leptris/memory/pool.c +1055 -0
- data/vendor-src/libleptris/src/leptris/memory/pool.h +426 -0
- data/vendor-src/libleptris/src/leptris/rng/parse.c +814 -0
- data/vendor-src/libleptris/src/leptris/rng/rng_internal.h +112 -0
- data/vendor-src/libleptris/src/leptris/rng/rng_public.c +159 -0
- data/vendor-src/libleptris/src/leptris/rng/rng_regex.c +453 -0
- data/vendor-src/libleptris/src/leptris/rng/validate.c +1923 -0
- data/vendor-src/libleptris/src/leptris/sax/iterparse.c +435 -0
- data/vendor-src/libleptris/src/leptris/sax/parser.c +105 -0
- data/vendor-src/libleptris/src/leptris/sax/pull.c +489 -0
- data/vendor-src/libleptris/src/leptris/sax/recorder.c +252 -0
- data/vendor-src/libleptris/src/leptris/sax/sax_internal.h +163 -0
- data/vendor-src/libleptris/src/leptris/sax/streaming.c +1469 -0
- data/vendor-src/libleptris/src/leptris/sch/schematron.c +1588 -0
- data/vendor-src/libleptris/src/leptris/serialize/c14n.c +1143 -0
- data/vendor-src/libleptris/src/leptris/serialize/serialize.c +2333 -0
- data/vendor-src/libleptris/src/leptris/serialize/serialize.h +188 -0
- data/vendor-src/libleptris/src/leptris/simd_helpers.h +447 -0
- data/vendor-src/libleptris/src/leptris/unicode/unicode.c +237 -0
- data/vendor-src/libleptris/src/leptris/unicode/unicode.h +113 -0
- data/vendor-src/libleptris/src/leptris/xinclude/xinclude.c +794 -0
- data/vendor-src/libleptris/src/leptris/xpath/bytecode.h +229 -0
- data/vendor-src/libleptris/src/leptris/xpath/compiler.c +1478 -0
- data/vendor-src/libleptris/src/leptris/xpath/evaluator.c +1099 -0
- data/vendor-src/libleptris/src/leptris/xpath/evaluator.h +189 -0
- data/vendor-src/libleptris/src/leptris/xpath/evaluator_axes.c +787 -0
- data/vendor-src/libleptris/src/leptris/xpath/evaluator_internal.h +112 -0
- data/vendor-src/libleptris/src/leptris/xpath/evaluator_operators.c +2138 -0
- data/vendor-src/libleptris/src/leptris/xpath/evaluator_path.c +1312 -0
- data/vendor-src/libleptris/src/leptris/xpath/evaluator_types.c +294 -0
- data/vendor-src/libleptris/src/leptris/xpath/functions.c +2544 -0
- data/vendor-src/libleptris/src/leptris/xpath/functions.h +161 -0
- data/vendor-src/libleptris/src/leptris/xpath/functions_exslt.c +545 -0
- data/vendor-src/libleptris/src/leptris/xpath/functions_ext31.c +4316 -0
- data/vendor-src/libleptris/src/leptris/xpath/lexer.c +636 -0
- data/vendor-src/libleptris/src/leptris/xpath/lexer.h +25 -0
- data/vendor-src/libleptris/src/leptris/xpath/parser.c +2992 -0
- data/vendor-src/libleptris/src/leptris/xpath/parser.h +28 -0
- data/vendor-src/libleptris/src/leptris/xpath/vm.c +2903 -0
- data/vendor-src/libleptris/src/leptris/xpath/xpath_ast_cache.c +319 -0
- data/vendor-src/libleptris/src/leptris/xpath/xpath_compiled.c +263 -0
- data/vendor-src/libleptris/src/leptris/xpath/xpath_internal.h +134 -0
- data/vendor-src/libleptris/src/leptris/xpath/xpath_public.c +1139 -0
- data/vendor-src/libleptris/src/leptris/xpath/xpath_variables.c +410 -0
- data/vendor-src/libleptris/src/leptris/xpath/xpath_variables.h +230 -0
- data/vendor-src/libleptris/src/leptris/xquery/xquery.c +2641 -0
- data/vendor-src/libleptris/src/leptris/xslt/xslt_exec.c +4887 -0
- data/vendor-src/libleptris/src/leptris/xslt/xslt_functions.c +1612 -0
- data/vendor-src/libleptris/src/leptris/xslt/xslt_internal.h +862 -0
- data/vendor-src/libleptris/src/leptris/xslt/xslt_parse.c +2418 -0
- data/vendor-src/libleptris/src/leptris/xslt/xslt_pattern.c +441 -0
- data/vendor-src/libleptris/src/leptris/xslt/xslt_public.c +710 -0
- data/vendor-src/libleptris/src/leptris.symvers +16 -0
- data/vendor-src/libleptris/src/man/libleptris.5.adoc +961 -0
- data/vendor-src/libleptris/test/CMakeLists.txt +234 -0
- data/vendor-src/libleptris/test/README.md +59 -0
- data/vendor-src/libleptris/test/abi/test_descriptor.cpp +441 -0
- data/vendor-src/libleptris/test/abi/test_doctype_api.cpp +51 -0
- data/vendor-src/libleptris/test/abi/test_dom_deep_copy.cpp +110 -0
- data/vendor-src/libleptris/test/abi/test_dom_mutation_bugs.cpp +210 -0
- data/vendor-src/libleptris/test/abi/test_header_hygiene.cpp +269 -0
- data/vendor-src/libleptris/test/abi/test_namespace_mutation_and_create.cpp +198 -0
- data/vendor-src/libleptris/test/abi/test_node_get_xpath.cpp +128 -0
- data/vendor-src/libleptris/test/abi/test_nokogiri_api.cpp +392 -0
- data/vendor-src/libleptris/test/abi/test_parse_fragment.cpp +114 -0
- data/vendor-src/libleptris/test/abi/test_previous_sibling_and_c14n_ex.cpp +299 -0
- data/vendor-src/libleptris/test/abi/test_public_surface.cpp +463 -0
- data/vendor-src/libleptris/test/abi/test_serialize_abi.cpp +67 -0
- data/vendor-src/libleptris/test/abi/test_v0_5_14_bugs.cpp +299 -0
- data/vendor-src/libleptris/test/abi/test_xpath_custom_fns.cpp +106 -0
- data/vendor-src/libleptris/test/cli/test_cli.cpp +493 -0
- data/vendor-src/libleptris/test/common/test_simd_spans.cpp +88 -0
- data/vendor-src/libleptris/test/common/test_simd_text.cpp +142 -0
- data/vendor-src/libleptris/test/concurrency/test_concurrency.cpp +218 -0
- data/vendor-src/libleptris/test/diff/test_diff.cpp +244 -0
- data/vendor-src/libleptris/test/dom/test_compact.cpp +339 -0
- data/vendor-src/libleptris/test/dom/test_digest.cpp +111 -0
- data/vendor-src/libleptris/test/dom/test_document_children.cpp +270 -0
- data/vendor-src/libleptris/test/dom/test_dom.cpp +2310 -0
- data/vendor-src/libleptris/test/dom/test_map_lifecycle.cpp +111 -0
- data/vendor-src/libleptris/test/dom/test_node_surface_parity.cpp +268 -0
- data/vendor-src/libleptris/test/dom/test_text_borrowed.cpp +126 -0
- data/vendor-src/libleptris/test/dom/test_vtable.cpp +108 -0
- data/vendor-src/libleptris/test/dtd/test_dtd_validate.cpp +1227 -0
- data/vendor-src/libleptris/test/dtd/test_w3c_conformance.cpp +212 -0
- data/vendor-src/libleptris/test/fixtures/basic.xml +13 -0
- data/vendor-src/libleptris/test/fixtures/cdata.xml +5 -0
- data/vendor-src/libleptris/test/fixtures/malformed.xml +2 -0
- data/vendor-src/libleptris/test/fixtures/namespaces.xml +11 -0
- data/vendor-src/libleptris/test/fixtures/utf16_decl.xml +5 -0
- data/vendor-src/libleptris/test/fuzz/fuzz_parse.c +40 -0
- data/vendor-src/libleptris/test/html/html5lib-redlist.txt +1366 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/LICENSE +21 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/README.md +11 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/adoption01.dat +354 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/adoption02.dat +39 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/blocks.dat +695 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/comments01.dat +217 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/doctype01.dat +474 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/domjs-unsafe.dat +0 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/entities01.dat +943 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/entities02.dat +309 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/foreign-fragment.dat +645 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/html5test-com.dat +301 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/inbody01.dat +54 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/isindex.dat +49 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/main-element.dat +46 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/math.dat +104 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/menuitem-element.dat +240 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/namespace-sensitivity.dat +22 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/noscript01.dat +237 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/pending-spec-changes-plain-text-unsafe.dat +0 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/pending-spec-changes.dat +46 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/plain-text-unsafe.dat +0 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/ruby.dat +302 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/scriptdata01.dat +372 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/search-element.dat +46 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/svg.dat +104 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tables01.dat +308 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/template.dat +1673 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests1.dat +1956 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests10.dat +849 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests11.dat +523 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests12.dat +62 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests14.dat +75 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests15.dat +216 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests16.dat +2602 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests17.dat +179 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests18.dat +558 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests19.dat +1398 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests2.dat +821 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests20.dat +842 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests21.dat +306 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests22.dat +190 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests23.dat +168 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests24.dat +79 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests25.dat +288 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests26.dat +453 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests3.dat +305 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests4.dat +58 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests5.dat +210 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests6.dat +663 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests7.dat +417 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests8.dat +165 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests9.dat +472 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tests_innerHTML_1.dat +843 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/tricky01.dat +336 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/webkit01.dat +785 -0
- data/vendor-src/libleptris/test/html/html5lib-tests/tree-construction/webkit02.dat +554 -0
- data/vendor-src/libleptris/test/html/html5lib_cases.h.in +6 -0
- data/vendor-src/libleptris/test/html/nokogiri-parity-redlist.txt +1183 -0
- data/vendor-src/libleptris/test/html/nokogiri-tree-tests.dat +18107 -0
- data/vendor-src/libleptris/test/html/test_html.cpp +2191 -0
- data/vendor-src/libleptris/test/html/test_html5lib.cpp +831 -0
- data/vendor-src/libleptris/test/memory/test_arena.cpp +252 -0
- data/vendor-src/libleptris/test/memory/test_oom_injection.cpp +170 -0
- data/vendor-src/libleptris/test/memory/test_pool.cpp +331 -0
- data/vendor-src/libleptris/test/memory/test_pool_arena.cpp +180 -0
- data/vendor-src/libleptris/test/parser/test_encoding.cpp +282 -0
- data/vendor-src/libleptris/test/parser/test_large_documents.cpp +346 -0
- data/vendor-src/libleptris/test/parser/test_parser.cpp +565 -0
- data/vendor-src/libleptris/test/parser/test_simd_count.cpp +70 -0
- data/vendor-src/libleptris/test/perf/test_perf.cpp +362 -0
- data/vendor-src/libleptris/test/perf/test_stress_high_doc_count.cpp +67 -0
- data/vendor-src/libleptris/test/rng/include-cases/bad-construct.rng +7 -0
- data/vendor-src/libleptris/test/rng/include-cases/bad-override.rng +6 -0
- data/vendor-src/libleptris/test/rng/include-cases/bad-start-override.rng +5 -0
- data/vendor-src/libleptris/test/rng/include-cases/ext-lib.rng +3 -0
- data/vendor-src/libleptris/test/rng/include-cases/ext-main.rng +7 -0
- data/vendor-src/libleptris/test/rng/include-cases/lib.rng +5 -0
- data/vendor-src/libleptris/test/rng/include-cases/lib2.rng +6 -0
- data/vendor-src/libleptris/test/rng/include-cases/main.rng +4 -0
- data/vendor-src/libleptris/test/rng/include-cases/no-href.rng +4 -0
- data/vendor-src/libleptris/test/rng/include-cases/override.rng +8 -0
- data/vendor-src/libleptris/test/rng/include-cases/self-include.rng +4 -0
- data/vendor-src/libleptris/test/rng/include-cases/start-override.rng +5 -0
- data/vendor-src/libleptris/test/rng/jing-cases/000.bad.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/000.ok.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/000.rng +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/001.bad.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/001.ok.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/001.rng +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/002.bad.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/002.ok.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/002.rng +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/003.bad.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/003.ok.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/003.rng +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/004.bad.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/004.ok.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/004.rng +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/005.bad.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/005.ok.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/005.rng +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/006.bad.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/006.ok.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/006.rng +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/007.bad.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/007.ok.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/007.rng +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/008.bad.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/008.ok.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/008.rng +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/009.bad.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/009.ok.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/009.rng +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/010.bad.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/010.ok.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/010.rng +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/011.bad.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/011.ok.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/011.rng +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/012.bad.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/012.ok.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/012.rng +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/013.bad.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/013.ok.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/013.rng +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/014.bad.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/014.ok.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/014.rng +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/015.bad.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/015.ok.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/015.rng +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/016.bad.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/016.ok.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/016.rng +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/017.bad.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/017.ok.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/017.rng +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/018.bad.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/018.ok.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/018.rng +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/019.bad.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/019.ok.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/019.rng +7 -0
- data/vendor-src/libleptris/test/rng/jing-cases/020-book.rng +4 -0
- data/vendor-src/libleptris/test/rng/jing-cases/020.bad.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/020.ok.xml +1 -0
- data/vendor-src/libleptris/test/rng/jing-cases/020.rng +3 -0
- data/vendor-src/libleptris/test/rng/jing-cases/README.md +32 -0
- data/vendor-src/libleptris/test/rng/jing-cases/jing-ref.json +212 -0
- data/vendor-src/libleptris/test/rng/jing-cases/meta.json +1 -0
- data/vendor-src/libleptris/test/rng/test_rng.cpp +1365 -0
- data/vendor-src/libleptris/test/rng/test_rng_corpus.cpp +133 -0
- data/vendor-src/libleptris/test/rng/test_rng_corpus_msg.cpp +233 -0
- data/vendor-src/libleptris/test/sax/test_iterparse.cpp +203 -0
- data/vendor-src/libleptris/test/sax/test_pull.cpp +214 -0
- data/vendor-src/libleptris/test/sax/test_pull_batch.cpp +201 -0
- data/vendor-src/libleptris/test/sax/test_recorder.cpp +265 -0
- data/vendor-src/libleptris/test/sax/test_sax.cpp +665 -0
- data/vendor-src/libleptris/test/sax/test_streaming.cpp +434 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/README.md +15 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/extends-baseuri-fixup-01.xml +28 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/extends-recursive-01.xml +27 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/include-baseuri-fixup-01.xml +24 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/include-recursive-01.xml +24 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/let-name-collision-error-01.xml +20 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/let-name-collision-error-02.xml +20 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/let-name-collision-error-03.xml +20 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/let-name-collision-error-04.xml +23 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/let-name-collision-error-05.xml +20 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/let-name-collision-error-06.xml +25 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/let-pattern-global-01.xml +24 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/let-reference-undefined-01.xml +18 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/let-reference-undefined-02.xml +18 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/let-reference-undefined-03.xml +18 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/let-reference-undefined-04.xml +19 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/let-reference-undefined-05.xml +20 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/let-reference-undefined-06.xml +20 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/let-reference-undefined-07.xml +18 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/let-rule-global-01.xml +20 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/let-rule-global-02.xml +23 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/let-scope-pattern-01.xml +25 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/let-scope-phase-01.xml +23 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/let-scope-rule-01.xml +23 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/let-value-element-content-01.xml +33 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/pattern-abstract-01.xml +22 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/pattern-subordinate-document-01.xml +21 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/pattern-subordinate-document-02.xml +21 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/rule-abstract-01.xml +21 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/rule-abstract-02.xml +23 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/rule-context-attribute-01.xml +18 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/rule-context-comment-01.xml +20 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/rule-context-element-01.xml +18 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/rule-context-pi-01.xml +20 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/rule-context-root-01.xml +18 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/rule-context-text-01.xml +18 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/rule-context-variable-01.xml +22 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/rule-context-variable-02.xml +25 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/rule-context-variable-03.xml +22 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/rule-order-01.xml +21 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/schema-default-phase-01.xml +26 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/schema-default-phase-02.xml +25 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/svrl-diagnostic-01.xml +28 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/svrl-diagnostic-02.xml +25 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/svrl-name-nopath-01.xml +23 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/svrl-name-path-01.xml +23 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/svrl-property-01.xml +28 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/svrl-property-copy-of.xml +26 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/svrl-value-of-01.xml +23 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/xslt-key-01.xml +19 -0
- data/vendor-src/libleptris/test/sch/conformance-cases/xslt-key-element-content-01.xml +21 -0
- data/vendor-src/libleptris/test/sch/test_schematron.cpp +337 -0
- data/vendor-src/libleptris/test/sch/test_schematron_corpus.cpp +421 -0
- data/vendor-src/libleptris/test/serializer/test_c14n.cpp +539 -0
- data/vendor-src/libleptris/test/serializer/test_serialize.cpp +890 -0
- data/vendor-src/libleptris/test/smoke/test_smoke.cpp +41 -0
- data/vendor-src/libleptris/test/xinclude/test_xinclude.cpp +903 -0
- data/vendor-src/libleptris/test/xpath/test_bytecode_vm.cpp +755 -0
- data/vendor-src/libleptris/test/xpath/test_compiled.cpp +171 -0
- data/vendor-src/libleptris/test/xpath/test_exslt.cpp +141 -0
- data/vendor-src/libleptris/test/xpath/test_xpath.cpp +2433 -0
- data/vendor-src/libleptris/test/xpath/test_xpath_conformance.cpp +570 -0
- data/vendor-src/libleptris/test/xpath/test_xslt.cpp +4245 -0
- data/vendor-src/libleptris/test/xquery/books.xml +1 -0
- data/vendor-src/libleptris/test/xquery/qt3/README.md +28 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/concat.xml +878 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/contains.xml +795 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/ends-with.xml +556 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/starts-with.xml +644 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/substring/concepts.xml +1 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/substring.xml +449 -0
- data/vendor-src/libleptris/test/xquery/test_qt3.cpp +324 -0
- data/vendor-src/libleptris/test/xquery/test_xquery.cpp +768 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/ATTRIBUTION.md +12 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/array.out +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/array.xml +7 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/array.xsl +26 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-1-.out +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-1-.xml +7 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-1-.xsl +21 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-10-.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-10-.xml +3 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-10-.xsl +10 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-100.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-100.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-100.xsl +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-101.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-101.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-101.xsl +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-102-inc.xsl +21 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-102.out +3 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-102.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-102.xsl +10 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-103.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-103.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-103.xsl +13 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-104.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-104.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-104.xsl +10 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-105.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-105.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-105.xsl +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-106.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-106.xml +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-106.xsl +12 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-107.out +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-107.xml +7 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-107.xsl +11 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-108.out +25 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-108.xml +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-108.xsl +21 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-109.out +3 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-109.xml +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-109.xsl +7 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-11-.out +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-11-.xml +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-11-.xsl +12 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-110.ent +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-110.out +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-110.xml +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-110.xsl +20 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-111.out +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-111.xml +17 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-111.xsl +45 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-112.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-112.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-112.xsl +22 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-113.out +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-113.xml +7 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-113.xsl +15 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-114.out +3 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-114.xml +7 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-114.xsl +16 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-115.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-115.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-115.xsl +19 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-116.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-116.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-116.xsl +22 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-117.out +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-117.xml +10 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-117.xsl +59 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-118.out +3 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-118.xml +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-118.xsl +14 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-119.out +10 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-119.xml +12 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-119.xsl +12 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-12-.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-12-.xml +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-12-.xsl +16 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-120.out +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-120.xml +15 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-120.xsl +27 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-121.out +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-121.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-121.xsl +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-122.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-122.xml +11 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-122.xsl +17 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-123.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-123.xml +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-123.xsl +14 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-124.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-124.xml +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-124.xsl +14 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-125.out +351 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-125.xml +118 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-125.xsl +99 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-126.out +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-126.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-126.xsl +17 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-127.out +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-127.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-127.xsl +18 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-128.out +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-128.xml +26 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-128.xsl +26 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-129.out +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-129.xml +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-129.xsl +10 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-13-.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-13-.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-13-.xsl +10 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-130-imp1.imp +25 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-130-imp2.imp +14 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-130-imp3.imp +16 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-130-imp4.imp +22 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-130.doc +7 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-130.out +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-130.xml +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-130.xsl +22 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-131-imp.imp +19 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-131.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-131.xml +3 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-131.xsl +13 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-132.out +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-132.xml +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-132.xsl +13 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-133.out +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-133.xml +7 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-133.xsl +32 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-134.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-134.xml +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-134.xsl +12 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-135.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-135.xml +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-135.xsl +10 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-136.out +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-136.xml +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-136.xsl +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-137.imp +12 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-137.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-137.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-137.xsl +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-138.out +23 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-138.xml +15 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-138.xsl +28 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-139.out +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-139.xml +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-139.xsl +14 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-14-.out +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-14-.xml +7 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-14-.xsl +23 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-140.out +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-140.xml +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-140.xsl +32 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-141.out +46 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-141.xml +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-141.xsl +25 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-142.out +35 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-142.xml +65 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-142.xsl +85 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-143.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-143.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-143.xsl +10 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-144.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-144.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-144.xsl +10 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-145.err +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-145.xml +10 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-145.xsl +10 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-147-1.imp +11 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-147-2.imp +11 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-147-3.imp +57 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-147-4.imp +15 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-147-5.imp +27 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-147-6.imp +31 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-147.out +17 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-147.xml +21 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-147.xsl +29 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-148.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-148.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-148.xsl +13 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-149.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-149.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-149.xsl +11 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-15-.out +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-15-.xml +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-15-.xsl +15 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-150.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-150.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-150.xsl +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-151.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-151.xsl +15 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-152.out +12 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-152.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-152.xsl +30 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-153.doc +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-153.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-153.xml +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-153.xsl +19 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-154.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-154.xsl +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-155.out +3 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-155.xml +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-155.xsl +10 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-156.err +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-156.imp1.imp +16 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-156.imp2.imp +10 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-156.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-156.xsl +12 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-157.err +3 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-157.out +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-157.xml +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-157.xsl +22 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-158.doc +3 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-158.out +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-158.xml +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-158.xsl +19 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-159.out +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-159.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-159.xsl +17 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-16-.out +14 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-16-.xml +17 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-16-.xsl +13 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-160.out +7 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-160.xml +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-160.xsl +14 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-161.out +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-161.xml +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-161.xsl +18 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-163.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-163.xml +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-163.xsl +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-164.out +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-164.xml +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-164.xsl +13 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-165.err +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-165.xml +10 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-165.xsl +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-166.out +15256 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-166.xml +15255 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-166.xsl +131 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-167.out +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-167.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-167.xsl +20 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-168.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-168.xml +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-168.xsl +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-169.imp +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-169.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-169.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-169.xsl +11 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-17-.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-17-.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-17-.xsl +7 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-170.out +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-170.xml +3 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-170.xsl +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-171.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-171.xml +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-171.xsl +7 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-172.out +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-172.xml +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-172.xsl +22 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-173.out +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-173.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-173.xsl +11 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-174.err +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-174.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-174.xsl +18 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-175.err +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-175.out +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-175.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-175.xsl +33 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-176.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-176.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-176.xsl +11 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-177.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-177.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-177.xsl +7 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-178.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-178.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-178.xsl +18 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-179.out +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-179.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-179.xsl +24 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-18-.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-18-.xml +3 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-18-.xsl +17 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-180.err +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-180.xml +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-180.xsl +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-181.out +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-181.xml +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-181.xsl +13 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-182.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-182.xml +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-182.xsl +21 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-183.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-183.xml +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-183.xsl +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-184.err +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-184.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-184.xsl +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-186.out +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-186.xml +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-186.xsl +7 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-187.err +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-187.out +14 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-187.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-187.xsl +42 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-188-imp.xsl +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-188.out +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-188.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-188.xsl +20 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-189.out +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-189.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-189.xsl +25 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-19-.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-19-.xml +3 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-19-.xsl +17 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-190-imp.xsl +10 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-190.out +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-190.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-190.xsl +16 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-191-imp.xsl +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-191.err +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-191.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-191.xsl +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-192.out +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-192.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-192.xsl +33 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-193.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-193.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-193.xsl +11 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-194.err +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-194.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-194.xsl +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-195.out +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-195.xml +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-195.xsl +19 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-196.out +7 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-196.xml +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-196.xsl +19 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-197.out +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-197.xml +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-197.xsl +16 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-198.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-198.xml +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-198.xsl +17 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-199.out +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-199.xml +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-199.xsl +18 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-2-.out +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-2-.xml +12 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-2-.xsl +16 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-20-.out +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-20-.xml +7 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-20-.xsl +22 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-200.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-200.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-200.xsl +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-201.err +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-201.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-201.xsl +16 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-202.err +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-202.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-202.xsl +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-203.err +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-203.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-203.xsl +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-204.err +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-204.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-204.xsl +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-205.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-205.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-205.xsl +10 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-206.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-206.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-206.xsl +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-207.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-207.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-207.xsl +61 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-208.err +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-208.xml +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-208.xsl +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-209.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-209.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-209.xsl +21 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-21-.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-21-.xml +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-21-.xsl +7 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-210.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-210.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-210.xsl +20 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-211.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-211.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-211.xsl +26 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-212.out +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-212.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-212.xsl +25 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-213.out +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-213.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-213.xsl +26 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-214.out +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-214.xml +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-214.xsl +25 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-215.err +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-215.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-215.xsl +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-216.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-216.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-216.xsl +11 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-217.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-217.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-217.xsl +24 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-218.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-218.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-218.xsl +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-219.out +68 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-219.xml +22 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-219.xsl +17 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-22-.out +12 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-22-.xml +18 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-22-.xsl +19 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-220.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-220.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-220.xsl +15 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-221.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-221.xml +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-221.xsl +15 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-222.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-222.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-222.xsl +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-223-imp.xsl +12 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-223-inc.xsl +12 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-223.out +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-223.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-223.xsl +17 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-224.out +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-224.xml +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-224.xsl +28 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-225.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-225.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-225.xsl +32 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-23-.out +15 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-23-.xml +21 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-23-.xsl +20 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-24-.out +27 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-24-.xml +2419 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-24-.xsl +22 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-25-.out +3 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-25-.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-25-.xsl +10 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-26-.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-26-.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-26-.xsl +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-27-.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-27-.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-27-.xsl +14 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-28-.out +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-28-.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-28-.xsl +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-29-.ent +7 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-29-.out +10 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-29-.xml +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-29-.xsl +16 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-3-.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-3-.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-3-.xsl +13 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-30-.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-30-.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-30-.xsl +7 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-31-.out +3 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-31-.xml +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-31-.xsl +10 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-32-.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-32-.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-32-.xsl +17 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-33-.out +16 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-33-.xml +14 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-33-.xsl +29 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-35-.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-35-.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-35-.xsl +10 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-36-.out +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-36-.xml +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-36-.xsl +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-36-inc.xsl +16 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-37-.out +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-37-.xml +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-37-.xsl +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-37-inc.xsl +15 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-38-.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-38-.xml +17 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-38-.xsl +17 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-39-.out +3 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-39-.xml +3 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-39-.xsl +34 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-4-.out +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-4-.xml +38 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-4-.xsl +12 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-40-.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-40-.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-40-.xsl +16 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-41-.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-41-.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-41-.xsl +19 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-42-.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-42-.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-42-.xsl +16 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-43-.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-43-.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-43-.xsl +19 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-44-.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-44-.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-44-.xsl +19 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-45-.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-45-.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-45-.xsl +27 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-46-.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-46-.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-46-.xsl +16 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-47-.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-47-.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-47-.xsl +18 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-48-.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-48-.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-48-.xsl +24 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-49-.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-49-.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-49-.xsl +15 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-5-.out +954 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-5-.xml +475 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-5-.xsl +158 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-50-.out +7 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-50-.xml +3 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-50-.xsl +14 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-52.out +3 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-52.xml +12 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-52.xsl +16 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-53.out +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-53.xml +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-53.xsl +11 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-54.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-54.xml +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-54.xsl +22 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-55.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-55.xml +3 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-55.xsl +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-56.out +3 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-56.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-56.xsl +28 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-57.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-57.xml +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-57.xsl +21 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-58.xsl +274 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-59.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-59.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-59.xsl +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-6-.out +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-6-.xml +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-6-.xsl +32 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-60.err +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-60.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-60.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-60.xsl +15 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-61.out +10 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-61.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-61.xsl +14 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-62-inc.xsl +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-62.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-62.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-62.xsl +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-63.out +22 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-63.xml +13 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-63.xsl +13 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-64.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-64.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-64.xsl +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-65.ent +7 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-65.out +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-65.xml +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-65.xsl +26 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-66.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-66.xml +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-66.xsl +12 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-68.out +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-68.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-68.xsl +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-69.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-69.xml +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-69.xsl +12 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-7-.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-7-.xml +3 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-7-.xsl +11 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-70.out +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-70.xml +10 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-70.xsl +13 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-71.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-71.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-71.xsl +17 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-72.out +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-72.xml +3 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-72.xsl +31 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-73.out +3 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-73.xml +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-73.xsl +17 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-74.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-74.xml +3 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-74.xsl +12 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-75.out +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-75.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-75.xsl +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-76.out +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-76.xml +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-76.xsl +16 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-77.out +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-77.xml +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-77.xsl +18 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-78.out +3 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-78.xml +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-78.xsl +17 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-79.out +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-79.xml +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-79.xsl +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-8-.out +3 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-8-.xml +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-8-.xsl +13 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-80.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-80.xml +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-80.xsl +29 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-81.out +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-81.xml +12 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-81.xsl +18 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-82.out +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-82.xml +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-82.xsl +12 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-83.out +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-83.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-83.xsl +14 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-84.out +15 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-84.xml +22 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-84.xsl +14 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-86.out +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-86.xml +7 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-86.xsl +7 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-87.out +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-87.xml +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-87.xsl +16 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-88.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-88.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-88.xsl +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-89.out +12 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-89.xml +13 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-89.xsl +105 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-9-.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-9-.xml +3 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-9-.xsl +10 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-90.out +13 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-90.xml +15 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-90.xsl +35 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-91.out +3 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-91.xml +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-91.xsl +8 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-92.out +15 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-92.xml +19 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-92.xsl +19 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-93-inc.xsl +12 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-93.out +3 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-93.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-93.xsl +7 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-94.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-94.xml +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-94.xsl +35 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-95.out +4 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-95.xml +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-95.xsl +22 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-96.out +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-96.xml +5 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-96.xsl +10 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-97.out +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-97.xml +16 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-97.xsl +32 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-98.out +6 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-98.xml +10 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-98.xsl +31 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-99.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-99.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/bug-99.xsl +16 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/character.out +2 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/character.xml +23 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/character.xsl +16 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/date_add.out +9 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/date_add.xml +1 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/date_add.xsl +16 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/doc.dtd +7 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/doc.out +16 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/doc.xml +17 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/doc.xsl +62 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/inner.xsl +12 -0
- data/vendor-src/libleptris/test/xslt/libxslt_suite_general/items.xml +34 -0
- data/vendor-src/libleptris/test/xslt/open_cases.txt +0 -0
- data/vendor-src/libleptris/test/xslt/test_libxslt_suite.cpp +398 -0
- data/vendor-src/libleptris/vcpkg.json +29 -0
- data/vendor-src/utf8proc/CMakeLists.txt +133 -0
- data/vendor-src/utf8proc/Doxyfile +2765 -0
- data/vendor-src/utf8proc/LICENSE.md +93 -0
- data/vendor-src/utf8proc/MANIFEST +9 -0
- data/vendor-src/utf8proc/Makefile +203 -0
- data/vendor-src/utf8proc/NEWS.md +479 -0
- data/vendor-src/utf8proc/README.md +143 -0
- data/vendor-src/utf8proc/appveyor.yml +46 -0
- data/vendor-src/utf8proc/bench/Makefile +40 -0
- data/vendor-src/utf8proc/bench/bench.c +56 -0
- data/vendor-src/utf8proc/bench/icu.c +61 -0
- data/vendor-src/utf8proc/bench/unistring.c +60 -0
- data/vendor-src/utf8proc/bench/util.c +39 -0
- data/vendor-src/utf8proc/bench/util.h +22 -0
- data/vendor-src/utf8proc/cmake/utf8proc-config.cmake.in +5 -0
- data/vendor-src/utf8proc/data/Makefile +62 -0
- data/vendor-src/utf8proc/data/Manifest.toml +16 -0
- data/vendor-src/utf8proc/data/Project.toml +2 -0
- data/vendor-src/utf8proc/data/data_generator.jl +498 -0
- data/vendor-src/utf8proc/libutf8proc.pc.cmakein +10 -0
- data/vendor-src/utf8proc/libutf8proc.pc.in +10 -0
- data/vendor-src/utf8proc/lump.md +27 -0
- data/vendor-src/utf8proc/test/app/CMakeLists.txt +6 -0
- data/vendor-src/utf8proc/test/app/app.c +9 -0
- data/vendor-src/utf8proc/test/case.c +76 -0
- data/vendor-src/utf8proc/test/charwidth.c +91 -0
- data/vendor-src/utf8proc/test/custom.c +28 -0
- data/vendor-src/utf8proc/test/fuzz_main.c +54 -0
- data/vendor-src/utf8proc/test/fuzzer.c +97 -0
- data/vendor-src/utf8proc/test/graphemetest.c +136 -0
- data/vendor-src/utf8proc/test/iscase.c +63 -0
- data/vendor-src/utf8proc/test/iterate.c +168 -0
- data/vendor-src/utf8proc/test/maxdecomposition.c +22 -0
- data/vendor-src/utf8proc/test/misc.c +51 -0
- data/vendor-src/utf8proc/test/normtest.c +64 -0
- data/vendor-src/utf8proc/test/ossfuzz.sh +13 -0
- data/vendor-src/utf8proc/test/printproperty.c +68 -0
- data/vendor-src/utf8proc/test/tests.c +60 -0
- data/vendor-src/utf8proc/test/tests.h +27 -0
- data/vendor-src/utf8proc/test/valid.c +41 -0
- data/vendor-src/utf8proc/utf8proc.c +834 -0
- data/vendor-src/utf8proc/utf8proc.h +794 -0
- data/vendor-src/utf8proc/utf8proc_data.c +17141 -0
- data/vendor-src/utf8proc/utils.cmake +20 -0
- 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] == '&' ? "&"
|
|
378
|
+
: p[run] == '<' ? "<" : ">");
|
|
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, "&"); break;
|
|
391
|
+
case '<': buffer_append(b, "<"); break;
|
|
392
|
+
case '>': buffer_append(b, ">"); break;
|
|
393
|
+
case '"': buffer_append(b, """); break;
|
|
394
|
+
case '\t': buffer_append(b, "	"); break;
|
|
395
|
+
case '\n': buffer_append(b, " "); break;
|
|
396
|
+
default: buffer_append(b, " "); 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; /* & */
|
|
1000
|
+
else if (*p == '<' || *p == '>') n += 4; /* < > */
|
|
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, "&", 5); o += 5; }
|
|
1009
|
+
else if (*p == '<') { memcpy(o, "<", 4); o += 4; }
|
|
1010
|
+
else if (*p == '>') { memcpy(o, ">", 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 &
|
|
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
|
+
|