leptris 1.9.231.1-ppc64le-linux → 1.9.232.1-ppc64le-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +19 -0
  3. data/Rakefile +1 -1
  4. data/ext/leptris/native/native.c +35 -4
  5. data/lib/leptris/version.rb +1 -1
  6. data/lib/leptris/xml/ffi.rb +88 -62
  7. data/lib/leptris/xml/native.so +0 -0
  8. data/lib/leptris/xml/node.rb +28 -0
  9. data/lib/libleptris.so +0 -0
  10. data/vendor-src/README.md +1 -1
  11. data/vendor-src/libleptris/CHANGELOG.md +15 -0
  12. data/vendor-src/libleptris/CMakeLists.txt +1 -1
  13. data/vendor-src/libleptris/src/include/leptris/descriptor.h +5 -1
  14. data/vendor-src/libleptris/src/include/leptris.h +17 -0
  15. data/vendor-src/libleptris/src/leptris/descriptor/plan.c +26 -6
  16. data/vendor-src/libleptris/src/leptris/dom/node.c +24 -7
  17. data/vendor-src/libleptris/src/leptris/xpath/evaluator_operators.c +22 -8
  18. data/vendor-src/libleptris/src/leptris/xpath/functions.c +29 -8
  19. data/vendor-src/libleptris/src/leptris/xpath/functions_ext31.c +30 -1
  20. data/vendor-src/libleptris/src/leptris/xpath/parser.c +106 -6
  21. data/vendor-src/libleptris/test/abi/test_descriptor.cpp +68 -0
  22. data/vendor-src/libleptris/test/dom/test_dom.cpp +56 -0
  23. data/vendor-src/libleptris/test/xquery/qt3/fn/codepoints-to-string.xml +808 -0
  24. data/vendor-src/libleptris/test/xquery/qt3/fn/deep-equal.xml +2709 -0
  25. data/vendor-src/libleptris/test/xquery/qt3/fn/distinct-values.xml +1223 -0
  26. data/vendor-src/libleptris/test/xquery/qt3/fn/index-of.xml +493 -0
  27. data/vendor-src/libleptris/test/xquery/qt3/fn/insert-before.xml +399 -0
  28. data/vendor-src/libleptris/test/xquery/qt3/fn/remove.xml +480 -0
  29. data/vendor-src/libleptris/test/xquery/qt3/fn/reverse.xml +653 -0
  30. data/vendor-src/libleptris/test/xquery/qt3/fn/string-to-codepoints.xml +452 -0
  31. data/vendor-src/libleptris/test/xquery/qt3/fn/subsequence.xml +1041 -0
  32. data/vendor-src/libleptris/test/xquery/test_qt3.cpp +179 -1
  33. data/vendor-src/libleptris/test/xquery/test_xquery.cpp +27 -0
  34. data/vendor-src/libleptris/vcpkg.json +1 -1
  35. metadata +11 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6a03ce93f7f2e1523f2da2f36d5e5a8673208f152681b0522169c7aa3858c040
4
- data.tar.gz: 99434e64ab561f2250851815dda490924545e7d03bf8584c663760c64e7b544a
3
+ metadata.gz: dbea4290be718ca7b75aa45539d8573ab5c5d410e8d3f21b9dae2fecf373ae4e
4
+ data.tar.gz: ac6e1d2b0ed35acc86b80f95299bfb07482fe2e10db91cc7829fe101171de6ad
5
5
  SHA512:
6
- metadata.gz: e8414dd067704ec35c08b107873143df153b8c25cf3d362f672b6314486b41df82bff4a68d51ae4fc9a7889721c2ae840aaef305d1835c54003a35298a074517
7
- data.tar.gz: 7334dd4eebd5482253441b45bc5ff666fa3d79dd5111d3f5685df5cd4710e2f5382f0b8ac5f4e68e80640426cad762d1646ce5cd7e4a2e9bed863b66030e05d4
6
+ metadata.gz: f8f75c17ec559fbe6ff018b1ec831313754ff34bc64953b6f8063f97130f831a0860a24166c64423382f8b0b331b1ca32e8717230335243c9dbd284b7eb9b8fe
7
+ data.tar.gz: 4c19cc71b5284ac325c75916d3a855d6cfb0ecda7ed7c15db5c3d36e296dc75509607049658c0469936f60af8c999084143f69ba22834c82f7dd93761a56a19e
data/CHANGELOG.md CHANGED
@@ -5,6 +5,25 @@ All notable changes to Leptris will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.9.232.0] - 2026-09-24
9
+
10
+ ### Added
11
+
12
+ - `Node#visit_entering` (libleptris #1332): the entering-only walk
13
+ — one C call yields `(node, true, depth)` exactly once per node,
14
+ halving the C→Ruby transitions against `#visit` for walks that
15
+ never acted on the leaving half. Same order and depths as
16
+ `#visit`; the native face falls back to the filtering visit on
17
+ pins predating #1332.
18
+
19
+ ### Performance — engine sync (1.9.232)
20
+
21
+ - Vendored libleptris 1.9.232: the per-eval registry leak fix, the
22
+ range NaN fix, string-literal character-reference expansion, and
23
+ the plan-walker prefixed-name fix — moxml/lutaml hydration of
24
+ `w:*` elements resolves correctly with no binding-side change —
25
+ plus 907 new QT3-gated engine behaviors.
26
+
8
27
  ## [1.9.231.0] - 2026-09-23
9
28
 
10
29
  ### Fixed
data/Rakefile CHANGED
@@ -8,7 +8,7 @@ RSpec::Core::RakeTask.new(:spec)
8
8
  # Pin for `rake compile` and the platform-gem builds. Keep in lockstep
9
9
  # with .github/workflows/build.yml (which calls `rake compile`) and the
10
10
  # CHANGELOG when libleptris releases.
11
- LIBLEPTRIS_VERSION = "1.9.231"
11
+ LIBLEPTRIS_VERSION = "1.9.232"
12
12
  # Vendored alongside libleptris for fn:normalize-unicode (TODO
13
13
  # .restructure/20): built per platform with a RELOCATABLE @rpath
14
14
  # install name, loaded by ffi.rb before libleptris so the
@@ -971,10 +971,39 @@ static VALUE nf_visit_binding(VALUE self, VALUE document, VALUE addr)
971
971
  st.klass_memo_flag =
972
972
  rb_obj_class(document) == c_iteration_scope ? Qfalse : Qtrue;
973
973
  st.for_visit = 1;
974
- if (f_node_visit_entering)
975
- f_node_visit_entering(st.self_ptr, visit_cb, &st);
976
- else
977
- f_node_visit(st.self_ptr, visit_cb, &st);
974
+ /* ALWAYS the two-event engine call: this seam backs the PUBLIC
975
+ * Node#visit, whose contract (specs since libleptris 1.9.20)
976
+ * is (node, entering, depth) enter/leave PAIRS. Entering-only
977
+ * walks belong to visit_entering_binding below — swapping the
978
+ * call here silently dropped every leaving callback and broke
979
+ * the contract. */
980
+ f_node_visit(st.self_ptr, visit_cb, &st);
981
+ if (st.err != Qnil)
982
+ rb_exc_raise(st.err);
983
+ return Qnil;
984
+ }
985
+
986
+ /* Entering-only walk (libleptris #1332): one callback per node.
987
+ * Yields the same (node, true, depth) shape as visit_binding — the
988
+ * entering argument is constant true here, but keeping the 3-arity
989
+ * yield lets a block be shared between the two walk modes. */
990
+ static VALUE nf_visit_entering_binding(VALUE self, VALUE document,
991
+ VALUE addr)
992
+ {
993
+ struct trav_state st;
994
+
995
+ (void)self;
996
+ if (!f_node_visit_entering)
997
+ return nf_visit_binding(self, document, addr);
998
+ resolve_binding_classes();
999
+ st.document = document;
1000
+ st.err = Qnil;
1001
+ st.self_ptr = (void *)(uintptr_t)NUM2ULL(addr);
1002
+ st.cache = binding_cache_of(document);
1003
+ st.klass_memo_flag =
1004
+ rb_obj_class(document) == c_iteration_scope ? Qfalse : Qtrue;
1005
+ st.for_visit = 1;
1006
+ f_node_visit_entering(st.self_ptr, visit_cb, &st);
978
1007
  if (st.err != Qnil)
979
1008
  rb_exc_raise(st.err);
980
1009
  return Qnil;
@@ -2739,6 +2768,8 @@ LEPTRIS_INIT_EXPORT void Init_native(void)
2739
2768
  nf_traverse_binding, 2);
2740
2769
  rb_define_module_function(m_native, "visit_binding",
2741
2770
  nf_visit_binding, 2);
2771
+ rb_define_module_function(m_native, "visit_entering_binding",
2772
+ nf_visit_entering_binding, 2);
2742
2773
  rb_define_module_function(m_native, "fast_text_content",
2743
2774
  nf_fast_text_content, 1);
2744
2775
  rb_define_module_function(m_native, "fast_comment_content",
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Leptris
4
- VERSION = "1.9.231.1"
4
+ VERSION = "1.9.232.1"
5
5
  end
@@ -7,6 +7,28 @@ module Leptris
7
7
  module FFI
8
8
  extend ::FFI::Library
9
9
 
10
+ # FFI's :string return type always tags returned bytes
11
+ # ASCII-8BIT, but libleptris produces character data (UTF-8,
12
+ # the XML default encoding). Every string-returning function
13
+ # therefore uses this converter: same NUL-terminated copy
14
+ # semantics as :string, tagged UTF-8. Input arguments keep
15
+ # plain :string (Ruby-to-C reads bytes regardless of tag).
16
+ UTF8_STRING = Class.new do
17
+ include ::FFI::DataConverter
18
+
19
+ def from_native(ptr, _ctx)
20
+ return nil if ptr.null? || ptr.address.zero?
21
+
22
+ ptr.read_string.force_encoding(Encoding::UTF_8)
23
+ end
24
+
25
+ def to_native(value, _ctx)
26
+ return nil if value.nil?
27
+
28
+ ::FFI::MemoryPointer.from_string(value.to_s)
29
+ end
30
+ end.new.tap { |c| c.native_type(::FFI::Type::POINTER) }
31
+
10
32
  # The per-OS vendor directory of the ruby-platform gem
11
33
  # (zero-setup TruffleRuby/JRuby, #160): binaries for the
12
34
  # common engines' OSes under lib/leptris/vendor/<platform>/.
@@ -321,11 +343,11 @@ module Leptris
321
343
  attach_function :leptris_plan_value_kind,
322
344
  [:leptris_plan_result], :int
323
345
  attach_function :leptris_plan_value_name,
324
- [:leptris_plan_result], :string
346
+ [:leptris_plan_result], UTF8_STRING
325
347
  attach_function :leptris_plan_value_type_tag,
326
348
  [:leptris_plan_result], :uint8
327
349
  attach_function :leptris_plan_value_string,
328
- [:leptris_plan_result], :string
350
+ [:leptris_plan_result], UTF8_STRING
329
351
  attach_function :leptris_plan_value_length,
330
352
  [:leptris_plan_result], :size_t
331
353
  attach_function :leptris_plan_value_position,
@@ -335,7 +357,7 @@ module Leptris
335
357
  attach_function :leptris_plan_value_at,
336
358
  [:leptris_plan_result, :size_t], :leptris_plan_result
337
359
  attach_function :leptris_plan_value_attribute,
338
- [:leptris_plan_result, :string], :string
360
+ [:leptris_plan_result, :string], UTF8_STRING
339
361
  # #1254 (leptris 1.9.216): one-call flat attribute read —
340
362
  # parallel name/value/handle arrays, capacity-bounded; total
341
363
  # count returned (min(total, max_count) copied). Also the
@@ -367,7 +389,7 @@ module Leptris
367
389
  [:string, :size_t, :leptris_plan, :pointer],
368
390
  :leptris_plan_result
369
391
 
370
- attach_function :leptris_version, [], :string
392
+ attach_function :leptris_version, [], UTF8_STRING
371
393
  attach_function :leptris_version_components, [:pointer, :pointer, :pointer], :void
372
394
 
373
395
  # Tolerant HTML4/5 parse into the STANDARD DOM (libleptris
@@ -424,9 +446,9 @@ attach_function :leptris_parse_string,
424
446
  attach_function :leptris_entity_ref_node_create,
425
447
  [:leptris_document, :string], :leptris_node_ref
426
448
  attach_function :leptris_entity_ref_node_name,
427
- [:leptris_node_ref], :string
449
+ [:leptris_node_ref], UTF8_STRING
428
450
  attach_function :leptris_document_version,
429
- [:leptris_document], :string
451
+ [:leptris_document], UTF8_STRING
430
452
  attach_function :leptris_document_standalone,
431
453
  [:leptris_document], :int
432
454
  attach_function :leptris_document_set_version,
@@ -447,14 +469,18 @@ attach_function :leptris_parse_string,
447
469
  # node walks the document child chain.
448
470
  attach_function :leptris_node_visit,
449
471
  [:leptris_node_ref, :pointer, :pointer], :void
472
+ # Entering-only walk (libleptris #1332): one callback per
473
+ # node. Rides the engine pin that ships it.
474
+ attach_function :leptris_node_visit_entering,
475
+ [:leptris_node_ref, :pointer, :pointer], :void
450
476
  # Document-level PIs (v1.6.0): not tree nodes — enumerate via
451
477
  # these accessors only.
452
478
  attach_function :leptris_document_pi_count,
453
479
  [:leptris_document], :size_t
454
480
  attach_function :leptris_document_pi_target,
455
- [:leptris_document, :size_t], :string
481
+ [:leptris_document, :size_t], UTF8_STRING
456
482
  attach_function :leptris_document_pi_data,
457
- [:leptris_document, :size_t], :string
483
+ [:leptris_document, :size_t], UTF8_STRING
458
484
  # Document-level PI removal by target or index (1.9.9, #612):
459
485
  # unlinks from the child chain; the node is pool-owned and
460
486
  # stays valid until document free.
@@ -472,13 +498,13 @@ attach_function :leptris_parse_string,
472
498
  attach_function :leptris_document_comment_count,
473
499
  [:leptris_document], :size_t
474
500
  attach_function :leptris_document_comment_content,
475
- [:leptris_document, :size_t], :string
501
+ [:leptris_document, :size_t], UTF8_STRING
476
502
  # Options-struct parse (v1.6.0): supersedes the flags variants;
477
503
  # the flags path remains bound for compatibility.
478
504
  attach_function :leptris_parse_string_ex,
479
505
  [:string, :size_t, :pointer, :pointer], :leptris_document
480
506
  attach_function :leptris_document_encoding,
481
- [:leptris_document], :string
507
+ [:leptris_document], UTF8_STRING
482
508
  attach_function :leptris_document_finalize_strings,
483
509
  [:leptris_document], :int
484
510
  attach_function :leptris_document_adopt_child,
@@ -501,10 +527,10 @@ attach_function :leptris_parse_string,
501
527
  [:leptris_element], :int
502
528
  attach_function :leptris_xinclude_is_fallback_element,
503
529
  [:leptris_element], :int
504
- attach_function :leptris_xinclude_get_href, [:leptris_element], :string
505
- attach_function :leptris_xinclude_get_parse, [:leptris_element], :string
506
- attach_function :leptris_xinclude_get_xpointer, [:leptris_element], :string
507
- attach_function :leptris_xinclude_get_encoding, [:leptris_element], :string
530
+ attach_function :leptris_xinclude_get_href, [:leptris_element], UTF8_STRING
531
+ attach_function :leptris_xinclude_get_parse, [:leptris_element], UTF8_STRING
532
+ attach_function :leptris_xinclude_get_xpointer, [:leptris_element], UTF8_STRING
533
+ attach_function :leptris_xinclude_get_encoding, [:leptris_element], UTF8_STRING
508
534
 
509
535
  attach_function :leptris_node_get_type,
510
536
  [:leptris_node_ref], :int
@@ -566,15 +592,15 @@ attach_function :leptris_parse_string,
566
592
  [:leptris_node_ref, :int, :pointer, :pointer], :int
567
593
 
568
594
  attach_function :leptris_text_node_get_content,
569
- [:leptris_node_ref], :string
595
+ [:leptris_node_ref], UTF8_STRING
570
596
  attach_function :leptris_comment_node_get_content,
571
- [:leptris_node_ref], :string
597
+ [:leptris_node_ref], UTF8_STRING
572
598
  attach_function :leptris_cdata_node_get_content,
573
- [:leptris_node_ref], :string
599
+ [:leptris_node_ref], UTF8_STRING
574
600
  attach_function :leptris_pi_node_get_target,
575
- [:leptris_node_ref], :string
601
+ [:leptris_node_ref], UTF8_STRING
576
602
  attach_function :leptris_pi_node_get_data,
577
- [:leptris_node_ref], :string
603
+ [:leptris_node_ref], UTF8_STRING
578
604
  attach_function :leptris_text_node_create,
579
605
  [:leptris_document, :string], :leptris_node_ref
580
606
  attach_function :leptris_comment_node_create,
@@ -595,9 +621,9 @@ attach_function :leptris_parse_string,
595
621
  [:leptris_node_ref, :string], :leptris_status
596
622
 
597
623
  attach_function :leptris_element_name,
598
- [:leptris_element], :string
624
+ [:leptris_element], UTF8_STRING
599
625
  attach_function :leptris_element_text,
600
- [:leptris_element], :string
626
+ [:leptris_element], UTF8_STRING
601
627
  attach_function :leptris_element_text_int,
602
628
  [:leptris_element, :int], :int
603
629
  attach_function :leptris_element_text_uint,
@@ -609,9 +635,9 @@ attach_function :leptris_parse_string,
609
635
  attach_function :leptris_element_text_bool,
610
636
  [:leptris_element, :int], :int
611
637
  attach_function :leptris_element_attribute,
612
- [:leptris_element, :string], :string
638
+ [:leptris_element, :string], UTF8_STRING
613
639
  attach_function :leptris_element_attribute_string,
614
- [:leptris_element, :string, :string], :string
640
+ [:leptris_element, :string, :string], UTF8_STRING
615
641
  attach_function :leptris_element_attribute_int,
616
642
  [:leptris_element, :string, :int], :int
617
643
  attach_function :leptris_element_attribute_uint,
@@ -628,32 +654,32 @@ attach_function :leptris_parse_string,
628
654
  # XML Namespaces 1.0 semantics; NULL/"" uri matches only
629
655
  # no-namespace attributes, xmlns declarations never match.
630
656
  attach_function :leptris_element_attribute_ns,
631
- [:leptris_element, :string, :string], :string
657
+ [:leptris_element, :string, :string], UTF8_STRING
632
658
  attach_function :leptris_element_has_attribute_ns,
633
659
  [:leptris_element, :string, :string], :int
634
660
  # libleptris 1.8.0: per-attribute prefix (name-derived) and
635
661
  # namespace URI (resolved through the owning element's
636
662
  # in-scope declarations at read time).
637
663
  attach_function :leptris_attribute_prefix,
638
- [:leptris_attribute], :string
664
+ [:leptris_attribute], UTF8_STRING
639
665
  attach_function :leptris_attribute_namespace_uri,
640
- [:leptris_attribute], :string
666
+ [:leptris_attribute], UTF8_STRING
641
667
  attach_function :leptris_element_first_attribute,
642
668
  [:leptris_element], :leptris_attribute
643
669
  attach_function :leptris_attribute_next,
644
670
  [:leptris_attribute], :leptris_attribute
645
671
  attach_function :leptris_attribute_get_name,
646
- [:leptris_attribute], :string
672
+ [:leptris_attribute], UTF8_STRING
647
673
  attach_function :leptris_attribute_get_value,
648
- [:leptris_element, :leptris_attribute], :string
674
+ [:leptris_element, :leptris_attribute], UTF8_STRING
649
675
  attach_function :leptris_element_prefix,
650
- [:leptris_element], :string
676
+ [:leptris_element], UTF8_STRING
651
677
  attach_function :leptris_element_attribute_count,
652
678
  [:leptris_element], :size_t
653
679
  attach_function :leptris_element_attribute_name_at,
654
- [:leptris_element, :size_t], :string
680
+ [:leptris_element, :size_t], UTF8_STRING
655
681
  attach_function :leptris_element_attribute_value_at,
656
- [:leptris_element, :size_t], :string
682
+ [:leptris_element, :size_t], UTF8_STRING
657
683
  attach_function :leptris_element_remove_all_attributes,
658
684
  [:leptris_element], :leptris_status
659
685
 
@@ -666,7 +692,7 @@ attach_function :leptris_parse_string,
666
692
  attach_function :leptris_element_root,
667
693
  [:leptris_element], :leptris_element
668
694
  attach_function :leptris_element_child_value,
669
- [:leptris_element], :string
695
+ [:leptris_element], UTF8_STRING
670
696
  attach_function :leptris_element_hash_value,
671
697
  [:leptris_element], :size_t
672
698
  attach_function :leptris_element_find_child,
@@ -752,23 +778,23 @@ attach_function :leptris_parse_string,
752
778
  attach_function :leptris_element_set_namespace,
753
779
  [:leptris_element, :string], :leptris_status
754
780
  attach_function :leptris_element_namespace,
755
- [:leptris_element], :string
781
+ [:leptris_element], UTF8_STRING
756
782
  attach_function :leptris_element_namespace_for_prefix,
757
- [:leptris_element, :string], :string
783
+ [:leptris_element, :string], UTF8_STRING
758
784
  attach_function :leptris_element_namespace_count,
759
785
  [:leptris_element], :size_t
760
786
  attach_function :leptris_element_namespace_decl_prefix,
761
- [:leptris_element, :size_t], :string
787
+ [:leptris_element, :size_t], UTF8_STRING
762
788
  attach_function :leptris_element_namespace_decl_uri,
763
- [:leptris_element, :size_t], :string
789
+ [:leptris_element, :size_t], UTF8_STRING
764
790
  attach_function :leptris_element_add_namespace_definition,
765
791
  [:leptris_element, :string, :string], :leptris_status
766
792
  attach_function :leptris_element_set_default_namespace,
767
793
  [:leptris_element, :string], :leptris_status
768
794
  attach_function :leptris_element_remove_namespace_definition,
769
795
  [:leptris_element, :string], :leptris_status
770
- attach_function :leptris_namespace_uri, [:string], :string
771
- attach_function :leptris_namespace_prefix, [:string], :string
796
+ attach_function :leptris_namespace_uri, [:string], UTF8_STRING
797
+ attach_function :leptris_namespace_prefix, [:string], UTF8_STRING
772
798
 
773
799
  attach_function :leptris_xpath_eval,
774
800
  [:leptris_document, :leptris_element, :string], :leptris_xpath_result
@@ -803,9 +829,9 @@ attach_function :leptris_parse_string,
803
829
  attach_function :leptris_xpath_result_get_node,
804
830
  [:leptris_xpath_result, :size_t], :leptris_node_ref
805
831
  attach_function :leptris_xpath_result_node_name,
806
- [:leptris_xpath_result, :size_t], :string
832
+ [:leptris_xpath_result, :size_t], UTF8_STRING
807
833
  attach_function :leptris_xpath_result_node_value,
808
- [:leptris_xpath_result, :size_t], :string
834
+ [:leptris_xpath_result, :size_t], UTF8_STRING
809
835
  # Document-scoped custom XPath functions. The callback receives
810
836
  # (const char* const* args, int argc, void* user_data) and returns
811
837
  # a heap string the library frees.
@@ -873,7 +899,7 @@ attach_function :leptris_parse_string,
873
899
  :leptris_xpath_result
874
900
  # Source text of a compiled expression (owned by the handle).
875
901
  attach_function :leptris_xpath_compiled_text,
876
- [:leptris_xpath_compiled], :string
902
+ [:leptris_xpath_compiled], UTF8_STRING
877
903
  attach_function :leptris_xpath_compiled_free,
878
904
 
879
905
  [:leptris_xpath_compiled], :void
@@ -918,9 +944,9 @@ attach_function :leptris_parse_string,
918
944
  attach_function :leptris_pull_attr_count,
919
945
  [:leptris_pull_parser], :size_t
920
946
  attach_function :leptris_pull_attr_name,
921
- [:leptris_pull_parser, :size_t], :string
947
+ [:leptris_pull_parser, :size_t], UTF8_STRING
922
948
  attach_function :leptris_pull_attr_value,
923
- [:leptris_pull_parser, :size_t], :string
949
+ [:leptris_pull_parser, :size_t], UTF8_STRING
924
950
  attach_function :leptris_pull_attrs,
925
951
  [:leptris_pull_parser, :pointer, :size_t], :size_t
926
952
  attach_function :leptris_pull_free,
@@ -944,9 +970,9 @@ attach_function :leptris_parse_string,
944
970
  attach_function :leptris_iterparse_ns_count,
945
971
  [:leptris_iterparse], :size_t
946
972
  attach_function :leptris_iterparse_ns_uri,
947
- [:leptris_iterparse, :string], :string
973
+ [:leptris_iterparse, :string], UTF8_STRING
948
974
  attach_function :leptris_iterparse_error,
949
- [:leptris_iterparse], :string
975
+ [:leptris_iterparse], UTF8_STRING
950
976
  attach_function :leptris_iterparse_free,
951
977
  [:leptris_iterparse], :void
952
978
 
@@ -1016,7 +1042,7 @@ attach_function :leptris_parse_string,
1016
1042
  attach_function :leptris_sax_records_data, [:pointer], :pointer
1017
1043
  attach_function :leptris_sax_records_attrs,
1018
1044
  [:pointer, :pointer], :pointer
1019
- attach_function :leptris_sax_records_buffer, [:pointer], :string
1045
+ attach_function :leptris_sax_records_buffer, [:pointer], UTF8_STRING
1020
1046
  attach_function :leptris_sax_records_free, [:pointer], :void
1021
1047
  # XSLT 1.0 engine (libleptris 1.9.1): compile once, apply many.
1022
1048
  # XQuery 1.0 core (libleptris 1.9.64-1.9.66): orchestration
@@ -1057,7 +1083,7 @@ attach_function :leptris_parse_string,
1057
1083
  attach_function :leptris_schematron_validate,
1058
1084
  [:leptris_schematron, :leptris_document], :leptris_document
1059
1085
  attach_function :leptris_schematron_error,
1060
- [:leptris_schematron], :string
1086
+ [:leptris_schematron], UTF8_STRING
1061
1087
 
1062
1088
  # Tree diff (libleptris >= 1.9.126 family): equal subtrees
1063
1089
  # prune in O(1) by the #869 Merkle digest; diverging regions
@@ -1070,13 +1096,13 @@ attach_function :leptris_parse_string,
1070
1096
  attach_function :leptris_diff_op_type,
1071
1097
  [:leptris_diff, :size_t], :int
1072
1098
  attach_function :leptris_diff_op_name,
1073
- [:leptris_diff, :size_t], :string
1099
+ [:leptris_diff, :size_t], UTF8_STRING
1074
1100
  attach_function :leptris_diff_op_path,
1075
- [:leptris_diff, :size_t], :string
1101
+ [:leptris_diff, :size_t], UTF8_STRING
1076
1102
  attach_function :leptris_diff_op_before,
1077
- [:leptris_diff, :size_t], :string
1103
+ [:leptris_diff, :size_t], UTF8_STRING
1078
1104
  attach_function :leptris_diff_op_after,
1079
- [:leptris_diff, :size_t], :string
1105
+ [:leptris_diff, :size_t], UTF8_STRING
1080
1106
  attach_function :leptris_diff_serialize,
1081
1107
  [:leptris_diff], :pointer
1082
1108
 
@@ -1123,14 +1149,14 @@ attach_function :leptris_parse_string,
1123
1149
  attach_function :leptris_rng_validate,
1124
1150
  [:leptris_relaxng, :leptris_document], :int
1125
1151
  attach_function :leptris_rng_error,
1126
- [:leptris_relaxng], :string
1152
+ [:leptris_relaxng], UTF8_STRING
1127
1153
  # Accumulated validation errors (libleptris 1.9.179, #878):
1128
1154
  # the validator no longer stops at the first failure;
1129
1155
  # leptris_rng_error keeps returning the first (back-compat).
1130
1156
  attach_function :leptris_rng_error_count,
1131
1157
  [:leptris_relaxng], :size_t
1132
1158
  attach_function :leptris_rng_error_message,
1133
- [:leptris_relaxng, :size_t], :string
1159
+ [:leptris_relaxng, :size_t], UTF8_STRING
1134
1160
  attach_function :leptris_rng_error_line,
1135
1161
  [:leptris_relaxng, :size_t], :int
1136
1162
  attach_function :leptris_rng_error_column,
@@ -1178,15 +1204,15 @@ attach_function :leptris_parse_string,
1178
1204
  attach_function :leptris_document_internal_subset,
1179
1205
  [:leptris_document], :leptris_doctype
1180
1206
  attach_function :leptris_doctype_get_name,
1181
- [:leptris_doctype], :string
1207
+ [:leptris_doctype], UTF8_STRING
1182
1208
  attach_function :leptris_doctype_get_root_name,
1183
- [:leptris_doctype], :string
1209
+ [:leptris_doctype], UTF8_STRING
1184
1210
  attach_function :leptris_doctype_get_public_id,
1185
- [:leptris_doctype], :string
1211
+ [:leptris_doctype], UTF8_STRING
1186
1212
  attach_function :leptris_doctype_get_system_id,
1187
- [:leptris_doctype], :string
1213
+ [:leptris_doctype], UTF8_STRING
1188
1214
  attach_function :leptris_doctype_get_internal_subset,
1189
- [:leptris_doctype], :string
1215
+ [:leptris_doctype], UTF8_STRING
1190
1216
 
1191
1217
  attach_function :leptris_free_string, [:pointer], :void
1192
1218
  attach_function :leptris_explicit_cleanup, [], :void
@@ -1196,8 +1222,8 @@ attach_function :leptris_parse_string,
1196
1222
  attach_function :leptris_get_memory_deallocation_function, [], :pointer
1197
1223
  attach_function :leptris_document_set_allocators,
1198
1224
  [:leptris_document, :pointer, :pointer], :leptris_status
1199
- attach_function :leptris_status_string, [:leptris_status], :string
1200
- attach_function :leptris_error_message, [:leptris_status], :string
1225
+ attach_function :leptris_status_string, [:leptris_status], UTF8_STRING
1226
+ attach_function :leptris_error_message, [:leptris_status], UTF8_STRING
1201
1227
  # Engine surface adopted with libleptris 1.9.206 (the FFI
1202
1228
  # mirror audit keeps attachments and exports in lockstep):
1203
1229
  # recover diagnostics (#1200), the standalone DTD family
@@ -1231,9 +1257,9 @@ attach_function :leptris_parse_string,
1231
1257
  [:pointer, :pointer], :void
1232
1258
  # Thread-local since v1.3.0; reliable under the
1233
1259
  # one-document-per-thread contract.
1234
- attach_function :leptris_last_error, [], :string
1260
+ attach_function :leptris_last_error, [], UTF8_STRING
1235
1261
  attach_function :leptris_document_last_error,
1236
- [:leptris_document], :string
1262
+ [:leptris_document], UTF8_STRING
1237
1263
  # Optional: release per-thread registry entries when a worker
1238
1264
  # thread exits (long-lived threads never need it).
1239
1265
  attach_function :leptris_thread_cleanup, [], :void
Binary file
@@ -545,6 +545,34 @@ class Leptris::XML::Node
545
545
  self
546
546
  end
547
547
 
548
+ # Visits the subtree with ONE C call, yielding ONCE per node
549
+ # (leptris_node_visit_entering, libleptris #1332): every node —
550
+ # elements included — yields (node, true, depth) exactly once, on
551
+ # entering. Halves the C-callback invocations against #visit for
552
+ # walks that never acted on the leaving half (the family-walk
553
+ # shape); the halving happens in the engine, not in a per-node
554
+ # Ruby filter. Same order and depths as #visit; read-only.
555
+ #
556
+ # root.visit_entering { |node, entering, depth| ... }
557
+ def visit_entering(&block)
558
+ return enum_for(:visit_entering) unless block
559
+ ensure_alive!
560
+ if @addr_reads_fast
561
+ Leptris::XML::Native.visit_entering_binding(@document,
562
+ @c_address, &block)
563
+ return self
564
+ end
565
+ document = @document
566
+ visitor = ::FFI::Function.new(
567
+ :void, [:pointer, :pointer, :int, :int], blocking: true) do |_, node_ptr, entering, depth|
568
+ block.call(
569
+ Leptris::XML::Node.wrap(node_ptr, document),
570
+ entering == 1, depth)
571
+ end
572
+ Leptris::XML::FFI.leptris_node_visit_entering(c_ptr, visitor, nil)
573
+ self
574
+ end
575
+
548
576
  # Walks the subtree in post-order DFS (matches Nokogiri's
549
577
  # semantics): the receiver, its descendants, nothing else.
550
578
  #
data/lib/libleptris.so CHANGED
Binary file
data/vendor-src/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  Sources vendored in this gem (recompile rights; the ruby
2
2
  variant builds them at install via extconf.rb):
3
3
 
4
- - libleptris v1.9.231
4
+ - libleptris v1.9.232
5
5
  - utf8proc v2.11.0
6
6
 
7
7
  Rebuild by hand:
@@ -1,5 +1,20 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.9.232] - 2026-09-24
4
+
5
+ ### Added
6
+
7
+ - QT3 corpus slice 4 — sequence-edit + codepoint families, 501 gated cases; seq member fidelity fixes (xquery)
8
+ - entering-only visit mode — leptris_node_visit_entering (#1332) (dom)
9
+
10
+ ### Fixed
11
+
12
+ - range A to B with an empty operand yields the empty sequence (xpath)
13
+ - expand character and predefined entity references in string literals (xpath)
14
+ - prefixed wire names bind namespaced elements (XSD-002 fallout) (descriptor)
15
+
16
+
17
+
3
18
  ## [1.9.231] - 2026-09-23
4
19
 
5
20
  ### Fixed
@@ -3,7 +3,7 @@
3
3
  cmake_minimum_required(VERSION 3.20)
4
4
 
5
5
  project(leptris
6
- VERSION 1.9.231
6
+ VERSION 1.9.232
7
7
  DESCRIPTION "Fast XML parser and XPath evaluator in pure C"
8
8
  LANGUAGES C CXX
9
9
  )
@@ -98,7 +98,11 @@ typedef struct {
98
98
  } leptris_attr_plan;
99
99
 
100
100
  typedef struct {
101
- const char* wire_name; /* XML element name as it appears on the wire */
101
+ const char* wire_name; /* XML element name as it appears on the wire:
102
+ * the prefixed form ("w:b") binds that literal
103
+ * prefix+local pair; the bare local form ("b")
104
+ * binds by local name and lets ns_form do the
105
+ * namespace work */
102
106
  uint8_t kind; /* LeptrisPlanKind */
103
107
  uint8_t type_tag; /* host-defined; echoed back verbatim */
104
108
  int32_t child_plan_index; /* NESTED: index into leptris_plan_spec.plans;
@@ -1195,6 +1195,23 @@ LEPTRIS_API void leptris_node_visit(LeptrisNodeRef root,
1195
1195
  LeptrisNodeVisitor visitor,
1196
1196
  void* user_data);
1197
1197
 
1198
+ /**
1199
+ * Entering-only subtree visitation (issue #1332)
1200
+ *
1201
+ * Same walk as leptris_node_visit — document order, same depths —
1202
+ * but the callback fires ONCE per node, on entering. Elements are
1203
+ * not re-visited after their subtree. Halves the C-callback
1204
+ * invocations for consumers that only act on entering=1 (the lazy
1205
+ * family-walk shape).
1206
+ *
1207
+ * @param root Subtree root (any node kind, or a document node)
1208
+ * @param visitor Callback per node (may be NULL — no-op)
1209
+ * @param user_data Opaque context for the callback
1210
+ */
1211
+ LEPTRIS_API void leptris_node_visit_entering(LeptrisNodeRef root,
1212
+ LeptrisNodeVisitor visitor,
1213
+ void* user_data);
1214
+
1198
1215
  /**
1199
1216
  * Count the document's top-level processing instructions
1200
1217
  *