leptris 1.9.331.0-ppc64le-linux → 1.9.334.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 +31 -0
- data/Rakefile +19 -1
- data/lib/leptris/version.rb +1 -1
- data/lib/leptris/xml/cdata.rb +4 -0
- data/lib/leptris/xml/comment.rb +4 -0
- data/lib/leptris/xml/descriptor.rb +55 -0
- data/lib/leptris/xml/entity_reference.rb +4 -0
- data/lib/leptris/xml/ffi.rb +25 -0
- data/lib/leptris/xml/node.rb +1 -0
- data/lib/leptris/xml/processing_instruction.rb +4 -0
- data/lib/leptris/xml/text.rb +4 -0
- data/lib/libleptris.so +0 -0
- data/vendor-src/README.md +1 -1
- data/vendor-src/libleptris/CHANGELOG.md +65 -0
- data/vendor-src/libleptris/CMakeLists.txt +1 -1
- data/vendor-src/libleptris/src/include/leptris/descriptor.h +30 -0
- data/vendor-src/libleptris/src/include/leptris.h +5 -0
- data/vendor-src/libleptris/src/leptris/descriptor/plan.c +144 -0
- data/vendor-src/libleptris/src/leptris/dom/element_modify.c +7 -0
- data/vendor-src/libleptris/src/leptris/xsd/compile.c +241 -4
- data/vendor-src/libleptris/src/leptris/xsd/content_model.c +50 -0
- data/vendor-src/libleptris/src/leptris/xsd/validate.c +190 -8
- data/vendor-src/libleptris/src/leptris/xsd/xsd_internal.h +34 -0
- data/vendor-src/libleptris/test/abi/test_descriptor.cpp +95 -0
- data/vendor-src/libleptris/test/xsd/test_xsd_compile.cpp +380 -0
- data/vendor-src/libleptris/vcpkg.json +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4c687c6b5c09c8f7ec7bd48a26c197318f6f2a396680075a39f2cbfe445eb9c8
|
|
4
|
+
data.tar.gz: 458aac071ab017d4bc2192bb9e1ac2c2c003edf631a058a16eb5446d1051e4f1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f3cacf66947185632eda797cc645d036978912e5acb10726a83c615db019ced9ffe6146411321ee47ffdb521f64d25f7f9789af7dd1938c2d7809bbf260a522d
|
|
7
|
+
data.tar.gz: 4efeebf09318e7c65ef475fc3fc05c44fa7597226fd8f087f26acac28d50b3a79c76fc574ff2937aa2436d2c16ac30aa5f9769813358e005f3a757701afd9c46
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,34 @@
|
|
|
1
|
+
## [1.9.334.0] - 2026-10-10
|
|
2
|
+
|
|
3
|
+
### Added — engine sync (libleptris 1.9.332-1.9.334)
|
|
4
|
+
|
|
5
|
+
- **Descriptor#build_result — serialize-side construction
|
|
6
|
+
(#408's face)**: `leptris_plan_result_build` builds a result
|
|
7
|
+
tree from row ops (:element structural opens, :scalar nesting
|
|
8
|
+
inside its producing row's element implicitly, :attr by name,
|
|
9
|
+
:end closes) that `#serialize` renders — the reverse of #walk,
|
|
10
|
+
byte-identical round-trip pinned. `leptris_element_add_child_addr`
|
|
11
|
+
attached (the #408 address-based attach; sugar is #408's design
|
|
12
|
+
work). Audit 384/383.
|
|
13
|
+
- **XSD 1.1 tier 2 (1.9.332)**: `xs:assert` on complexTypes
|
|
14
|
+
(XPath 2 lane, per-instance), `xs:assertion` on simpleTypes,
|
|
15
|
+
`xs:openContent` — `xs:assert` pinned.
|
|
16
|
+
- **Completion wave (1.9.334)**: `xs:all` order-free with foreign
|
|
17
|
+
children rejected; strict validation of undeclared elements
|
|
18
|
+
and attributes — both pinned.
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- **#1615 resolved as a malformed repro**: the well-formed mixed
|
|
23
|
+
union (memberTypes + inline member) validates correctly on
|
|
24
|
+
both paths — my filed schema was missing a `</xs:restriction>`
|
|
25
|
+
close. On 1.9.334 the malformed schema compiles to an
|
|
26
|
+
error-carrying handle ("schema document is not well-formed
|
|
27
|
+
XML") and fails validation CLOSED (it over-accepted silently
|
|
28
|
+
on 1.9.331 — the real defect, fixed engine-side by their
|
|
29
|
+
regression pin). Both behaviors spec-pinned; leptris#1615
|
|
30
|
+
closed with the correction.
|
|
31
|
+
|
|
1
32
|
## [1.9.331.0] - 2026-10-10
|
|
2
33
|
|
|
3
34
|
### Added — engine sync (libleptris 1.9.325-1.9.331)
|
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.334"
|
|
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
|
|
@@ -31,6 +31,22 @@ CMAKE_FLAGS = %w[
|
|
|
31
31
|
require "tmpdir"
|
|
32
32
|
|
|
33
33
|
desc "Build libleptris #{LIBLEPTRIS_VERSION} (+ utf8proc) from release tarballs into lib/"
|
|
34
|
+
# leptris#1623: macOS 14's dyld intermittently SIGKILLs
|
|
35
|
+
# linker-signed adhoc images at load ("CODESIGNING Invalid Page" —
|
|
36
|
+
# the same kill the atomic-replace dance below already guards in
|
|
37
|
+
# dev). The linker's implicit signature is the bare minimum; an
|
|
38
|
+
# explicit codesign at package time writes a complete, deterministic
|
|
39
|
+
# CodeDirectory that survives the gem pipeline (cp, packaging,
|
|
40
|
+
# install). Re-sign every shipped darwin binary and verify it.
|
|
41
|
+
def sign_darwin_binaries(*bins)
|
|
42
|
+
return unless RUBY_PLATFORM =~ /darwin/
|
|
43
|
+
|
|
44
|
+
bins.flatten.compact.each do |bin|
|
|
45
|
+
sh "codesign --force --sign - #{bin}"
|
|
46
|
+
sh "codesign --verify #{bin}"
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
34
50
|
task :compile do
|
|
35
51
|
# GitHub tarball downloads intermittently return a non-gzip body
|
|
36
52
|
# (rate-limit/redirect HTML) — the piped curl|tar form then fails
|
|
@@ -256,6 +272,7 @@ task :compile do
|
|
|
256
272
|
Dir.glob("#{u8_prefix}/{lib,bin}/utf8proc.dll").first
|
|
257
273
|
raise "utf8proc shared library not found after build" unless u8_lib
|
|
258
274
|
cp(u8_lib, "lib/#{File.basename(u8_lib)}")
|
|
275
|
+
sign_darwin_binaries("lib/libleptris#{ext}", "lib/#{File.basename(u8_lib)}")
|
|
259
276
|
puts "Vendored #{File.basename(lib)} + #{File.basename(u8_lib)} into lib/"
|
|
260
277
|
|
|
261
278
|
# Opt-in native read layer ext (#185): built and vendored beside
|
|
@@ -319,6 +336,7 @@ task :compile do
|
|
|
319
336
|
dest = "lib/leptris/xml/#{File.basename(bundle)}"
|
|
320
337
|
cp(bundle, "#{dest}.new")
|
|
321
338
|
mv("#{dest}.new", dest)
|
|
339
|
+
sign_darwin_binaries(dest)
|
|
322
340
|
puts "Vendored native layer (#{File.basename(bundle)}) into lib/leptris/xml/"
|
|
323
341
|
end
|
|
324
342
|
end
|
data/lib/leptris/version.rb
CHANGED
data/lib/leptris/xml/cdata.rb
CHANGED
data/lib/leptris/xml/comment.rb
CHANGED
|
@@ -347,6 +347,61 @@ class Leptris::XML::Descriptor
|
|
|
347
347
|
owner: true, plans: @plans, plan: @plans[0])
|
|
348
348
|
end
|
|
349
349
|
|
|
350
|
+
# Serialize-side construction (leptris_plan_result_build): a
|
|
351
|
+
# result tree from +ops+ — hashes of {kind: :element / :scalar /
|
|
352
|
+
# :attr / :end, plan_index:, row_index:, name:, value:} — that
|
|
353
|
+
# #serialize renders through this plan. Encoding: an :element op
|
|
354
|
+
# opens a structural element (row_index UINT32_MAX = the root);
|
|
355
|
+
# a :scalar op carries its PRODUCING row and nests inside that
|
|
356
|
+
# row's element implicitly; :attr attaches by name; :end closes.
|
|
357
|
+
# Returns a root-owned PlanValue.
|
|
358
|
+
ROW_OP_KINDS = {
|
|
359
|
+
scalar: Leptris::XML::FFI::PLAN_OP_SCALAR,
|
|
360
|
+
element: Leptris::XML::FFI::PLAN_OP_ELEMENT,
|
|
361
|
+
attr: Leptris::XML::FFI::PLAN_OP_ATTR,
|
|
362
|
+
end: Leptris::XML::FFI::PLAN_OP_END,
|
|
363
|
+
}.freeze
|
|
364
|
+
private_constant :ROW_OP_KINDS
|
|
365
|
+
|
|
366
|
+
def build_result(ops)
|
|
367
|
+
memory = ::FFI::MemoryPointer.new(Leptris::XML::FFI::PlanRowOp, ops.size)
|
|
368
|
+
anchors = [memory]
|
|
369
|
+
ops.each_with_index do |op, i|
|
|
370
|
+
row = Leptris::XML::FFI::PlanRowOp.new(memory[i])
|
|
371
|
+
kind = ROW_OP_KINDS.fetch(op.fetch(:kind)) do
|
|
372
|
+
raise ArgumentError,
|
|
373
|
+
"op kind must be one of #{ROW_OP_KINDS.keys.inspect}"
|
|
374
|
+
end
|
|
375
|
+
value = op[:value]
|
|
376
|
+
row[:kind] = kind
|
|
377
|
+
row[:plan_index] = op.fetch(:plan_index, 0)
|
|
378
|
+
row[:row_index] = op.fetch(:row_index, 0xFFFF_FFFF)
|
|
379
|
+
row[:name] =
|
|
380
|
+
if (n = op[:name])
|
|
381
|
+
anchors << (ptr = ::FFI::MemoryPointer.from_string(n.to_s))
|
|
382
|
+
ptr
|
|
383
|
+
end
|
|
384
|
+
if value.nil?
|
|
385
|
+
row[:value] = nil
|
|
386
|
+
row[:value_len] = 0
|
|
387
|
+
else
|
|
388
|
+
s = value.to_s
|
|
389
|
+
anchors << (ptr = ::FFI::MemoryPointer.from_string(s))
|
|
390
|
+
row[:value] = ptr
|
|
391
|
+
row[:value_len] = s.bytesize
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
status = ::FFI::MemoryPointer.new(:int)
|
|
395
|
+
raw = Leptris::XML::FFI.leptris_plan_result_build(
|
|
396
|
+
@handle, memory, ops.size, status)
|
|
397
|
+
if raw.null?
|
|
398
|
+
raise Leptris::XML::Error,
|
|
399
|
+
"plan result build failed (status=#{status.read_int})"
|
|
400
|
+
end
|
|
401
|
+
Leptris::XML::PlanValue.new(ResultHandle.new(raw),
|
|
402
|
+
owner: true, plans: @plans, plan: @plans[0])
|
|
403
|
+
end
|
|
404
|
+
|
|
350
405
|
# libleptris 1.9.312 (#1551): serialize a walk result back to
|
|
351
406
|
# XML guided by this plan — the plan supplies element wrappers
|
|
352
407
|
# (row wire_name + ns_prefix), the result the content; children
|
data/lib/leptris/xml/ffi.rb
CHANGED
|
@@ -418,6 +418,26 @@ module Leptris
|
|
|
418
418
|
:leptris_plan_result
|
|
419
419
|
attach_function :leptris_plan_result_free,
|
|
420
420
|
[:leptris_plan_result], :void
|
|
421
|
+
# libleptris 1.9.324+: construct a result tree from row ops
|
|
422
|
+
# (the serialize-side fast path — the reverse of the walk):
|
|
423
|
+
# ELEMENT opens under the current parent, SCALAR/ATTR carry
|
|
424
|
+
# values, END closes. Strings are copied at build; free with
|
|
425
|
+
# leptris_plan_result_free (the ResultHandle does).
|
|
426
|
+
class PlanRowOp < ::FFI::Struct
|
|
427
|
+
layout :kind, :int,
|
|
428
|
+
:plan_index, :uint32,
|
|
429
|
+
:row_index, :uint32,
|
|
430
|
+
:name, :pointer,
|
|
431
|
+
:value, :pointer,
|
|
432
|
+
:value_len, :size_t
|
|
433
|
+
end
|
|
434
|
+
PLAN_OP_SCALAR = 0
|
|
435
|
+
PLAN_OP_ELEMENT = 1
|
|
436
|
+
PLAN_OP_ATTR = 2
|
|
437
|
+
PLAN_OP_END = 3
|
|
438
|
+
attach_function :leptris_plan_result_build,
|
|
439
|
+
[:leptris_plan, :pointer, :size_t, :pointer], :leptris_plan_result
|
|
440
|
+
|
|
421
441
|
# libleptris 1.9.312 (#1551): serialize a walk result back
|
|
422
442
|
# to XML guided by its plan — the plan supplies element
|
|
423
443
|
# wrappers (row wire_name + ns_prefix), the result the
|
|
@@ -858,6 +878,11 @@ attach_function :leptris_parse_string,
|
|
|
858
878
|
[:leptris_element, :string], :leptris_status
|
|
859
879
|
attach_function :leptris_element_append_child,
|
|
860
880
|
[:leptris_element, :leptris_element], :leptris_status
|
|
881
|
+
# #408: address-based attach — bindings pass raw addresses
|
|
882
|
+
# and skip the per-node FFI pointer-wrapper mint. Same
|
|
883
|
+
# semantics and status contract as the pointer face.
|
|
884
|
+
attach_function :leptris_element_add_child_addr,
|
|
885
|
+
[:ulong_long, :ulong_long], :leptris_status
|
|
861
886
|
# Fused create+append (libleptris 1.9.153): one document
|
|
862
887
|
# resolution, identical tree semantics to the two-call pair.
|
|
863
888
|
attach_function :leptris_element_create_child,
|
data/lib/leptris/xml/node.rb
CHANGED
|
@@ -50,6 +50,10 @@ class Leptris::XML::ProcessingInstruction < Leptris::XML::Node
|
|
|
50
50
|
new_data
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
+
def to_s
|
|
54
|
+
content.to_s.empty? ? "<?#{name}?>" : "<?#{name} #{content}?>"
|
|
55
|
+
end
|
|
56
|
+
|
|
53
57
|
# Document-level PIs have no tree parent for leptris_node_unlink
|
|
54
58
|
# — route through the document-level removal (libleptris 1.9.9,
|
|
55
59
|
# #612), identity-matched by index so the right same-target PI
|
data/lib/leptris/xml/text.rb
CHANGED
data/lib/libleptris.so
CHANGED
|
Binary file
|
data/vendor-src/README.md
CHANGED
|
@@ -1,5 +1,70 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [1.9.334] - 2026-10-10
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **XSD completion wave (#1075, PR #1620).** `xs:all` at the model
|
|
8
|
+
root is order-free now (counting check: each member at most
|
|
9
|
+
maxOccurs, minOccurs floors, foreign children rejected) — it
|
|
10
|
+
previously enforced declaration order. Strict validation:
|
|
11
|
+
undeclared elements (including the document root) and undeclared
|
|
12
|
+
attributes fail with `not declared (strict)`, unless the type
|
|
13
|
+
captures `xs:anyAttribute`, whose namespace grammar
|
|
14
|
+
(`##any`/`##other`/`##targetNamespace`/`##local`/URI list) is
|
|
15
|
+
enforced. Unresolved named types are loud — `type not found in
|
|
16
|
+
the schema` — closing the silent-accept class behind #1615.
|
|
17
|
+
`$value` binds typed: the simple type's numeric chain decides
|
|
18
|
+
number-vs-string, not the lexical's shape. Eight red-first
|
|
19
|
+
specs; zero fallout in existing pins.
|
|
20
|
+
- **Native plan-result builder + address-based attach (leptris-
|
|
21
|
+
ruby#408 asks, PR #1621).** `leptris_plan_result_build` builds
|
|
22
|
+
the standalone result tree from a flat op program —
|
|
23
|
+
ELEMENT/SCALAR/ATTR/END, stamped exactly as a walk stamps it —
|
|
24
|
+
so `leptris_plan_serialize` serves standalone serialization with
|
|
25
|
+
zero DOM mint on the host (the to_xml → to_json-floor path).
|
|
26
|
+
`leptris_element_add_child_addr` attaches by raw addresses,
|
|
27
|
+
dropping the per-node FFI pointer-wrapper mint (~2 allocs/row).
|
|
28
|
+
The Ruby-side wiring rides the binding repo.
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
## [1.9.333] - 2026-10-10
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
|
|
36
|
+
- **Regression pin: union `memberTypes` + inline anonymous members
|
|
37
|
+
(#1615, PR #1618).** The reported over-acceptance was not
|
|
38
|
+
reproducible on any engine artifact (main, the v1.9.331 tag,
|
|
39
|
+
every published gem binary — including through the full Ruby
|
|
40
|
+
binding path). The exact schema now asserts in CI through both
|
|
41
|
+
`leptris_xsd_simple_valid` and instance validation, so the
|
|
42
|
+
mixed-member semantics are verifiable binary-independent of any
|
|
43
|
+
binding environment.
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
## [1.9.332] - 2026-10-09
|
|
47
|
+
|
|
48
|
+
### Added
|
|
49
|
+
|
|
50
|
+
- **XSD 1.1 — tier 2 (#1075, PR #1616).** Gated on
|
|
51
|
+
`xs:schema @version="1.1"`: `xs:assert` on complexTypes (direct
|
|
52
|
+
and derivation-nested; compiled once, evaluated per instance
|
|
53
|
+
through the engine's XPath 2 lane; evaluation errors are
|
|
54
|
+
failures); `xs:assertion` on simpleTypes (`$value` binds the
|
|
55
|
+
lexical, element context); `xs:openContent` interleave/suffix
|
|
56
|
+
(wildcard self-loops at the Thompson NFA's junction states;
|
|
57
|
+
`xs:defaultOpenContent` schema-wide with `appliesToEmpty`) and
|
|
58
|
+
`xs:alternative` conditional type assignment (first passing
|
|
59
|
+
test types the instance, declared type as fallback). Ten
|
|
60
|
+
red-first specs; ctest 1951/1951; 1.0 schemas unaffected.
|
|
61
|
+
|
|
62
|
+
### Fixed
|
|
63
|
+
|
|
64
|
+
- free the defaultOpenContent wildcard with the schema (xsd)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
3
68
|
## [1.9.331] - 2026-10-09
|
|
4
69
|
|
|
5
70
|
### Fixed
|
|
@@ -259,6 +259,36 @@ LEPTRIS_API LeptrisPlanResult leptris_plan_walk(LeptrisDocument doc,
|
|
|
259
259
|
LeptrisStatus* status);
|
|
260
260
|
LEPTRIS_API void leptris_plan_result_free(LeptrisPlanResult result);
|
|
261
261
|
|
|
262
|
+
/* #408 ask 2: build a standalone result natively from a flat op
|
|
263
|
+
* program — the same tree a walk produces (wrappers, ns bindings,
|
|
264
|
+
* kid order), so leptris_plan_serialize serves standalone
|
|
265
|
+
* serialization with no DOM mint on the host side. ELEMENT ops
|
|
266
|
+
* reference the plan row that captured the member (plan_index +
|
|
267
|
+
* row_index; the walk root uses row_index = UINT32_MAX); SCALAR
|
|
268
|
+
* and ATTR carry the value; END pops the open element. Programs
|
|
269
|
+
* must balance (every ELEMENT closed; no END without an open
|
|
270
|
+
* element) and open with the root element op. Strings are copied.
|
|
271
|
+
* Memory: free with leptris_plan_result_free. */
|
|
272
|
+
typedef enum {
|
|
273
|
+
LEPTRIS_PLAN_OP_SCALAR = 0,
|
|
274
|
+
LEPTRIS_PLAN_OP_ELEMENT = 1,
|
|
275
|
+
LEPTRIS_PLAN_OP_ATTR = 2,
|
|
276
|
+
LEPTRIS_PLAN_OP_END = 3
|
|
277
|
+
} LeptrisPlanRowOpKind;
|
|
278
|
+
|
|
279
|
+
typedef struct {
|
|
280
|
+
LeptrisPlanRowOpKind kind;
|
|
281
|
+
uint32_t plan_index; /* ELEMENT: the plan whose row captured it */
|
|
282
|
+
uint32_t row_index; /* producing row (UINT32_MAX = root) */
|
|
283
|
+
const char* name; /* ATTR: attribute name */
|
|
284
|
+
const char* value; /* SCALAR/ATTR: value (NULL = empty) */
|
|
285
|
+
size_t value_len;
|
|
286
|
+
} leptris_plan_row_op;
|
|
287
|
+
|
|
288
|
+
LEPTRIS_API LeptrisPlanResult leptris_plan_result_build(
|
|
289
|
+
LeptrisPlan plan, const leptris_plan_row_op* ops, size_t count,
|
|
290
|
+
LeptrisStatus* status);
|
|
291
|
+
|
|
262
292
|
/* #1551: serialize a walk result back to XML, guided by its plan.
|
|
263
293
|
* The plan supplies element wrappers (row wire_name + ns_prefix)
|
|
264
294
|
* and the result supplies content; children emit in document order
|
|
@@ -2153,6 +2153,11 @@ LEPTRIS_API LeptrisStatus leptris_element_set_name(LeptrisElement elem, const ch
|
|
|
2153
2153
|
* @param child Child element to append
|
|
2154
2154
|
* @return LEPTRIS_OK on success, error code otherwise
|
|
2155
2155
|
*/
|
|
2156
|
+
/* #408: address-based attach — bindings pass raw addresses and
|
|
2157
|
+
* skip the per-node FFI pointer-wrapper mint. Same semantics and
|
|
2158
|
+
* status contract as leptris_element_append_child. */
|
|
2159
|
+
LEPTRIS_API LeptrisStatus leptris_element_add_child_addr(uintptr_t parent_addr,
|
|
2160
|
+
uintptr_t child_addr);
|
|
2156
2161
|
LEPTRIS_API LeptrisStatus leptris_element_append_child(LeptrisElement parent, LeptrisElement child);
|
|
2157
2162
|
|
|
2158
2163
|
/**
|
|
@@ -1530,6 +1530,150 @@ LEPTRIS_API char* leptris_plan_serialize(LeptrisPlan plan,
|
|
|
1530
1530
|
return b.s;
|
|
1531
1531
|
}
|
|
1532
1532
|
|
|
1533
|
+
LEPTRIS_API LeptrisPlanResult leptris_plan_result_build(
|
|
1534
|
+
LeptrisPlan plan, const leptris_plan_row_op* ops, size_t count,
|
|
1535
|
+
LeptrisStatus* status) {
|
|
1536
|
+
if (status) *status = LEPTRIS_OK;
|
|
1537
|
+
if (!plan || !ops || count == 0) {
|
|
1538
|
+
if (status) *status = LEPTRIS_ERROR_INVALID_ARG;
|
|
1539
|
+
return NULL;
|
|
1540
|
+
}
|
|
1541
|
+
const struct leptris_plan* pool =
|
|
1542
|
+
(const struct leptris_plan*)plan;
|
|
1543
|
+
/* op stack of open elements; depth is program-bounded */
|
|
1544
|
+
struct leptris_plan_result** stack =
|
|
1545
|
+
(struct leptris_plan_result**)calloc(count,
|
|
1546
|
+
sizeof(*stack));
|
|
1547
|
+
if (!stack) {
|
|
1548
|
+
if (status) *status = LEPTRIS_ERROR_MEMORY;
|
|
1549
|
+
return NULL;
|
|
1550
|
+
}
|
|
1551
|
+
int sp = 0;
|
|
1552
|
+
struct leptris_plan_result* root = NULL;
|
|
1553
|
+
for (size_t i = 0; i < count; i++) {
|
|
1554
|
+
const leptris_plan_row_op* op = &ops[i];
|
|
1555
|
+
if (op->kind == LEPTRIS_PLAN_OP_ELEMENT) {
|
|
1556
|
+
if (op->plan_index >= pool->plan_count ||
|
|
1557
|
+
(op->row_index != UINT32_MAX &&
|
|
1558
|
+
op->row_index >= pool->plans[op->plan_index]
|
|
1559
|
+
.child_count)) {
|
|
1560
|
+
free(stack);
|
|
1561
|
+
if (status) *status = LEPTRIS_ERROR_INVALID_ARG;
|
|
1562
|
+
return NULL;
|
|
1563
|
+
}
|
|
1564
|
+
struct leptris_plan_result* v = dp_value_new(
|
|
1565
|
+
LEPTRIS_PLAN_VALUE_ELEMENT);
|
|
1566
|
+
if (!v) goto oom;
|
|
1567
|
+
const dp_plan* cp = &pool->plans[op->plan_index];
|
|
1568
|
+
const char* wire =
|
|
1569
|
+
op->row_index == UINT32_MAX
|
|
1570
|
+
? cp->element_name
|
|
1571
|
+
: cp->child_plans[op->row_index].wire_name;
|
|
1572
|
+
v->name = dp_strdup(wire);
|
|
1573
|
+
v->container_plan = op->plan_index;
|
|
1574
|
+
v->row_index = op->row_index;
|
|
1575
|
+
if (op->row_index != UINT32_MAX) {
|
|
1576
|
+
const leptris_child_plan* cr =
|
|
1577
|
+
&cp->child_plans[op->row_index];
|
|
1578
|
+
v->ns_prefix = dp_strdup(cr->ns_prefix);
|
|
1579
|
+
v->ns_uri = dp_strdup(cr->ns_uri);
|
|
1580
|
+
}
|
|
1581
|
+
if (sp == 0) {
|
|
1582
|
+
if (root) { /* multiple roots */
|
|
1583
|
+
dp_result_free_rec(v);
|
|
1584
|
+
free(stack);
|
|
1585
|
+
if (status) *status = LEPTRIS_ERROR_INVALID_ARG;
|
|
1586
|
+
return NULL;
|
|
1587
|
+
}
|
|
1588
|
+
root = v;
|
|
1589
|
+
} else if (!dp_value_push(stack[sp - 1], v)) {
|
|
1590
|
+
dp_result_free_rec(v);
|
|
1591
|
+
goto oom;
|
|
1592
|
+
}
|
|
1593
|
+
v->order_index = (uint32_t)
|
|
1594
|
+
(sp == 0 ? 0 : stack[sp - 1]->kid_count);
|
|
1595
|
+
stack[sp++] = v;
|
|
1596
|
+
} else if (op->kind == LEPTRIS_PLAN_OP_SCALAR) {
|
|
1597
|
+
if (sp == 0) {
|
|
1598
|
+
free(stack);
|
|
1599
|
+
if (status) *status = LEPTRIS_ERROR_INVALID_ARG;
|
|
1600
|
+
return NULL;
|
|
1601
|
+
}
|
|
1602
|
+
struct leptris_plan_result* v =
|
|
1603
|
+
dp_value_new(LEPTRIS_PLAN_VALUE_SCALAR);
|
|
1604
|
+
if (!v) goto oom;
|
|
1605
|
+
const dp_plan* cp = &pool->plans[op->plan_index];
|
|
1606
|
+
if (op->row_index < cp->child_count)
|
|
1607
|
+
v->name = dp_strdup(
|
|
1608
|
+
cp->child_plans[op->row_index].wire_name);
|
|
1609
|
+
if (!dp_value_set_str(v, op->value ? op->value : "",
|
|
1610
|
+
op->value ? op->value_len : 0))
|
|
1611
|
+
dp_value_set_str(v, "", 0);
|
|
1612
|
+
if (!dp_value_push(stack[sp - 1], v)) {
|
|
1613
|
+
dp_result_free_rec(v);
|
|
1614
|
+
goto oom;
|
|
1615
|
+
}
|
|
1616
|
+
} else if (op->kind == LEPTRIS_PLAN_OP_ATTR) {
|
|
1617
|
+
if (sp == 0 || !op->name) {
|
|
1618
|
+
free(stack);
|
|
1619
|
+
if (status) *status = LEPTRIS_ERROR_INVALID_ARG;
|
|
1620
|
+
return NULL;
|
|
1621
|
+
}
|
|
1622
|
+
struct leptris_plan_result* el = stack[sp - 1];
|
|
1623
|
+
char** gn = (char**)realloc(
|
|
1624
|
+
el->attr_names,
|
|
1625
|
+
(el->attr_count + 1) * sizeof(char*));
|
|
1626
|
+
char** gv = (char**)realloc(
|
|
1627
|
+
el->attr_values,
|
|
1628
|
+
(el->attr_count + 1) * sizeof(char*));
|
|
1629
|
+
char** gp = (char**)realloc(
|
|
1630
|
+
el->attr_ns_prefixes,
|
|
1631
|
+
(el->attr_count + 1) * sizeof(char*));
|
|
1632
|
+
char** gu = (char**)realloc(
|
|
1633
|
+
el->attr_ns_uris,
|
|
1634
|
+
(el->attr_count + 1) * sizeof(char*));
|
|
1635
|
+
if (!gn || !gv || !gp || !gu) {
|
|
1636
|
+
free(gn); free(gv); free(gp); free(gu);
|
|
1637
|
+
goto oom;
|
|
1638
|
+
}
|
|
1639
|
+
el->attr_names = gn;
|
|
1640
|
+
el->attr_values = gv;
|
|
1641
|
+
el->attr_ns_prefixes = gp;
|
|
1642
|
+
el->attr_ns_uris = gu;
|
|
1643
|
+
gn[el->attr_count] = dp_strdup(op->name);
|
|
1644
|
+
gv[el->attr_count] =
|
|
1645
|
+
dp_strdup_n(op->value ? op->value : "",
|
|
1646
|
+
op->value ? op->value_len : 0);
|
|
1647
|
+
gp[el->attr_count] = NULL;
|
|
1648
|
+
gu[el->attr_count] = NULL;
|
|
1649
|
+
if (!gn[el->attr_count] || !gv[el->attr_count])
|
|
1650
|
+
goto oom;
|
|
1651
|
+
el->attr_count++;
|
|
1652
|
+
} else if (op->kind == LEPTRIS_PLAN_OP_END) {
|
|
1653
|
+
if (sp == 0) {
|
|
1654
|
+
free(stack);
|
|
1655
|
+
if (status) *status = LEPTRIS_ERROR_INVALID_ARG;
|
|
1656
|
+
return NULL;
|
|
1657
|
+
}
|
|
1658
|
+
sp--;
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
int balanced = (sp == 0 && root != NULL);
|
|
1662
|
+
free(stack);
|
|
1663
|
+
if (!balanced) {
|
|
1664
|
+
dp_result_free_rec(root);
|
|
1665
|
+
if (status) *status = LEPTRIS_ERROR_INVALID_ARG;
|
|
1666
|
+
return NULL;
|
|
1667
|
+
}
|
|
1668
|
+
return (LeptrisPlanResult)root;
|
|
1669
|
+
|
|
1670
|
+
oom:
|
|
1671
|
+
if (root) dp_result_free_rec(root);
|
|
1672
|
+
free(stack);
|
|
1673
|
+
if (status) *status = LEPTRIS_ERROR_MEMORY;
|
|
1674
|
+
return NULL;
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1533
1677
|
LEPTRIS_API void leptris_plan_result_free(LeptrisPlanResult result) {
|
|
1534
1678
|
dp_result_free_rec((struct leptris_plan_result*)result);
|
|
1535
1679
|
}
|
|
@@ -493,6 +493,13 @@ static LeptrisNode* adopt_for_splice(LeptrisNode* node,
|
|
|
493
493
|
return copy ? (LeptrisNode*)copy : NULL;
|
|
494
494
|
}
|
|
495
495
|
|
|
496
|
+
LeptrisStatus leptris_element_add_child_addr(uintptr_t parent_addr,
|
|
497
|
+
uintptr_t child_addr) {
|
|
498
|
+
if (!parent_addr || !child_addr) return LEPTRIS_ERROR_NULL_ARG;
|
|
499
|
+
return leptris_element_append_child((LeptrisElement)parent_addr,
|
|
500
|
+
(LeptrisElement)child_addr);
|
|
501
|
+
}
|
|
502
|
+
|
|
496
503
|
LeptrisStatus leptris_element_append_child(LeptrisElement parent, LeptrisElement child) {
|
|
497
504
|
if (!parent || !child) return LEPTRIS_ERROR_NULL_ARG;
|
|
498
505
|
|