yeptris 0.6.59.1-arm-linux-eabihf → 0.6.61.1-arm-linux-eabihf
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/ext/yeptris_native/version.h +2 -2
- data/lib/yeptris/3.4/native.so +0 -0
- data/lib/yeptris/ffi.rb +19 -0
- data/lib/yeptris/yaml.rb +71 -0
- data/lib/yeptris.rb +1 -1
- data/libyeptris.so +0 -0
- data/vendor/libyeptris/CMakeLists.txt +1 -1
- data/vendor/libyeptris/src/CMakeLists.txt +7 -0
- data/vendor/libyeptris/src/include/yeptris/emit.h +30 -2
- data/vendor/libyeptris/src/include/yeptris/parse.h +73 -0
- data/vendor/libyeptris/src/include/yeptris/resolve.h +8 -0
- data/vendor/libyeptris/src/include/yeptris/validate.h +222 -21
- data/vendor/libyeptris/src/include/yeptris/values.h +8 -2
- data/vendor/libyeptris/src/yeptris/cbor/cbor.h +10 -0
- data/vendor/libyeptris/src/yeptris/cbor/decode.c +5 -7
- data/vendor/libyeptris/src/yeptris/cbor/encode.c +9 -9
- data/vendor/libyeptris/src/yeptris/cbor/from_marshal.c +1 -1
- data/vendor/libyeptris/src/yeptris/common/error.h +2 -0
- data/vendor/libyeptris/src/yeptris/doc.h +20 -0
- data/vendor/libyeptris/src/yeptris/dom/dom.c +12 -1
- data/vendor/libyeptris/src/yeptris/dom/ytape.c +56 -7
- data/vendor/libyeptris/src/yeptris/emit/emit.c +93 -13
- data/vendor/libyeptris/src/yeptris/emit/writer.c +243 -652
- data/vendor/libyeptris/src/yeptris/emit/writer.h +25 -8
- data/vendor/libyeptris/src/yeptris/events/push.c +28 -3
- data/vendor/libyeptris/src/yeptris/events/values.c +46 -0
- data/vendor/libyeptris/src/yeptris/marshal/to_json.c +650 -0
- data/vendor/libyeptris/src/yeptris/parse/engine.c +611 -130
- data/vendor/libyeptris/src/yeptris/parse/engine.h +5 -0
- data/vendor/libyeptris/src/yeptris/parse/stream_iter.c +358 -0
- data/vendor/libyeptris/src/yeptris/parse.c +216 -44
- data/vendor/libyeptris/src/yeptris/resolve/compat11.c +3 -6
- data/vendor/libyeptris/src/yeptris/resolve/core12.c +11 -3
- data/vendor/libyeptris/src/yeptris/resolve/full12.c +201 -0
- data/vendor/libyeptris/src/yeptris/resolve/json12.c +12 -6
- data/vendor/libyeptris/src/yeptris/resolve/resolver.h +38 -0
- data/vendor/libyeptris/src/yeptris/resolve/tags.c +192 -0
- data/vendor/libyeptris/src/yeptris/scan/scan.c +22 -7
- data/vendor/libyeptris/src/yeptris/tape.c +24 -5
- data/vendor/libyeptris/src/yeptris/validate/compile.c +39 -3
- data/vendor/libyeptris/src/yeptris/validate/internal.h +223 -7
- data/vendor/libyeptris/src/yeptris/validate/jsonschema.c +645 -115
- data/vendor/libyeptris/src/yeptris/validate/output.c +246 -0
- data/vendor/libyeptris/src/yeptris/validate/regexp.c +623 -157
- data/vendor/libyeptris/src/yeptris/validate/registry.c +118 -0
- data/vendor/libyeptris/src/yeptris/validate/resources.c +601 -0
- data/vendor/libyeptris/src/yeptris/validate/stream.c +1155 -0
- data/vendor/libyeptris/src/yeptris/validate/validate.c +288 -145
- metadata +8 -1
|
@@ -52,7 +52,11 @@ typedef struct {
|
|
|
52
52
|
uint8_t tag_id; /* the resolver's verdict for this scalar */
|
|
53
53
|
uint8_t is_key; /* the entry lands in the inner map's key slot */
|
|
54
54
|
uint8_t b; /* BOOL payload; implicit-plain flag otherwise */
|
|
55
|
-
uint32_t off; /* STR/TIMESTAMP/ALIAS/anchor bytes
|
|
55
|
+
uint32_t off; /* STR/TIMESTAMP/ALIAS/anchor bytes; SEQ/MAP OPEN:
|
|
56
|
+
* the collection's EXPLICIT tag text ("tag:yaml.
|
|
57
|
+
* org,2002:set") when it carries one — off/len stay
|
|
58
|
+
* 0 for untagged containers, so hosts re-tag
|
|
59
|
+
* containers without a second drain */
|
|
56
60
|
uint32_t len;
|
|
57
61
|
uint64_t p; /* INT or FLOAT payload, by kind */
|
|
58
62
|
} YeptrisValue;
|
|
@@ -80,7 +84,9 @@ typedef struct {
|
|
|
80
84
|
size_t count;
|
|
81
85
|
size_t arena_len;
|
|
82
86
|
int64_t* payloads; /* INT or FLOAT bits, by kind */
|
|
83
|
-
uint32_t* offs; /* STR/TIMESTAMP/ALIAS/ANCHOR bytes
|
|
87
|
+
uint32_t* offs; /* STR/TIMESTAMP/ALIAS/ANCHOR bytes; SEQ/MAP OPEN:
|
|
88
|
+
the explicit tag text when tagged (see
|
|
89
|
+
YeptrisValue.off) */
|
|
84
90
|
uint32_t* lens;
|
|
85
91
|
uint8_t* kinds; /* YeptrisValueKind */
|
|
86
92
|
uint8_t* tags; /* resolver verdict per scalar */
|
|
@@ -11,6 +11,16 @@
|
|
|
11
11
|
extern "C" {
|
|
12
12
|
#endif
|
|
13
13
|
|
|
14
|
+
/* The semantic-tag chain law: decode renders the chain into a stack
|
|
15
|
+
* buffer; encode splits that text back into tag heads. ONE pair of
|
|
16
|
+
* constants governs both ends — the nightly's 23-nested-tags artifact
|
|
17
|
+
* (23 links decoded fine, encode-side tags[16] refused) was the two
|
|
18
|
+
* ends disagreeing. 64 links is already pathological (RFC 8949's
|
|
19
|
+
* registry is <20); a link renders up to 20 digits + separator, so
|
|
20
|
+
* the buffer holds a full 64-link chain. */
|
|
21
|
+
#define YEP_CBOR_TAGBUF 1408
|
|
22
|
+
#define YEP_CBOR_TAG_MAX_LINKS 64
|
|
23
|
+
|
|
14
24
|
/* one data item: bytes -> the shared DOM (the plan's item 01) */
|
|
15
25
|
/* One data item. consumed (may be NULL): when given, returns the
|
|
16
26
|
* item's byte extent and TRAILING BYTES ARE NOT an error (the
|
|
@@ -50,11 +50,6 @@ typedef struct {
|
|
|
50
50
|
uint8_t is_map;
|
|
51
51
|
} yep_cframe;
|
|
52
52
|
|
|
53
|
-
#define YEP_CBOR_TAGBUF \
|
|
54
|
-
512 /* a semantic-tag chain over ~23 links is \
|
|
55
|
-
* pathological; the arena form had no cap, \
|
|
56
|
-
* the stack form does (documented) */
|
|
57
|
-
|
|
58
53
|
typedef struct {
|
|
59
54
|
yep_dom* d; /* the DOM sink's ctx (NULL for pure sinks) */
|
|
60
55
|
const unsigned char* p;
|
|
@@ -66,6 +61,7 @@ typedef struct {
|
|
|
66
61
|
* first — the next item's writer consumes it) */
|
|
67
62
|
char tagbuf[YEP_CBOR_TAGBUF];
|
|
68
63
|
uint32_t taglen;
|
|
64
|
+
uint32_t taglinks; /* the chain's link count (the shared cap) */
|
|
69
65
|
/* indefinite-string accumulation (chunk framing is the grammar's;
|
|
70
66
|
* the finished span goes to one str/bytes callback) */
|
|
71
67
|
unsigned char* ibuf;
|
|
@@ -190,6 +186,7 @@ static const char* cbor_take_tag(yep_cdec* c, uint32_t* len) {
|
|
|
190
186
|
}
|
|
191
187
|
*len = c->taglen;
|
|
192
188
|
c->taglen = 0;
|
|
189
|
+
c->taglinks = 0;
|
|
193
190
|
return c->tagbuf;
|
|
194
191
|
}
|
|
195
192
|
|
|
@@ -239,9 +236,9 @@ static int cbor_open(yep_cdec* c, int is_map, uint64_t cap) {
|
|
|
239
236
|
}
|
|
240
237
|
|
|
241
238
|
static int cbor_note_tag(yep_cdec* c, uint64_t tag) {
|
|
242
|
-
if (c->taglen + 1 + 20 > sizeof c->tagbuf) {
|
|
239
|
+
if (c->taglinks >= YEP_CBOR_TAG_MAX_LINKS || c->taglen + 1 + 20 > sizeof c->tagbuf) {
|
|
243
240
|
yep_error_set(yep_error_tls(), YEP_ERR_UNEXPECTED, 0, 0, c->i,
|
|
244
|
-
"semantic-tag chain exceeds %u
|
|
241
|
+
"semantic-tag chain exceeds %u links at byte %zu", YEP_CBOR_TAG_MAX_LINKS,
|
|
245
242
|
c->i);
|
|
246
243
|
c->status = YEPTRIS_ERROR_PARSE;
|
|
247
244
|
return 0;
|
|
@@ -250,6 +247,7 @@ static int cbor_note_tag(yep_cdec* c, uint64_t tag) {
|
|
|
250
247
|
c->tagbuf[c->taglen++] = ' '; /* separator between chain links */
|
|
251
248
|
}
|
|
252
249
|
c->taglen += cbor_u64dec(tag, c->tagbuf + c->taglen);
|
|
250
|
+
c->taglinks++;
|
|
253
251
|
return 1;
|
|
254
252
|
}
|
|
255
253
|
|
|
@@ -326,14 +326,14 @@ typedef struct {
|
|
|
326
326
|
/* Encodes one KEY item (tags + scalar) into exactly-sized scratch. */
|
|
327
327
|
static uint8_t* cbor_encode_key(const yep_dom* d, const yep_dnode* key, size_t* out_len) {
|
|
328
328
|
yep_view v = yep_dom_view(d, key->value);
|
|
329
|
-
size_t cap =
|
|
329
|
+
size_t cap = (size_t)YEP_CBOR_TAG_MAX_LINKS * 9 + 9 + v.len; /* tags + head + text */
|
|
330
330
|
uint8_t* buf = malloc(cap);
|
|
331
331
|
if (buf == NULL) {
|
|
332
332
|
return NULL;
|
|
333
333
|
}
|
|
334
334
|
size_t pos = 0;
|
|
335
|
-
uint64_t tags[
|
|
336
|
-
int ntags = cbor_tag_chain(d, key, tags,
|
|
335
|
+
uint64_t tags[YEP_CBOR_TAG_MAX_LINKS];
|
|
336
|
+
int ntags = cbor_tag_chain(d, key, tags, YEP_CBOR_TAG_MAX_LINKS);
|
|
337
337
|
if (ntags < 0) {
|
|
338
338
|
goto bad;
|
|
339
339
|
}
|
|
@@ -491,8 +491,8 @@ static size_t cbor_size_item(cenc* e, uint32_t id);
|
|
|
491
491
|
static size_t cbor_size_scalar(cenc* e, const yep_dnode* n) {
|
|
492
492
|
const yep_dom* d = e->d;
|
|
493
493
|
size_t sz = 0;
|
|
494
|
-
uint64_t tags[
|
|
495
|
-
int ntags = cbor_tag_chain(d, n, tags,
|
|
494
|
+
uint64_t tags[YEP_CBOR_TAG_MAX_LINKS];
|
|
495
|
+
int ntags = cbor_tag_chain(d, n, tags, YEP_CBOR_TAG_MAX_LINKS);
|
|
496
496
|
if (ntags < 0) {
|
|
497
497
|
e->failed = 1;
|
|
498
498
|
e->status = YEPTRIS_ERROR_UNSUPPORTED;
|
|
@@ -534,8 +534,8 @@ static size_t cbor_size_item(cenc* e, uint32_t id) {
|
|
|
534
534
|
return cbor_size_scalar(e, n); /* includes the node's own tags */
|
|
535
535
|
}
|
|
536
536
|
size_t sz = 0;
|
|
537
|
-
uint64_t tags[
|
|
538
|
-
int ntags = cbor_tag_chain(d, n, tags,
|
|
537
|
+
uint64_t tags[YEP_CBOR_TAG_MAX_LINKS];
|
|
538
|
+
int ntags = cbor_tag_chain(d, n, tags, YEP_CBOR_TAG_MAX_LINKS);
|
|
539
539
|
if (ntags < 0) {
|
|
540
540
|
e->failed = 1;
|
|
541
541
|
e->status = YEPTRIS_ERROR_UNSUPPORTED;
|
|
@@ -653,8 +653,8 @@ static void cbor_write_scalar(cenc* e, const yep_dnode* n, uint8_t* out, size_t*
|
|
|
653
653
|
static void cbor_write_item(cenc* e, uint32_t id, uint8_t* out, size_t* pos) {
|
|
654
654
|
const yep_dom* d = e->d;
|
|
655
655
|
const yep_dnode* n = &d->nodes[id];
|
|
656
|
-
uint64_t tags[
|
|
657
|
-
int ntags = cbor_tag_chain(d, n, tags,
|
|
656
|
+
uint64_t tags[YEP_CBOR_TAG_MAX_LINKS];
|
|
657
|
+
int ntags = cbor_tag_chain(d, n, tags, YEP_CBOR_TAG_MAX_LINKS);
|
|
658
658
|
for (int t = 0; t < ntags; t++) {
|
|
659
659
|
yep_cbor_put_head(out, pos, 6, tags[t]);
|
|
660
660
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* from_marshal.c — Ruby Marshal.dump bytes to ONE CBOR data item
|
|
2
2
|
* (yeptris-ruby#322's CBOR half: the binding's dump face).
|
|
3
3
|
*
|
|
4
|
-
* The twin of
|
|
4
|
+
* The twin of marshal/to_json.c's JSON reader (yeptris_json_from_marshal):
|
|
5
5
|
* the Marshal stream is walked once, in C, and the CBOR item is
|
|
6
6
|
* appended straight to the output — no per-node Ruby crossings, no
|
|
7
7
|
* Document, no YAMLTree. The format facts mirror marshal.c's emission
|
|
@@ -25,6 +25,7 @@ extern "C" {
|
|
|
25
25
|
#define YEP_ERROR_X(X) \
|
|
26
26
|
X(YEP_ERR_NONE, "no error") \
|
|
27
27
|
X(YEP_ERR_UNEXPECTED, "unexpected parser state") \
|
|
28
|
+
X(YEP_ERR_DOC_BOUNDARY, "invalid content at a document boundary") \
|
|
28
29
|
X(YEP_ERR_MEMORY, "out of memory") \
|
|
29
30
|
X(YEP_ERR_DEPTH, "nesting depth exceeds the limit") \
|
|
30
31
|
X(YEP_ERR_ENCODING, "ill-formed or unsupported character encoding") \
|
|
@@ -33,6 +34,7 @@ extern "C" {
|
|
|
33
34
|
X(YEP_ERR_BAD_INDENT, "inconsistent indentation") \
|
|
34
35
|
X(YEP_ERR_KEY_TOO_LONG, "simple key exceeds 1024 characters") \
|
|
35
36
|
X(YEP_ERR_UNDEFINED_ALIAS, "alias references an undefined anchor") \
|
|
37
|
+
X(YEP_ERR_ABORTED, "parse aborted by the event callback") \
|
|
36
38
|
X(YEP_ERR_INVALID_ESCAPE, "invalid escape sequence in double-quoted scalar") \
|
|
37
39
|
X(YEP_ERR_BAD_DIRECTIVE, "invalid or unsupported directive") \
|
|
38
40
|
X(YEP_ERR_INTERNAL, "internal invariant violation") \
|
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
#include "dom/dom.h"
|
|
12
12
|
#include "memory/allocator.h"
|
|
13
13
|
|
|
14
|
+
#include <yeptris/error.h>
|
|
15
|
+
#include <yeptris/resolve.h> /* YeptrisSchema */
|
|
16
|
+
|
|
14
17
|
typedef struct yeptris_document {
|
|
15
18
|
yep_dom* dom;
|
|
16
19
|
const yep_allocator* sys;
|
|
@@ -59,8 +62,25 @@ extern "C" {
|
|
|
59
62
|
yep_dom* yep_doc_dom(yeptris_document* doc);
|
|
60
63
|
yeptris_node* yep_handle_new(yeptris_document* doc, uint32_t id);
|
|
61
64
|
|
|
65
|
+
/* parse.c's sink-entry seam (#902): the DOM route's exact front-end and
|
|
66
|
+
* engine run into a caller sink — no DOM, no tape. Statuses are the
|
|
67
|
+
* parse route's (OK, or PARSE / DEPTH / ENCODING / MEMORY; the sink's
|
|
68
|
+
* own failure rides MEMORY like the DOM builder's). on_input (may be
|
|
69
|
+
* NULL) receives the run's input view — the DOM route's input_base law
|
|
70
|
+
* (the transcoded copy, or the caller's bytes) and its post-BOM length
|
|
71
|
+
* — immediately before the engine runs, because the events' borrowed
|
|
72
|
+
* views subtract from it. The bytes live only for the run. */
|
|
73
|
+
typedef void (*yep_input_fn)(void* ctx, const char* base, size_t len);
|
|
74
|
+
YeptrisStatus yep_parse_events(const char* buf, size_t len, YeptrisSchema schema,
|
|
75
|
+
const yep_sink* sink, yep_input_fn on_input, void* on_ctx);
|
|
76
|
+
|
|
62
77
|
#ifdef __cplusplus
|
|
63
78
|
}
|
|
64
79
|
#endif
|
|
65
80
|
|
|
81
|
+
/* The typing SSOT's one switch (parse.c owns it; the stream iterator
|
|
82
|
+
* and any future bytes->document route select through it too). */
|
|
83
|
+
struct yep_resolver; /* resolve/resolver.h's fwd — doc.h stays leaf */
|
|
84
|
+
const struct yep_resolver* resolver_for_schema(YeptrisSchema schema);
|
|
85
|
+
|
|
66
86
|
#endif /* YEP_DOC_H */
|
|
@@ -158,7 +158,18 @@ static yep_sview dom_str_in(yep_dom* d, const yep_view* v, int borrowed) {
|
|
|
158
158
|
yep_sview sv = {0, 0};
|
|
159
159
|
return sv;
|
|
160
160
|
}
|
|
161
|
-
|
|
161
|
+
/* The zero-copy law: borrow ONLY a view demonstrably inside the
|
|
162
|
+
* recorded input window. The old heap-order probe (v->p >=
|
|
163
|
+
* input_base) misfiled every engine-owned buffer that happened to
|
|
164
|
+
* sit above the caller's input — the r171 normalizer copy path
|
|
165
|
+
* (norm_buf) hands exactly such views to the pair/event builders —
|
|
166
|
+
* and the resulting input-relative offset was then layout luck per
|
|
167
|
+
* platform/build (the ubuntu-gcc / MSVC-arm / TSan / UBSan CI
|
|
168
|
+
* divergences of PR #1042). The upper bound makes the decision a
|
|
169
|
+
* pure function of the view's location class: both engines of a
|
|
170
|
+
* differential run now store identically on every platform. */
|
|
171
|
+
if (borrowed && v->p != NULL && d->input_base != NULL &&
|
|
172
|
+
(size_t)((const char*)v->p - d->input_base) + v->len <= d->input_len) {
|
|
162
173
|
return yep_sv_input(d, *v);
|
|
163
174
|
}
|
|
164
175
|
return yep_dom_str_put(d, (const char*)v->p, v->len);
|
|
@@ -1640,15 +1640,64 @@ static int yt_f_run(yt_fused* F) {
|
|
|
1640
1640
|
col + 1 != st[depth].content_col && st[depth].phantom) {
|
|
1641
1641
|
yt_f_close(F, st[depth].kind);
|
|
1642
1642
|
st[depth].phantom = 0;
|
|
1643
|
+
st[depth].content_col =
|
|
1644
|
+
0; /* the content map is gone:
|
|
1645
|
+
* its column must not greet later pairs (the
|
|
1646
|
+
* stale-frame law, run 38179552341) — after the
|
|
1647
|
+
* chained-pending arm resumes here, a stale
|
|
1648
|
+
* column rode yt_f_open_form's sibling test and
|
|
1649
|
+
* misfiled the next pending's container as a
|
|
1650
|
+
* key-SCALAR ("b:\n c: d\nq:\n b:\n c: d\n"
|
|
1651
|
+
* lost q's map; the nightly's run 42488986434) */
|
|
1643
1652
|
}
|
|
1644
1653
|
if (depth > 0 && st[depth].pending) {
|
|
1645
|
-
/* chained
|
|
1646
|
-
*
|
|
1647
|
-
*
|
|
1648
|
-
*
|
|
1649
|
-
*
|
|
1650
|
-
*
|
|
1651
|
-
|
|
1654
|
+
/* a chained pending ("a:\na:", the deep-nesting
|
|
1655
|
+
* "k:\n k:\n k:" ladder): resolve the outer
|
|
1656
|
+
* one before the sibling's frame takes the slot.
|
|
1657
|
+
* A same-column sibling key (col == the pending's
|
|
1658
|
+
* own column) gives the pending a NULL value —
|
|
1659
|
+
* the null pair MUST land now, or the OPEN'd
|
|
1660
|
+
* container swallows the sibling key as its
|
|
1661
|
+
* first pair's value (the nightly's run
|
|
1662
|
+
* 38110714729 tree corruption: {a: a, ?{b: c}:
|
|
1663
|
+
* h} instead of {a: null, a: {b: c}, h: v}).
|
|
1664
|
+
* When the OPEN form fired, the null pairs
|
|
1665
|
+
* INSIDE the opened container (parent → {k:
|
|
1666
|
+
* null}); under the key-SCALAR form it completes
|
|
1667
|
+
* the key's pair in the parent's map. A deeper
|
|
1668
|
+
* line (col > indent) opens the pending's
|
|
1669
|
+
* container and the chain nests. Anchored
|
|
1670
|
+
* pendings keep the engine: their anchor rides
|
|
1671
|
+
* the event path (yt_f_open drops the name) */
|
|
1672
|
+
if (st[depth].aid != 0) {
|
|
1673
|
+
return 1;
|
|
1674
|
+
}
|
|
1675
|
+
uint8_t of = yt_f_open_form(&st[depth - 1], depth == 1, st[depth].indent);
|
|
1676
|
+
if (aid != 0 && of == 0) {
|
|
1677
|
+
/* the outer pending resolved as a SIBLING
|
|
1678
|
+
* key-SCALAR: its value container is "the pair's",
|
|
1679
|
+
* materialized by the next OPEN-class record — but
|
|
1680
|
+
* the anchored pending resolves through the event
|
|
1681
|
+
* path, which emits its KEY SCALAR *before* the
|
|
1682
|
+
* anchored MAP_START. That key pairs with the
|
|
1683
|
+
* stranded outer key (the pair's value slot) and
|
|
1684
|
+
* the anchored map strands as a sibling key of the
|
|
1685
|
+
* parent: "2: e\n4:\n 5: &5\n 5: e\n7: s"
|
|
1686
|
+
* built {2:e, 4:"5", {5:e}&5:"7", s:null} instead
|
|
1687
|
+
* of {2:e, 4:{5:{5:e}&5}, 7:s} (the nightly's
|
|
1688
|
+
* crash-d8e3b3f392c37a62257576ce20d5a19b351f66ad,
|
|
1689
|
+
* round 213 — the first shape where a completed
|
|
1690
|
+
* pair arms root_pair_col BEFORE the chain). The
|
|
1691
|
+
* engine resolves the composition. */
|
|
1692
|
+
return 1;
|
|
1693
|
+
}
|
|
1694
|
+
yt_f_open(F, &st[depth], of);
|
|
1695
|
+
root_open = 1;
|
|
1696
|
+
if (col == st[depth].indent) {
|
|
1697
|
+
(void)yt_put(t, yt_props(YTP_SCALAR, 0, 0x0904u));
|
|
1698
|
+
yt_f_empty_span(F);
|
|
1699
|
+
}
|
|
1700
|
+
st[depth].pending = 0;
|
|
1652
1701
|
}
|
|
1653
1702
|
/* a spent key-SCALAR frame (resolved, phantom closed,
|
|
1654
1703
|
* no map of its own) gives its slot to the sibling —
|
|
@@ -11,12 +11,22 @@
|
|
|
11
11
|
#include "../doc.h"
|
|
12
12
|
#include "writer.h"
|
|
13
13
|
|
|
14
|
+
/* Every field reads behind ITS OWN offsetof gate — never the whole
|
|
15
|
+
* struct's sizeof. The #909/#903 append grew sizeof(*opts) to 24, and
|
|
16
|
+
* a `size >= sizeof(*opts)` gate silently orphaned the ORIGINAL
|
|
17
|
+
* fields for callers compiled against the 16-byte struct (the Ruby
|
|
18
|
+
* binding): best_width fell back to 80 and canonical fell off. The
|
|
19
|
+
* versioning contract is per field: declared-present or default. */
|
|
14
20
|
static int opts_canonical(const yeptris_emit_options* opts) {
|
|
15
|
-
return opts != NULL &&
|
|
21
|
+
return opts != NULL &&
|
|
22
|
+
opts->size >= (uint32_t)(offsetof(yeptris_emit_options, canonical) + sizeof(int)) &&
|
|
23
|
+
opts->canonical;
|
|
16
24
|
}
|
|
17
25
|
|
|
18
26
|
static int opts_width(const yeptris_emit_options* opts) {
|
|
19
|
-
if (opts == NULL ||
|
|
27
|
+
if (opts == NULL ||
|
|
28
|
+
opts->size < (uint32_t)(offsetof(yeptris_emit_options, best_width) + sizeof(int)) ||
|
|
29
|
+
opts->best_width <= 0) {
|
|
20
30
|
return 80; /* libyaml best_width parity */
|
|
21
31
|
}
|
|
22
32
|
return opts->best_width;
|
|
@@ -32,6 +42,41 @@ static int opts_doc_marker(const yeptris_emit_options* opts) {
|
|
|
32
42
|
return opts->explicit_doc_start != 0;
|
|
33
43
|
}
|
|
34
44
|
|
|
45
|
+
static int opts_indent(const yeptris_emit_options* opts) {
|
|
46
|
+
/* size-versioned (#903); out of range rides the default (libyaml
|
|
47
|
+
* clamps 2..9 the same way) */
|
|
48
|
+
int ind = 2;
|
|
49
|
+
if (opts != NULL &&
|
|
50
|
+
opts->size >= (uint32_t)(offsetof(yeptris_emit_options, best_indent) + sizeof(int))) {
|
|
51
|
+
ind = opts->best_indent;
|
|
52
|
+
}
|
|
53
|
+
if (ind < 2 || ind > 9) {
|
|
54
|
+
ind = 2;
|
|
55
|
+
}
|
|
56
|
+
return ind;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
static int opts_block_fold(const yeptris_emit_options* opts) {
|
|
60
|
+
/* size-versioned (#903): default off — block output stays
|
|
61
|
+
* width-invariant (byte-identical with the pre-option releases) */
|
|
62
|
+
if (opts == NULL ||
|
|
63
|
+
opts->size < (uint32_t)(offsetof(yeptris_emit_options, block_fold) + sizeof(int))) {
|
|
64
|
+
return 0;
|
|
65
|
+
}
|
|
66
|
+
return opts->block_fold != 0;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* The emitter's SCRATCH rides the document's allocator (#904 item 3):
|
|
70
|
+
* sc_dec and the streaming window are emitter-internal (never leak
|
|
71
|
+
* into caller hands), so the fail-injection harness — a counting
|
|
72
|
+
* allocator passed at the document's build — now reaches them. The
|
|
73
|
+
* CALLER-RETURNED output buffers stay system-malloc on purpose: their
|
|
74
|
+
* release contract is free() (emit.h "malloc'd buffer, caller frees"),
|
|
75
|
+
* and a failing allocator's pointer cannot be freed by the host. */
|
|
76
|
+
static const yep_allocator* emit_sys(const yeptris_document* doc) {
|
|
77
|
+
return doc->sys != NULL ? doc->sys : yep_system_allocator();
|
|
78
|
+
}
|
|
79
|
+
|
|
35
80
|
YEPTRIS_API size_t yeptris_serialize_into_ex(YeptrisDocument handle,
|
|
36
81
|
const yeptris_emit_options* opts, char* buf,
|
|
37
82
|
size_t cap) {
|
|
@@ -62,18 +107,22 @@ YEPTRIS_API size_t yeptris_serialize_into_ex(YeptrisDocument handle,
|
|
|
62
107
|
em.w.json_pretty = 0;
|
|
63
108
|
em.w.pretty_depth = 0;
|
|
64
109
|
em.w.best_width = opts_width(opts);
|
|
110
|
+
em.w.indent = opts_indent(opts);
|
|
111
|
+
em.w.block_fold = opts_block_fold(opts);
|
|
65
112
|
em.w.col = 0;
|
|
66
113
|
em.w.sv_input = handle ? ((const yeptris_document*)handle)->dom->input_base : NULL;
|
|
67
114
|
em.w.sv_arena = handle ? ((const yeptris_document*)handle)->dom->str : NULL;
|
|
115
|
+
em.w.resolver = handle ? ((const yeptris_document*)handle)->dom->resolver : NULL;
|
|
68
116
|
em.w.sink = NULL;
|
|
69
117
|
em.w.watermark = 0;
|
|
70
118
|
em.w.sink_aborted = 0;
|
|
71
119
|
em.w.flushed = 0;
|
|
72
120
|
memset(&em.canon_names, 0, sizeof(em.canon_names));
|
|
73
|
-
if (em.w.canonical && !yep_nametab_init(&em.canon_names,
|
|
121
|
+
if (em.w.canonical && !yep_nametab_init(&em.canon_names, emit_sys(em.doc))) {
|
|
74
122
|
return 0;
|
|
75
123
|
}
|
|
76
|
-
em.w.sc_dec =
|
|
124
|
+
em.w.sc_dec =
|
|
125
|
+
(uint8_t*)yep_alloc(emit_sys(em.doc), em.doc->dom->ncount > 0 ? em.doc->dom->ncount : 1);
|
|
77
126
|
if (em.w.sc_dec == NULL) {
|
|
78
127
|
if (em.canon_names.sys != NULL) {
|
|
79
128
|
yep_nametab_free(&em.canon_names);
|
|
@@ -82,7 +131,7 @@ YEPTRIS_API size_t yeptris_serialize_into_ex(YeptrisDocument handle,
|
|
|
82
131
|
}
|
|
83
132
|
size_t need = yep_emit_run(&em, 1);
|
|
84
133
|
if (buf == NULL || cap < need + 1) {
|
|
85
|
-
|
|
134
|
+
yep_free(emit_sys(em.doc), em.w.sc_dec);
|
|
86
135
|
if (em.canon_names.sys != NULL) {
|
|
87
136
|
yep_nametab_free(&em.canon_names);
|
|
88
137
|
}
|
|
@@ -90,7 +139,7 @@ YEPTRIS_API size_t yeptris_serialize_into_ex(YeptrisDocument handle,
|
|
|
90
139
|
}
|
|
91
140
|
em.w.p = buf;
|
|
92
141
|
size_t wrote = yep_emit_run(&em, 0);
|
|
93
|
-
|
|
142
|
+
yep_free(emit_sys(em.doc), em.w.sc_dec);
|
|
94
143
|
if (em.canon_names.sys != NULL) {
|
|
95
144
|
yep_nametab_free(&em.canon_names);
|
|
96
145
|
}
|
|
@@ -128,15 +177,18 @@ YEPTRIS_API size_t yeptris_serialize_into_trusted(YeptrisDocument handle,
|
|
|
128
177
|
em.w.json_pretty = 0;
|
|
129
178
|
em.w.pretty_depth = 0;
|
|
130
179
|
em.w.best_width = opts_width(opts);
|
|
180
|
+
em.w.indent = opts_indent(opts);
|
|
181
|
+
em.w.block_fold = opts_block_fold(opts);
|
|
131
182
|
em.w.col = 0;
|
|
132
183
|
em.w.sv_input = ((const yeptris_document*)handle)->dom->input_base;
|
|
133
184
|
em.w.sv_arena = ((const yeptris_document*)handle)->dom->str;
|
|
185
|
+
em.w.resolver = ((const yeptris_document*)handle)->dom->resolver;
|
|
134
186
|
em.w.sink = NULL;
|
|
135
187
|
em.w.watermark = 0;
|
|
136
188
|
em.w.sink_aborted = 0;
|
|
137
189
|
em.w.flushed = 0;
|
|
138
190
|
memset(&em.canon_names, 0, sizeof(em.canon_names));
|
|
139
|
-
if (em.w.canonical && !yep_nametab_init(&em.canon_names,
|
|
191
|
+
if (em.w.canonical && !yep_nametab_init(&em.canon_names, emit_sys(em.doc))) {
|
|
140
192
|
return 0;
|
|
141
193
|
}
|
|
142
194
|
/* #352: ONE bounded wet pass — no memo, no dry run (the emit-split
|
|
@@ -194,15 +246,18 @@ YEPTRIS_API char* yeptris_serialize_ex(YeptrisDocument handle, const yeptris_emi
|
|
|
194
246
|
em.w.json_pretty = 0;
|
|
195
247
|
em.w.pretty_depth = 0;
|
|
196
248
|
em.w.best_width = opts_width(opts);
|
|
249
|
+
em.w.indent = opts_indent(opts);
|
|
250
|
+
em.w.block_fold = opts_block_fold(opts);
|
|
197
251
|
em.w.col = 0;
|
|
198
252
|
em.w.sv_input = handle ? ((const yeptris_document*)handle)->dom->input_base : NULL;
|
|
199
253
|
em.w.sv_arena = handle ? ((const yeptris_document*)handle)->dom->str : NULL;
|
|
254
|
+
em.w.resolver = handle ? ((const yeptris_document*)handle)->dom->resolver : NULL;
|
|
200
255
|
em.w.sink = NULL;
|
|
201
256
|
em.w.watermark = 0;
|
|
202
257
|
em.w.sink_aborted = 0;
|
|
203
258
|
em.w.flushed = 0;
|
|
204
259
|
memset(&em.canon_names, 0, sizeof(em.canon_names));
|
|
205
|
-
if (em.w.canonical && !yep_nametab_init(&em.canon_names,
|
|
260
|
+
if (em.w.canonical && !yep_nametab_init(&em.canon_names, emit_sys(em.doc))) {
|
|
206
261
|
return NULL;
|
|
207
262
|
}
|
|
208
263
|
/* #352 slice 2: ONE wet pass into a growable buffer — the dry
|
|
@@ -211,6 +266,9 @@ YEPTRIS_API char* yeptris_serialize_ex(YeptrisDocument handle, const yeptris_emi
|
|
|
211
266
|
* starts at the input size (+64) and doubles on demand; a final
|
|
212
267
|
* shrink-to-fit keeps the returned allocation tight. No dry pass,
|
|
213
268
|
* so no decisions table. */
|
|
269
|
+
/* raw malloc ON PURPOSE (#904 item 3): this buffer is RETURNED —
|
|
270
|
+
* the release contract is the host's free() (emit.h), so it must
|
|
271
|
+
* come from the system allocator, not the document's */
|
|
214
272
|
size_t est = em.doc->dom->input_len + 64;
|
|
215
273
|
if (est < 256) {
|
|
216
274
|
est = 256;
|
|
@@ -260,6 +318,8 @@ YEPTRIS_API char* yeptris_serialize_ex(YeptrisDocument handle, const yeptris_emi
|
|
|
260
318
|
* (+64) and doubles on demand; shrink-to-fit at the end. Owns the
|
|
261
319
|
* emitter's canon_names cleanup. */
|
|
262
320
|
static char* yep_json_run_growable(yep_emitter* em, size_t* len) {
|
|
321
|
+
/* raw malloc ON PURPOSE (#904 item 3): the buffer is RETURNED —
|
|
322
|
+
* the host's free() owns it (emit.h), system allocator only */
|
|
263
323
|
size_t est = em->doc->dom->input_len + 64;
|
|
264
324
|
if (est < 256) {
|
|
265
325
|
est = 256;
|
|
@@ -328,9 +388,12 @@ YEPTRIS_API char* yeptris_serialize_json(YeptrisDocument handle, size_t* len) {
|
|
|
328
388
|
em.w.json_pretty = 0;
|
|
329
389
|
em.w.pretty_depth = 0;
|
|
330
390
|
em.w.best_width = 0; /* JSON: no folding (single-line output) */
|
|
391
|
+
em.w.indent = 2;
|
|
392
|
+
em.w.block_fold = 0;
|
|
331
393
|
em.w.col = 0;
|
|
332
394
|
em.w.sv_input = handle ? ((const yeptris_document*)handle)->dom->input_base : NULL;
|
|
333
395
|
em.w.sv_arena = handle ? ((const yeptris_document*)handle)->dom->str : NULL;
|
|
396
|
+
em.w.resolver = handle ? ((const yeptris_document*)handle)->dom->resolver : NULL;
|
|
334
397
|
em.w.sink = NULL;
|
|
335
398
|
em.w.watermark = 0;
|
|
336
399
|
em.w.sink_aborted = 0;
|
|
@@ -370,9 +433,12 @@ YEPTRIS_API char* yeptris_serialize_json_ex(YeptrisDocument handle, size_t* len,
|
|
|
370
433
|
em.w.json_pretty = 0;
|
|
371
434
|
em.w.pretty_depth = 0;
|
|
372
435
|
em.w.best_width = 0; /* JSON: no folding (single-line output) */
|
|
436
|
+
em.w.indent = 2;
|
|
437
|
+
em.w.block_fold = 0;
|
|
373
438
|
em.w.col = 0;
|
|
374
439
|
em.w.sv_input = handle ? ((const yeptris_document*)handle)->dom->input_base : NULL;
|
|
375
440
|
em.w.sv_arena = handle ? ((const yeptris_document*)handle)->dom->str : NULL;
|
|
441
|
+
em.w.resolver = handle ? ((const yeptris_document*)handle)->dom->resolver : NULL;
|
|
376
442
|
em.w.sink = NULL;
|
|
377
443
|
em.w.watermark = 0;
|
|
378
444
|
em.w.sink_aborted = 0;
|
|
@@ -414,9 +480,12 @@ char* yep_serialize_json_compact(const yeptris_document* doc, size_t* len) {
|
|
|
414
480
|
em.w.json_pretty = 0;
|
|
415
481
|
em.w.pretty_depth = 0;
|
|
416
482
|
em.w.best_width = 0;
|
|
483
|
+
em.w.indent = 2;
|
|
484
|
+
em.w.block_fold = 0;
|
|
417
485
|
em.w.col = 0;
|
|
418
486
|
em.w.sv_input = doc->dom->input_base;
|
|
419
487
|
em.w.sv_arena = doc->dom->str;
|
|
488
|
+
em.w.resolver = doc->dom->resolver;
|
|
420
489
|
em.w.sink = NULL;
|
|
421
490
|
em.w.watermark = 0;
|
|
422
491
|
em.w.sink_aborted = 0;
|
|
@@ -460,17 +529,22 @@ char* yep_serialize_json_pretty_ex(const yeptris_document* doc, size_t* len, con
|
|
|
460
529
|
em.w.json_indent = indent;
|
|
461
530
|
em.w.json_indent_len = indent == NULL ? 2 : (int)indent_len;
|
|
462
531
|
em.w.best_width = 0;
|
|
532
|
+
em.w.indent = 2;
|
|
533
|
+
em.w.block_fold = 0;
|
|
463
534
|
em.w.col = 0;
|
|
464
535
|
em.w.sv_input = doc->dom->input_base;
|
|
465
536
|
em.w.sv_arena = doc->dom->str;
|
|
537
|
+
em.w.resolver = doc->dom->resolver;
|
|
466
538
|
em.w.sink = NULL;
|
|
467
539
|
em.w.watermark = 0;
|
|
468
540
|
em.w.sink_aborted = 0;
|
|
469
541
|
em.w.flushed = 0;
|
|
470
542
|
memset(&em.canon_names, 0, sizeof(em.canon_names));
|
|
471
|
-
if (em.w.canonical && !yep_nametab_init(&em.canon_names,
|
|
543
|
+
if (em.w.canonical && !yep_nametab_init(&em.canon_names, emit_sys(doc))) {
|
|
472
544
|
return NULL;
|
|
473
545
|
}
|
|
546
|
+
/* raw malloc ON PURPOSE (#904 item 3): the dry-wet pair's exact-
|
|
547
|
+
* sized output is RETURNED — the host's free() owns it */
|
|
474
548
|
size_t need = yep_emit_run(&em, 1);
|
|
475
549
|
char* out = malloc(need + 1);
|
|
476
550
|
if (out == NULL) {
|
|
@@ -532,18 +606,24 @@ YEPTRIS_API size_t yeptris_serialize_stream(YeptrisDocument handle,
|
|
|
532
606
|
em.w.json_pretty = 0;
|
|
533
607
|
em.w.pretty_depth = 0;
|
|
534
608
|
em.w.best_width = opts_width(opts);
|
|
609
|
+
em.w.indent = opts_indent(opts);
|
|
610
|
+
em.w.block_fold = opts_block_fold(opts);
|
|
535
611
|
em.w.col = 0;
|
|
536
612
|
em.w.sv_input = handle ? ((const yeptris_document*)handle)->dom->input_base : NULL;
|
|
537
613
|
em.w.sv_arena = handle ? ((const yeptris_document*)handle)->dom->str : NULL;
|
|
614
|
+
em.w.resolver = handle ? ((const yeptris_document*)handle)->dom->resolver : NULL;
|
|
538
615
|
em.w.sink = sink;
|
|
539
616
|
em.w.sink_ctx = ctx;
|
|
540
617
|
em.w.watermark = YEP_EMIT_WATERMARK;
|
|
541
618
|
memset(&em.canon_names, 0, sizeof(em.canon_names));
|
|
542
|
-
if (em.w.canonical && !yep_nametab_init(&em.canon_names,
|
|
619
|
+
if (em.w.canonical && !yep_nametab_init(&em.canon_names, emit_sys(em.doc))) {
|
|
543
620
|
return 0;
|
|
544
621
|
}
|
|
545
|
-
/* one scratch window; the writer flushes it when it fills
|
|
546
|
-
|
|
622
|
+
/* one scratch window; the writer flushes it when it fills.
|
|
623
|
+
* Document allocator (#904 item 3): emitter-internal scratch —
|
|
624
|
+
* flushed out through the sink, never returned — so the
|
|
625
|
+
* fail-injection harness reaches it. */
|
|
626
|
+
char* window = yep_alloc(emit_sys(em.doc), YEP_EMIT_WATERMARK * 2);
|
|
547
627
|
if (window == NULL) {
|
|
548
628
|
if (em.canon_names.sys != NULL) {
|
|
549
629
|
yep_nametab_free(&em.canon_names);
|
|
@@ -564,7 +644,7 @@ YEPTRIS_API size_t yeptris_serialize_stream(YeptrisDocument handle,
|
|
|
564
644
|
/* total already counted by the flush hooks */
|
|
565
645
|
}
|
|
566
646
|
}
|
|
567
|
-
|
|
647
|
+
yep_free(emit_sys(em.doc), window);
|
|
568
648
|
if (em.canon_names.sys != NULL) {
|
|
569
649
|
yep_nametab_free(&em.canon_names);
|
|
570
650
|
}
|