leptris 1.9.292.0-ppc64le-linux → 1.9.302.0-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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +23 -0
- data/Rakefile +1 -1
- data/lib/leptris/version.rb +1 -1
- data/lib/libleptris.so +0 -0
- data/vendor-src/README.md +1 -1
- data/vendor-src/libleptris/CHANGELOG.md +331 -0
- data/vendor-src/libleptris/CMakeLists.txt +6 -1
- data/vendor-src/libleptris/benchmarks/modification/bench_append_attr_pugixml.cpp +36 -0
- data/vendor-src/libleptris/bindings/rust/Cargo.lock +1 -1
- data/vendor-src/libleptris/bindings/rust/Cargo.toml +3 -1
- data/vendor-src/libleptris/cli/CLI_ARCHITECTURE.md +1 -1
- data/vendor-src/libleptris/cli/CMakeLists.txt +1 -0
- data/vendor-src/libleptris/cli/cli.c +36 -1
- data/vendor-src/libleptris/cli/cli.h +39 -2
- data/vendor-src/libleptris/cli/commands/xquery.c +1 -31
- data/vendor-src/libleptris/cli/commands/xslt.c +118 -0
- data/vendor-src/libleptris/cli/main.c +24 -22
- data/vendor-src/libleptris/cli/man/leptris-diff.1.adoc +40 -0
- data/vendor-src/libleptris/cli/man/leptris-validate.1.adoc +43 -0
- data/vendor-src/libleptris/cli/man/leptris-xquery.1.adoc +44 -0
- data/vendor-src/libleptris/cli/man/leptris-xslt.1.adoc +49 -0
- data/vendor-src/libleptris/src/CMakeLists.txt +26 -0
- data/vendor-src/libleptris/src/leptris/dom/compact.c +4 -0
- data/vendor-src/libleptris/src/leptris/dom/element_modify.c +21 -18
- data/vendor-src/libleptris/src/leptris/dom/mut_recycle.c +112 -0
- data/vendor-src/libleptris/src/leptris/dom/mut_recycle.h +50 -0
- data/vendor-src/libleptris/src/leptris/leptris.c +10 -4
- data/vendor-src/libleptris/src/leptris/leptris_internal.h +7 -0
- data/vendor-src/libleptris/src/leptris/xpath/collation.c +494 -0
- data/vendor-src/libleptris/src/leptris/xpath/collation.h +66 -0
- data/vendor-src/libleptris/src/leptris/xpath/ducet_table.h +21994 -0
- data/vendor-src/libleptris/src/leptris/xpath/evaluator_internal.h +6 -0
- data/vendor-src/libleptris/src/leptris/xpath/evaluator_operators.c +53 -5
- data/vendor-src/libleptris/src/leptris/xpath/evaluator_types.c +53 -8
- data/vendor-src/libleptris/src/leptris/xpath/functions.c +506 -67
- data/vendor-src/libleptris/src/leptris/xpath/functions_ext31.c +572 -64
- data/vendor-src/libleptris/src/leptris/xpath/vm.c +20 -4
- data/vendor-src/libleptris/src/leptris/xpath/xpath_public.c +3 -1
- data/vendor-src/libleptris/src/leptris/xquery/xquery.c +23 -1
- data/vendor-src/libleptris/test/CMakeLists.txt +14 -0
- data/vendor-src/libleptris/test/cli/test_cli.cpp +61 -0
- data/vendor-src/libleptris/test/memory/test_mut_recycle.cpp +64 -0
- data/vendor-src/libleptris/test/xpath/test_collation.cpp +147 -0
- data/vendor-src/libleptris/test/xpath/test_xslt.cpp +114 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/abs.xml +2085 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/apply.xml +214 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/avg.xml +2199 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/ceiling.xml +961 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/collation-key.xml +331 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/filter.xml +387 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/floor.xml +968 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/fold-left.xml +426 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/fold-right.xml +363 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/for-each-pair.xml +585 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/for-each.xml +170 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/max.xml +2018 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/min.xml +1973 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/round-half-to-even.xml +1336 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/round.xml +2539 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/sum.xml +2043 -0
- data/vendor-src/libleptris/test/xquery/qt3/misc/UCACollation.xml +1120 -0
- data/vendor-src/libleptris/test/xquery/test_qt3.cpp +226 -14
- data/vendor-src/libleptris/test/xquery/test_xquery.cpp +208 -0
- data/vendor-src/libleptris/tools/gen_ducet_table.py +110 -0
- data/vendor-src/libleptris/vcpkg.json +1 -1
- data/vendor-src/libleptris/vendor/ducet/allkeys.txt +39435 -0
- metadata +33 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2764954457c94ab3a836428d2e5fbe63235ce201e99c92446573030d489e1b6a
|
|
4
|
+
data.tar.gz: 33f05143b2d66134a8261bdb45665b800eec9a5edcca3f455d6f4249c47901b6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: abfce50cca667748bb0fee5e17aa61e1980d298238c94a431075fc3d8e5b4fd1f574c2915c7a5990b868822d3e98bbc1980c192430187213695020a65484f7c0
|
|
7
|
+
data.tar.gz: 2d1a21dd0b38bf9aab1a407eda3d21614c606037c23c5444fc3ea0ac6d500636151c49c4f950a4d374da540938c05c0c83c32e6f38087cb45d49c01b1986cb98
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,26 @@
|
|
|
1
|
+
## [1.9.302.0] - 2026-10-05
|
|
2
|
+
|
|
3
|
+
### Engine sync (libleptris 1.9.293-1.9.302)
|
|
4
|
+
|
|
5
|
+
Ten upstream releases ride in this pin — internal fixes and
|
|
6
|
+
performance with NO binding-surface changes (zero header deltas
|
|
7
|
+
292..302; the audit gate confirms 363/362 unchanged). Highlights:
|
|
8
|
+
|
|
9
|
+
- **XQuery correctness**: a false() bound anywhere read as truthy;
|
|
10
|
+
fn:not uses the effective boolean value; fn:abs(()) is empty;
|
|
11
|
+
string lt/gt are codepoint comparisons; fn:avg edge shapes;
|
|
12
|
+
aggregates atomize array arguments; `instance of xs:integer`
|
|
13
|
+
demands integrality; xs:byte/unsignedByte/unsignedInt
|
|
14
|
+
constructors; fn:sum#2's zero argument.
|
|
15
|
+
- **Collation**: UCA over the vendored DUCET table (slices 1-4) —
|
|
16
|
+
fn:normalize-unicode F&O conformance, collation-aware string
|
|
17
|
+
functions, 71+1078 QT3 cases adopted, implicit weights and
|
|
18
|
+
alternate=blanked.
|
|
19
|
+
- **Performance**: per-thread recycle of mutation blocks (DOM
|
|
20
|
+
create/build/free).
|
|
21
|
+
- **Rust bindings**: first tokenless crates.io release (leptris
|
|
22
|
+
v1.4.1) from CI.
|
|
23
|
+
|
|
1
24
|
## [1.9.292.0] - 2026-10-03
|
|
2
25
|
|
|
3
26
|
### 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.
|
|
11
|
+
LIBLEPTRIS_VERSION = "1.9.302"
|
|
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
|
data/lib/leptris/version.rb
CHANGED
data/lib/libleptris.so
CHANGED
|
Binary file
|
data/vendor-src/README.md
CHANGED
|
@@ -1,5 +1,336 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [1.9.302] - 2026-10-04
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **XQuery: aggregates atomize array arguments** — `fn:avg`,
|
|
8
|
+
`fn:sum`, `fn:min` and `fn:max` take `xs:anyAtomicType*`, so a
|
|
9
|
+
dense array argument now contributes its members instead of
|
|
10
|
+
leaking the internal carrier: `avg([1,2,3,4,5])` = 3,
|
|
11
|
+
`sum([1,2,3,4,5])` = 15 (fn-avg-10, fn-sum-11, fn-min-19,
|
|
12
|
+
fn-max-19). A new shared decoder turns carriers keyed exactly
|
|
13
|
+
1..n into positional members, recursing into nested arrays
|
|
14
|
+
(`[[1,2],[3]]` → 1,2,3); maps and sparse carriers stay single
|
|
15
|
+
items, and `item()`-typed functions such as `fn:count` still see
|
|
16
|
+
an array as one item, per XDM. `fn:sum`'s per-item accumulation
|
|
17
|
+
moved into a helper so atomized members feed the existing
|
|
18
|
+
int64-exact and xs:float channels unchanged.
|
|
19
|
+
- **XQuery: `instance of` over the integer family demands
|
|
20
|
+
integrality** — `xs:integer` and its derived types
|
|
21
|
+
(int/long/short/byte/unsigned*/nonNegative…) now require an
|
|
22
|
+
integral value on both the sequence-member and scalar paths:
|
|
23
|
+
`fn:abs(1.1) instance of xs:integer` is false,
|
|
24
|
+
`fn:abs(-3) instance of xs:integer` is true.
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- **XQuery: `fn:avg` edge shapes** — `avg(())` returns the empty
|
|
29
|
+
sequence under XQuery (XPath 1.0 parity untouched), and averages
|
|
30
|
+
over `xs:yearMonthDuration` format through the shared months
|
|
31
|
+
formatter (cbcl-avg-006: `P1Y`). Also freed a nested-array
|
|
32
|
+
carrier on an allocation-failure path in the atomizing decoder.
|
|
33
|
+
- QT3 re-pins from one verified run: fn/avg 164→173, fn/max
|
|
34
|
+
165→167, fn/min 165→167, fn/sum 203→204 (+14 adopted cases;
|
|
35
|
+
total pins 1134 → 1148; 61/61 suites green).
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
## [1.9.301] - 2026-10-04
|
|
40
|
+
|
|
41
|
+
### Fixed
|
|
42
|
+
|
|
43
|
+
- **XQuery: a false() bound anywhere read as truthy** — values
|
|
44
|
+
stringified to a marker-less "false" that every effective-boolean-
|
|
45
|
+
value site saw as a non-empty string, so `let $x := false() return
|
|
46
|
+
if ($x)...` took the then-branch and fold accumulators ignored a
|
|
47
|
+
false() zero (fold-left-004). Variable bindings, local:function
|
|
48
|
+
thunk arguments and the fold accumulators/items now carry the
|
|
49
|
+
boolean type marker; the EBV read honors it on singleton synthetic
|
|
50
|
+
members (XML 1.0 forbids raw control characters in text content,
|
|
51
|
+
so the marker cannot collide with document data); named-reference
|
|
52
|
+
closure calls spell marked booleans back to literals; both string
|
|
53
|
+
consumers render them as true/false. (PR #1522)
|
|
54
|
+
|
|
55
|
+
- **fn:not uses the effective boolean value** — not(false()) is
|
|
56
|
+
true while fn:empty((false())) stays false; real nodes keep the
|
|
57
|
+
XPath 1.0 existence rule, so libxml2 parity is unchanged.
|
|
58
|
+
(PR #1522)
|
|
59
|
+
|
|
60
|
+
- **fn:abs(()) is the empty sequence** under the XQuery surface;
|
|
61
|
+
**fn:sum((), $zero) returns a non-numeric zero verbatim**
|
|
62
|
+
(sum((), xs:dayTimeDuration("PT0S")) = PT0S); **fn:avg over
|
|
63
|
+
dayTimeDurations** divides the total seconds and formats
|
|
64
|
+
(fn-avg-4: PT5H30M); and the kept lexical zero in fn:sum is freed
|
|
65
|
+
on every result path (a Linux ASAN catch — macOS has no leak
|
|
66
|
+
sanitizer). (PR #1522)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
## [1.9.300] - 2026-10-04
|
|
71
|
+
|
|
72
|
+
### Added
|
|
73
|
+
|
|
74
|
+
- **XQuery: the xs:float and int64 typed-atom channels survive the
|
|
75
|
+
numeric function hop (+49 QT3 agreements; the fifteen-family batch
|
|
76
|
+
pins rise 1078→1127 and fn:round is fully green at 220/220)**.
|
|
77
|
+
fn:abs, fn:round, fn:round-half-to-even and the avg/min/max
|
|
78
|
+
aggregates copy the float tag onto their results (round over
|
|
79
|
+
xs:float("3.4028235E38") spells 3.4028235E38, not the widened
|
|
80
|
+
double digits); fn:sum keeps an exact long-long total when every
|
|
81
|
+
member is an integer lexical (fn:sum#2's zero seeds it); fn:floor,
|
|
82
|
+
fn:ceiling, fn:round and fn:abs pass int64 atoms through unchanged
|
|
83
|
+
(floor(xs:integer("999999999999999999")) stays exact, not 1e18).
|
|
84
|
+
(PR #1520)
|
|
85
|
+
|
|
86
|
+
- **xs:byte, xs:unsignedByte and xs:unsignedInt constructors** —
|
|
87
|
+
the three integer subtypes were unregistered and errored as
|
|
88
|
+
unknown functions. (PR #1520)
|
|
89
|
+
|
|
90
|
+
### Fixed
|
|
91
|
+
|
|
92
|
+
- **is_int results now also carry the double field** — eq and
|
|
93
|
+
boolean() comparisons read number_value, which the int64 path
|
|
94
|
+
left unset (sum((3,4,5)) eq 12 was false). (PR #1520)
|
|
95
|
+
|
|
96
|
+
- **The float-precision speller snaps into the float domain before
|
|
97
|
+
spelling** — double arithmetic can leave a non-float-representable
|
|
98
|
+
value whose shortest float round-trip never terminates, spelling
|
|
99
|
+
18-digit mantissas. (PR #1520)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
## [1.9.299] - 2026-10-04
|
|
104
|
+
|
|
105
|
+
### Added
|
|
106
|
+
|
|
107
|
+
- **XQuery: 1078 QT3 cases adopted across fifteen fn families** —
|
|
108
|
+
the numeric aggregates and rounding set (abs, avg, ceiling, floor,
|
|
109
|
+
max, min, round, round-half-to-even, sum) plus the higher-order
|
|
110
|
+
combiners (apply, filter, for-each, for-each-pair, fold-left,
|
|
111
|
+
fold-right), vendored verbatim from the upstream QT3 mirror. The
|
|
112
|
+
named per-suite excludes document the typed-atom lane's remaining
|
|
113
|
+
levers (xs:float spelling through aggregates, int64-exact
|
|
114
|
+
multi-argument sums, instance-of results). (PR #1518)
|
|
115
|
+
|
|
116
|
+
- **fn:sum#2** — the zero argument returns its value for the empty
|
|
117
|
+
sequence: fn:sum((1,2,3), 10) = 16, fn:sum((), 5) = 5.
|
|
118
|
+
(PR #1518)
|
|
119
|
+
|
|
120
|
+
### Fixed
|
|
121
|
+
|
|
122
|
+
- **Number spelling destroyed integral magnitudes** — the shared
|
|
123
|
+
trailing-zero trim ran on dot-free integer renderings, so 1e18
|
|
124
|
+
spelled "1"; it now runs only when a decimal point is present.
|
|
125
|
+
Negative zero also spells "-0" (fn:round(-0.01) = -0), and
|
|
126
|
+
fn:round preserves -0 for inputs in (-0.5, 0). (PR #1518)
|
|
127
|
+
|
|
128
|
+
- **Value carriers overflowed at DBL_MAX** — the ext31 string
|
|
129
|
+
carrier used the libxml2-parity printer, which renders DBL_MAX
|
|
130
|
+
with 18 significant digits; strtod read-back of that string
|
|
131
|
+
overflows to infinity, so fn:avg((1.7976931348623157E308)) was
|
|
132
|
+
INF. Carriers now use the injective shortest-round-trip spelling.
|
|
133
|
+
(PR #1518)
|
|
134
|
+
|
|
135
|
+
- **fn:sum rejected non-nodeset arguments** — single-item sequences
|
|
136
|
+
(passed as scalars by the XQuery adapter) errored out. (PR #1518)
|
|
137
|
+
|
|
138
|
+
- **fn:round()/fn:round-half-to-even(()) now return the empty
|
|
139
|
+
sequence** under the XQuery surface; XPath 1.0 coercion stays NaN
|
|
140
|
+
(libxml2 parity unchanged). (PR #1518)
|
|
141
|
+
|
|
142
|
+
- **fn:max/fn:min over non-numeric items** (xs:string, xs:anyURI)
|
|
143
|
+
compare in codepoint order and return the extreme item instead of
|
|
144
|
+
coercing to zero. (PR #1518)
|
|
145
|
+
|
|
146
|
+
- **QT3 runner: the standard `emptydoc`/`empty` environments
|
|
147
|
+
resolve to the empty context** — cases carrying them were
|
|
148
|
+
silently skipped (the abs/ceiling/floor/fold-* families adopted
|
|
149
|
+
zero cases before this). (PR #1518)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
## [1.9.298] - 2026-10-04
|
|
154
|
+
|
|
155
|
+
### Added
|
|
156
|
+
|
|
157
|
+
- **XPath/XQuery: the six remaining string functions honor UCA
|
|
158
|
+
collations (DUCET lane closed)** — starts-with, ends-with,
|
|
159
|
+
contains, substring-before, substring-after and deep-equal now
|
|
160
|
+
route `http://www.w3.org/2013/collation/UCA` URIs through the
|
|
161
|
+
collation module. Matching scans codepoint-aligned windows under
|
|
162
|
+
the collation compare (every collation-unit boundary falls
|
|
163
|
+
between codepoints, so the scan is exact across contractions and
|
|
164
|
+
normalization); substring-before/after slice the leftmost-shortest
|
|
165
|
+
occurrence. deep-equal threads the collation into plain string
|
|
166
|
+
atoms and map values, while \x03-marked carriers keep their
|
|
167
|
+
value-space equality. **QT3 adoption rises by 73 cases**:
|
|
168
|
+
contains 46→63, starts-with 43→56, ends-with 34→48,
|
|
169
|
+
substring-before 12→26, substring-after 16→29, deep-equal
|
|
170
|
+
221→223. (PR #1515)
|
|
171
|
+
|
|
172
|
+
- **Collation: UCA 7.1.1 implicit weights** — codepoints with no
|
|
173
|
+
DUCET mapping sort by the two-CE algorithm: the registered
|
|
174
|
+
@implicitweights ranges (Tangut/Tangut-Supplement base FB00,
|
|
175
|
+
Khitan FB02, Nushu FB01) order ahead of the unassigned groups
|
|
176
|
+
(base 0xFB80 + 2*(cp>>15)), each codepoint emitting an
|
|
177
|
+
even/odd CE pair that orders within its group by codepoint.
|
|
178
|
+
(PR #1515)
|
|
179
|
+
|
|
180
|
+
- **Collation: `alternate=blanked`** (fn-contains-35..38) — the
|
|
181
|
+
third W3C UCA variable-weighting value is accepted, and variable
|
|
182
|
+
collation elements now leave every ordinary level under
|
|
183
|
+
shifted/blanked weighting (shifted retains its quaternary
|
|
184
|
+
re-add; blanked drops them wholly — ICU variable semantics).
|
|
185
|
+
(PR #1515)
|
|
186
|
+
|
|
187
|
+
- **CLI: `leptris xslt` command** — apply a stylesheet to a
|
|
188
|
+
document and print the serialized result tree:
|
|
189
|
+
`leptris xslt -s style.xsl input.xml`. Conventions match
|
|
190
|
+
xsltproc: INPUT is a file path, `-` or absent reads stdin. The
|
|
191
|
+
stylesheet compiles via leptris_xslt_parse_file, so
|
|
192
|
+
xsl:include/xsl:import resolve relative to the sheet. New
|
|
193
|
+
CLI_ERROR_XSLT exit code (7). (PR #1516)
|
|
194
|
+
|
|
195
|
+
- **CLI: man pages for every command** — new leptris-xslt.1 plus
|
|
196
|
+
the missing leptris-xquery.1, leptris-diff.1 and
|
|
197
|
+
leptris-validate.1, all registered for generation. (PR #1516)
|
|
198
|
+
|
|
199
|
+
### Fixed
|
|
200
|
+
|
|
201
|
+
- **CLI: `--help` was missing registered commands** — the usage
|
|
202
|
+
text hand-maintained its own command list, so the registered
|
|
203
|
+
`diff` and `xquery` commands were invisible. The help listing
|
|
204
|
+
now iterates the command registry (the descriptors are the
|
|
205
|
+
single source of truth), and adding a command can no longer
|
|
206
|
+
leave help stale. xquery's private stream reader is promoted to
|
|
207
|
+
shared cli_read_stream/cli_read_file. (PR #1516)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
## [1.9.297] - 2026-10-03
|
|
212
|
+
|
|
213
|
+
### Fixed
|
|
214
|
+
|
|
215
|
+
- **XQuery: string lt/gt are codepoint value comparisons** — the
|
|
216
|
+
shared XPath 1.0 comparison numeric-coerced strings, so two
|
|
217
|
+
collation-keys that both spell numbers compared as equal numbers.
|
|
218
|
+
Both comparison sites now codepoint-compare string operands when
|
|
219
|
+
the evaluation is XQuery-flavored (the evaluator's string branch
|
|
220
|
+
and the VM twin); XPath 1.0 evaluation is unchanged.
|
|
221
|
+
(PR #1513)
|
|
222
|
+
|
|
223
|
+
- **XQuery: fn:codepoints-to-string encodes every item of its
|
|
224
|
+
sequence argument** — the collector collapsed a parenthesized
|
|
225
|
+
sequence to one scalar (its space-joined spelling), so
|
|
226
|
+
(37, 65500, 37) encoded as just the first codepoint. Collation-key
|
|
227
|
+
adoption rises to 12/56 run-and-agree. (PR #1513)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
## [1.9.296] - 2026-10-03
|
|
232
|
+
|
|
233
|
+
### Added
|
|
234
|
+
|
|
235
|
+
- **XPath/XQuery: 71 QT3 collation cases adopted (DUCET slice 4)** —
|
|
236
|
+
the misc/UCACollation corpus (62 cases: the UCA ordering battery
|
|
237
|
+
over DUCET weights) and fn/collation-key (9 cases). The collation
|
|
238
|
+
URI grammar now parses the W3C semicolon-separated parameter form,
|
|
239
|
+
accepts lang= (DUCET is the root locale), and applies
|
|
240
|
+
caseFirst=upper|lower by swapping the DUCET case tertiaries.
|
|
241
|
+
fn:collation-key gains its 1-argument form (the static default
|
|
242
|
+
collation; codepoint keys are the UTF-8 bytes) and its keys are
|
|
243
|
+
lowercase hex — injective AND order-preserving, so lt/gt on two
|
|
244
|
+
keys is byte-wise key order. The QT3 runner now credits an
|
|
245
|
+
error alternative inside any-of for a failed evaluation, gates the
|
|
246
|
+
optional simple-uca-fallback feature (this engine raises FOCH0002
|
|
247
|
+
per the strict F&O reading), and lifts the pre-DUCET
|
|
248
|
+
collation/UCA exclusion under a DUCET build. (PR #1511)
|
|
249
|
+
|
|
250
|
+
### Fixed
|
|
251
|
+
|
|
252
|
+
- the DUCET implicit-weight fallback dropped a mask that broke
|
|
253
|
+
ordering between high codepoints. (PR #1511)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
## [1.9.295] - 2026-10-03
|
|
258
|
+
|
|
259
|
+
### Added
|
|
260
|
+
|
|
261
|
+
- **XPath: collation-aware functions over the vendored DUCET
|
|
262
|
+
(slices 2-3)** — fn:compare's 3-argument form honors its collation
|
|
263
|
+
URI (unknown needed collations raise FOCH0002; unknown-but-unneeded
|
|
264
|
+
ones are ignored per the QT3 any-of expectations);
|
|
265
|
+
fn:collation-key($key, $collation) is new, returning the UCA sort
|
|
266
|
+
key as base64 text (the result-type enum is ABI-frozen with no
|
|
267
|
+
binary kind; base64 is injective, so key equality is byte equality);
|
|
268
|
+
fn:index-of, fn:distinct-values and fn:sort route plain-string
|
|
269
|
+
comparisons through the collation while typed atoms keep their
|
|
270
|
+
value-space equality. DUCET-gated: builds without utf8proc keep the
|
|
271
|
+
previous behavior. (PRs #1508, #1509)
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
## [1.9.294] - 2026-10-03
|
|
276
|
+
|
|
277
|
+
### Added
|
|
278
|
+
|
|
279
|
+
- **XPath: UCA collation over the vendored DUCET table (slice 1)** —
|
|
280
|
+
`http://www.w3.org/2013/collation/UCA` collation URIs parse
|
|
281
|
+
`strength` and `alternate` parameters per F&O 3.x (defaults:
|
|
282
|
+
tertiary, non-ignorable) and compare through multi-level sort keys:
|
|
283
|
+
NFD (utf8proc) → DUCET weights (Unicode 16.0.0, 38,443 single
|
|
284
|
+
codepoints + 964 contractions, vendored with an offline table
|
|
285
|
+
generator) → primary/secondary/tertiary levels with 0x00
|
|
286
|
+
separators; `alternate=shifted` demotes variable primaries to the
|
|
287
|
+
quaternary level. Codepoint and html-ascii-case-insensitive
|
|
288
|
+
collations keep their semantics. Unmapped codepoints get a coarse
|
|
289
|
+
deterministic fallback (the full UCA 7.1.1 implicit-weight
|
|
290
|
+
algorithm is a later slice). New CMake option
|
|
291
|
+
`LEPTRIS_ENABLE_DUCET` (default on, requires utf8proc; builds
|
|
292
|
+
without utf8proc degrade to codepoint collation). Function
|
|
293
|
+
wiring (fn:compare, fn:collation-key, default collation) and
|
|
294
|
+
QT3 UCA case adoption are the next slices. (PR #1506)
|
|
295
|
+
|
|
296
|
+
- **XQuery: fn:normalize-unicode F&O conformance** — the
|
|
297
|
+
single-argument form normalizes with NFC instead of returning the
|
|
298
|
+
input unchanged; unknown normalization forms raise FOCH0003
|
|
299
|
+
instead of silently falling back to NFC; the form argument is
|
|
300
|
+
case-insensitive with surrounding whitespace tolerated
|
|
301
|
+
(FULLY-NORMALIZED is gone from F&O 3.x; its satisfied="false"
|
|
302
|
+
twins run). utf8proc-gated end to end; the 29-run
|
|
303
|
+
fn/normalize-unicode QT3 family is adopted. (PR #1505)
|
|
304
|
+
|
|
305
|
+
### Fixed
|
|
306
|
+
|
|
307
|
+
- DUCET builds without utf8proc (cppcheck leg, Rust lane, ILP32,
|
|
308
|
+
Windows static) degrade to codepoint collation with a warning
|
|
309
|
+
instead of failing the configure. (PR #1506)
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
## [1.9.293] - 2026-10-03
|
|
314
|
+
|
|
315
|
+
### Performance
|
|
316
|
+
|
|
317
|
+
- DOM: per-thread recycle of mutation blocks. Document create/build/free
|
|
318
|
+
cycles now park their elem (45KB), name (4KB) and attr (5KB) blocks on
|
|
319
|
+
thread-local free-lists instead of returning them to malloc — the next
|
|
320
|
+
cycle carves from hot pages instead of re-faulting fresh ones. Byte-capped
|
|
321
|
+
(8MB elem, 4MB name/attr); POSIX threads drain via a pthread_key
|
|
322
|
+
destructor at thread exit, and `leptris_explicit_cleanup()` drains
|
|
323
|
+
synchronously. Mutation doc-cycle row: 19.4 → 15.1 ns/child (−22%), gap
|
|
324
|
+
to pugixml on that shape narrows 1.66x → 1.29x. Single-document append
|
|
325
|
+
throughput is unchanged. (PR #1503)
|
|
326
|
+
|
|
327
|
+
### Rust bindings
|
|
328
|
+
|
|
329
|
+
- First fully tokenless crates.io release: leptris v1.4.1 published from CI
|
|
330
|
+
via crates.io Trusted Publishing (`rust-lang/crates-io-auth-action` —
|
|
331
|
+
cargo itself has no native OIDC support). The Rust release lane now needs
|
|
332
|
+
no registry token of any kind. (PRs #1497, #1499–#1502)
|
|
333
|
+
|
|
3
334
|
## [1.9.292] - 2026-10-02
|
|
4
335
|
|
|
5
336
|
### Added
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
cmake_minimum_required(VERSION 3.20)
|
|
4
4
|
|
|
5
5
|
project(leptris
|
|
6
|
-
VERSION 1.9.
|
|
6
|
+
VERSION 1.9.302
|
|
7
7
|
DESCRIPTION "Fast XML parser and XPath evaluator in pure C"
|
|
8
8
|
LANGUAGES C CXX
|
|
9
9
|
)
|
|
@@ -30,6 +30,7 @@ option(LEPTRIS_BUILD_MAN_PAGES "Generate man pages with asciidoctor" OFF)
|
|
|
30
30
|
option(LEPTRIS_BUILD_BENCHMARKS "Build performance benchmarks" OFF)
|
|
31
31
|
option(LEPTRIS_ENABLE_UTF8PROC "Enable Unicode support via utf8proc" ON)
|
|
32
32
|
option(LEPTRIS_ENABLE_ICONV "Enable encoding conversion via iconv" ON)
|
|
33
|
+
option(LEPTRIS_ENABLE_DUCET "Vendor DUCET table for UCA collation (requires utf8proc)" ON)
|
|
33
34
|
option(LEPTRIS_ENABLE_ASAN "Enable AddressSanitizer (catches heap bugs at runtime)" OFF)
|
|
34
35
|
option(LEPTRIS_ENABLE_FUZZING "Build libFuzzer harness" OFF)
|
|
35
36
|
option(LEPTRIS_BUILD_DOCS "Build Doxygen API docs" OFF)
|
|
@@ -341,6 +342,10 @@ if(LEPTRIS_BUILD_CLI AND LEPTRIS_BUILD_MAN_PAGES)
|
|
|
341
342
|
cli/man/leptris-parse.1.adoc
|
|
342
343
|
cli/man/leptris-xpath.1.adoc
|
|
343
344
|
cli/man/leptris-format.1.adoc
|
|
345
|
+
cli/man/leptris-validate.1.adoc
|
|
346
|
+
cli/man/leptris-diff.1.adoc
|
|
347
|
+
cli/man/leptris-xquery.1.adoc
|
|
348
|
+
cli/man/leptris-xslt.1.adoc
|
|
344
349
|
)
|
|
345
350
|
|
|
346
351
|
foreach(ADOC_SOURCE ${ADOC_MAN_SOURCES})
|
|
@@ -44,6 +44,42 @@ int main(void) {
|
|
|
44
44
|
(t1 - t0) / N_APPEND);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
/* ---- mut-doc-cycle: 20k create/build/free cycles, 1024
|
|
48
|
+
* children each (1 elem block + ~7 name blocks per cycle). The
|
|
49
|
+
* mut-block recycle target: without it every cycle frees those
|
|
50
|
+
* blocks back to malloc (madvise) and the next cycle re-mallocs
|
|
51
|
+
* and re-faults them on the carve memsets. */
|
|
52
|
+
const int N_CYCLE = 20000;
|
|
53
|
+
const int CYCLE_CHILDREN = 1024;
|
|
54
|
+
{
|
|
55
|
+
double t0 = now_ns();
|
|
56
|
+
for (int i = 0; i < N_CYCLE; i++) {
|
|
57
|
+
LeptrisDocument d = leptris_document_create();
|
|
58
|
+
LeptrisElement root = leptris_element_create(d, "root");
|
|
59
|
+
leptris_document_set_root(d, root);
|
|
60
|
+
for (int c = 0; c < CYCLE_CHILDREN; c++) {
|
|
61
|
+
LeptrisElement e = leptris_element_create(d, "c");
|
|
62
|
+
leptris_element_append_child(root, e);
|
|
63
|
+
}
|
|
64
|
+
leptris_document_free(d);
|
|
65
|
+
}
|
|
66
|
+
double t1 = now_ns();
|
|
67
|
+
printf("mutcycle leptris: %7.1f ns/child\n",
|
|
68
|
+
(t1 - t0) / ((double)N_CYCLE * CYCLE_CHILDREN));
|
|
69
|
+
}
|
|
70
|
+
{
|
|
71
|
+
double t0 = now_ns();
|
|
72
|
+
for (int i = 0; i < N_CYCLE; i++) {
|
|
73
|
+
pugi::xml_document d;
|
|
74
|
+
pugi::xml_node root = d.append_child("root");
|
|
75
|
+
for (int c = 0; c < CYCLE_CHILDREN; c++)
|
|
76
|
+
root.append_child("c");
|
|
77
|
+
}
|
|
78
|
+
double t1 = now_ns();
|
|
79
|
+
printf("mutcycle pugixml: %7.1f ns/child\n",
|
|
80
|
+
(t1 - t0) / ((double)N_CYCLE * CYCLE_CHILDREN));
|
|
81
|
+
}
|
|
82
|
+
|
|
47
83
|
/* ---- attr-parse: parse 20k docs, 4 elems x 16 attrs ---- */
|
|
48
84
|
std::string xml = "<r>";
|
|
49
85
|
for (int e = 0; e < 4; e++) {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "leptris"
|
|
3
|
-
version = "1.4.
|
|
3
|
+
version = "1.4.1"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
description = "Rust bindings for libleptris — fast XML 1.0 parsing, XPath 1.0, SAX"
|
|
6
6
|
license = "MIT"
|
|
7
7
|
readme = "README.md"
|
|
8
|
+
repository = "https://github.com/leptris/leptris"
|
|
9
|
+
homepage = "https://www.leptris.org"
|
|
8
10
|
links = "leptris"
|
|
9
11
|
build = "build.rs"
|
|
10
12
|
|
|
@@ -73,7 +73,7 @@ The Leptris CLI is a **thin layer** on top of the C library API (`libleptris`).
|
|
|
73
73
|
|
|
74
74
|
Every aspect of the CLI follows MECE principles:
|
|
75
75
|
|
|
76
|
-
- **Commands**: Each command has distinct responsibility (parse, xpath, format, version)
|
|
76
|
+
- **Commands**: Each command has distinct responsibility (parse, validate, xpath, format, diff, xquery, xslt, version — the registry is the single source of truth for this list and for --help)
|
|
77
77
|
- **Options**: Three exclusive sources (CLI → ENV → Default)
|
|
78
78
|
- **Output formats**: Three formats (XML, JSON, text), never mixed
|
|
79
79
|
- **Error levels**: Three levels (warning, error, fatal), no overlap
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
#include "cli.h"
|
|
7
7
|
#include "error.h"
|
|
8
|
+
#include <stdio.h>
|
|
8
9
|
#include <stdlib.h>
|
|
9
10
|
#include <string.h>
|
|
10
11
|
|
|
@@ -89,7 +90,6 @@ cli_command_t* cli_registry_find(
|
|
|
89
90
|
void cli_registry_print_all(const cli_registry_t* registry) {
|
|
90
91
|
if (!registry) return;
|
|
91
92
|
|
|
92
|
-
printf("Available commands:\n");
|
|
93
93
|
for (size_t i = 0; i < registry->count; i++) {
|
|
94
94
|
printf(" %-12s %s\n",
|
|
95
95
|
registry->commands[i]->name,
|
|
@@ -97,6 +97,40 @@ void cli_registry_print_all(const cli_registry_t* registry) {
|
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
/* ------------------------------------------------------------------------- */
|
|
101
|
+
/* Shared Command Utilities */
|
|
102
|
+
/* ------------------------------------------------------------------------- */
|
|
103
|
+
|
|
104
|
+
char* cli_read_stream(FILE* fp, size_t* out_len) {
|
|
105
|
+
size_t cap = 4096, len = 0;
|
|
106
|
+
char* buf = (char*)malloc(cap);
|
|
107
|
+
if (!buf) return NULL;
|
|
108
|
+
for (;;) {
|
|
109
|
+
size_t n = fread(buf + len, 1, cap - len - 1, fp);
|
|
110
|
+
len += n;
|
|
111
|
+
if (len + 1 >= cap) {
|
|
112
|
+
cap *= 2;
|
|
113
|
+
char* grown = (char*)realloc(buf, cap);
|
|
114
|
+
if (!grown) { free(buf); return NULL; }
|
|
115
|
+
buf = grown;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
buf[len] = 0;
|
|
121
|
+
if (out_len) *out_len = len;
|
|
122
|
+
return buf;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
char* cli_read_file(const char* path, size_t* out_len) {
|
|
126
|
+
if (strcmp(path, "-") == 0) return cli_read_stream(stdin, out_len);
|
|
127
|
+
FILE* fp = fopen(path, "rb");
|
|
128
|
+
if (!fp) return NULL;
|
|
129
|
+
char* s = cli_read_stream(fp, out_len);
|
|
130
|
+
fclose(fp);
|
|
131
|
+
return s;
|
|
132
|
+
}
|
|
133
|
+
|
|
100
134
|
/* ------------------------------------------------------------------------- */
|
|
101
135
|
/* Helper Functions */
|
|
102
136
|
/* ------------------------------------------------------------------------- */
|
|
@@ -110,6 +144,7 @@ const char* cli_result_to_string(cli_result_t result) {
|
|
|
110
144
|
case CLI_ERROR_ARGS: return "invalid arguments";
|
|
111
145
|
case CLI_ERROR_MEMORY: return "memory allocation failed";
|
|
112
146
|
case CLI_ERROR_INTERNAL: return "internal error";
|
|
147
|
+
case CLI_ERROR_XSLT: return "xslt error";
|
|
113
148
|
default: return "unknown error";
|
|
114
149
|
}
|
|
115
150
|
}
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
#define LEPTRIS_CLI_H
|
|
18
18
|
|
|
19
19
|
#include <stddef.h>
|
|
20
|
+
#include <stdio.h>
|
|
20
21
|
|
|
21
22
|
#ifdef __cplusplus
|
|
22
23
|
extern "C" {
|
|
@@ -43,7 +44,8 @@ typedef enum {
|
|
|
43
44
|
CLI_ERROR_IO = 3, /**< I/O error (file not found, etc.) */
|
|
44
45
|
CLI_ERROR_ARGS = 4, /**< Invalid arguments */
|
|
45
46
|
CLI_ERROR_MEMORY = 5, /**< Memory allocation failed */
|
|
46
|
-
CLI_ERROR_INTERNAL = 6
|
|
47
|
+
CLI_ERROR_INTERNAL = 6, /**< Internal error (bug) */
|
|
48
|
+
CLI_ERROR_XSLT = 7 /**< XSLT transformation failed */
|
|
47
49
|
} cli_result_t;
|
|
48
50
|
|
|
49
51
|
/* ------------------------------------------------------------------------- */
|
|
@@ -166,12 +168,39 @@ cli_command_t* cli_registry_find(
|
|
|
166
168
|
/**
|
|
167
169
|
* Print all registered commands
|
|
168
170
|
*
|
|
169
|
-
*
|
|
171
|
+
* Prints one aligned "name — description" line per registered
|
|
172
|
+
* command, in registration order, without a section header — the
|
|
173
|
+
* caller frames the listing. This is the single source of truth
|
|
174
|
+
* for the global --help command list: command descriptors carry
|
|
175
|
+
* their own description, and no hand-maintained copy of the list
|
|
176
|
+
* exists anywhere else.
|
|
170
177
|
*
|
|
171
178
|
* @param registry Registry to print
|
|
172
179
|
*/
|
|
173
180
|
void cli_registry_print_all(const cli_registry_t* registry);
|
|
174
181
|
|
|
182
|
+
/* ------------------------------------------------------------------------- */
|
|
183
|
+
/* Shared Command Utilities */
|
|
184
|
+
/* ------------------------------------------------------------------------- */
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Read a whole stream into a NUL-terminated heap buffer
|
|
188
|
+
*
|
|
189
|
+
* @param fp Stream to read (not closed)
|
|
190
|
+
* @param out_len Length in bytes excluding the NUL, or NULL
|
|
191
|
+
* @return Buffer (caller frees), or NULL on allocation failure
|
|
192
|
+
*/
|
|
193
|
+
char* cli_read_stream(FILE* fp, size_t* out_len);
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Read a whole file into a NUL-terminated heap buffer
|
|
197
|
+
*
|
|
198
|
+
* @param path File path, or "-" for stdin
|
|
199
|
+
* @param out_len Length in bytes excluding the NUL, or NULL
|
|
200
|
+
* @return Buffer (caller frees), NULL on open or allocation failure
|
|
201
|
+
*/
|
|
202
|
+
char* cli_read_file(const char* path, size_t* out_len);
|
|
203
|
+
|
|
175
204
|
/* ------------------------------------------------------------------------- */
|
|
176
205
|
/* Standard Commands (Forward Declarations) */
|
|
177
206
|
/* ------------------------------------------------------------------------- */
|
|
@@ -225,6 +254,14 @@ extern cli_command_t* cli_command_validate(void);
|
|
|
225
254
|
*/
|
|
226
255
|
extern cli_command_t* cli_command_xquery(void);
|
|
227
256
|
|
|
257
|
+
/**
|
|
258
|
+
* Get the 'xslt' command
|
|
259
|
+
*
|
|
260
|
+
* Command: leptris xslt -s STYLESHEET [INPUT]
|
|
261
|
+
* Purpose: Apply an XSLT stylesheet to an XML document
|
|
262
|
+
*/
|
|
263
|
+
extern cli_command_t* cli_command_xslt(void);
|
|
264
|
+
|
|
228
265
|
#ifdef __cplusplus
|
|
229
266
|
}
|
|
230
267
|
#endif
|