yeptris 0.6.59.1-aarch64-linux → 0.6.61.1-aarch64-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/ext/yeptris_native/version.h +2 -2
- data/lib/yeptris/3.3/native.so +0 -0
- data/lib/yeptris/3.4/native.so +0 -0
- data/lib/yeptris/4.0/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 +9 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bbbe4a9411210888a16c92e91b7d17d6e15f0ccb7ad48d8acdf174f867f51f45
|
|
4
|
+
data.tar.gz: dcbe1dae7f15b3541c5d2587e7914e50a4cd1575dc301cfd73aefbdb3f62882d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 52c8f1fb37c18fc9e0d31a7b8d4d0ddbb19d7c408077ca324e60ba6594c2f7dc3d56794421fb255b287c42a01a501e53cd01a6ee16806fe38504fced57c794e6
|
|
7
|
+
data.tar.gz: c09e79a2a68c4cac043801616accde5655ea10d9a7a278c91d10f3824e55e35ea29dad1c5736cedc019e7298ab27b1e0fc737a5c4eb679ca047e221dba2ad662
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
|
|
12
12
|
#define YEPTRIS_VERSION_MAJOR 0
|
|
13
13
|
#define YEPTRIS_VERSION_MINOR 6
|
|
14
|
-
#define YEPTRIS_VERSION_PATCH
|
|
15
|
-
#define YEPTRIS_VERSION_STRING "0.6.
|
|
14
|
+
#define YEPTRIS_VERSION_PATCH 61
|
|
15
|
+
#define YEPTRIS_VERSION_STRING "0.6.61"
|
|
16
16
|
|
|
17
17
|
#ifdef __cplusplus
|
|
18
18
|
extern "C" {
|
data/lib/yeptris/3.3/native.so
CHANGED
|
Binary file
|
data/lib/yeptris/3.4/native.so
CHANGED
|
Binary file
|
data/lib/yeptris/4.0/native.so
CHANGED
|
Binary file
|
data/lib/yeptris/ffi.rb
CHANGED
|
@@ -56,6 +56,7 @@ module Yeptris
|
|
|
56
56
|
|
|
57
57
|
|
|
58
58
|
typedef :pointer, :yeptris_document
|
|
59
|
+
typedef :pointer, :yeptris_stream_iter
|
|
59
60
|
typedef :pointer, :yeptris_node
|
|
60
61
|
typedef :pointer, :yeptris_status_out
|
|
61
62
|
typedef :int, :yeptris_status
|
|
@@ -87,6 +88,24 @@ module Yeptris
|
|
|
87
88
|
%i[pointer size_t pointer yeptris_status_out], :yeptris_document
|
|
88
89
|
attach_function :yeptris_parse_json, %i[pointer size_t yeptris_status_out], :yeptris_document
|
|
89
90
|
|
|
91
|
+
# The tolerant per-document stream iterator (engine #921): frames
|
|
92
|
+
# documents scanner-accurately, reports failures per document (the
|
|
93
|
+
# failed run's line/col ARE that document's own), resyncs to the
|
|
94
|
+
# next line-start marker. On an engine older than the iterator the
|
|
95
|
+
# attach stubs above raise the stale-engine message at USE
|
|
96
|
+
# (each_document's caller sees it directly — no separate gate
|
|
97
|
+
# constant, the @missing law covers it).
|
|
98
|
+
attach_function :yeptris_stream_iter_new, %i[pointer size_t pointer], :yeptris_stream_iter
|
|
99
|
+
attach_function :yeptris_stream_iter_next,
|
|
100
|
+
%i[yeptris_stream_iter pointer pointer], :yeptris_status
|
|
101
|
+
attach_function :yeptris_stream_iter_status,
|
|
102
|
+
%i[yeptris_stream_iter pointer pointer], :yeptris_status
|
|
103
|
+
attach_function :yeptris_stream_iter_free, [:yeptris_stream_iter], :void
|
|
104
|
+
# the capability probe (evaluated AFTER the attaches above — the
|
|
105
|
+
# CBOR.available? pattern): specs and hosts gate on it; at USE a
|
|
106
|
+
# stale engine still raises the stub's message
|
|
107
|
+
STREAM_ITER = !(@missing ||= []).include?(:yeptris_stream_iter_new)
|
|
108
|
+
|
|
90
109
|
# The JSON tape (TODO.restructure/85; the JSON surface's load
|
|
91
110
|
# engine — issue #81): ONE call, three bulk columns, spans borrow
|
|
92
111
|
# the caller's string (no arena copy, no second validating parse).
|
data/lib/yeptris/yaml.rb
CHANGED
|
@@ -197,6 +197,67 @@ module Yeptris
|
|
|
197
197
|
results
|
|
198
198
|
end
|
|
199
199
|
|
|
200
|
+
# The engine capability behind each_document (the CBOR.available?
|
|
201
|
+
# pattern): false when the loaded libyeptris predates the stream
|
|
202
|
+
# iterator — the walk itself raises the stale-engine message at use.
|
|
203
|
+
def each_document?
|
|
204
|
+
FFI::STREAM_ITER
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# The tolerant per-document walk (engine #921): every document of
|
|
208
|
+
# the stream reaches the block IN STREAM ORDER — a valid document
|
|
209
|
+
# yields (document, nil); a failed document yields (nil, error)
|
|
210
|
+
# and the walk CONTINUES at the next line-start marker, so the
|
|
211
|
+
# valid documents after a bad one are kept (load_stream with
|
|
212
|
+
# errors: :raise would drop the whole stream; :collect recovers by
|
|
213
|
+
# a regex slice split, which quoted scalars spanning marker-looking
|
|
214
|
+
# lines can defeat — the engine iterator frames scanner-accurately,
|
|
215
|
+
# so those documents fail as ONE unit instead of splitting).
|
|
216
|
+
# Errors carry the failed document's own line/column and its
|
|
217
|
+
# stream index. Without a block, an Enumerator over the pairs.
|
|
218
|
+
def each_document(yaml, schema: :compat_11, max_depth: 0, &block)
|
|
219
|
+
return enum_for(:each_document, yaml, schema: schema, max_depth: max_depth) unless block
|
|
220
|
+
|
|
221
|
+
yaml = Yeptris.read_input(yaml)
|
|
222
|
+
yaml = yaml.to_s
|
|
223
|
+
opts = FFI::ParseOptions.new
|
|
224
|
+
opts[:schema] = schema == :compat_11 ? FFI::SCHEMA_11_COMPAT : FFI::SCHEMA_12_CORE
|
|
225
|
+
opts[:max_depth] = max_depth
|
|
226
|
+
it = FFI.yeptris_stream_iter_new(yaml, yaml.bytesize, opts)
|
|
227
|
+
doc_p = ::FFI::MemoryPointer.new(:pointer)
|
|
228
|
+
idx_p = ::FFI::MemoryPointer.new(:size_t)
|
|
229
|
+
line_p = ::FFI::MemoryPointer.new(:uint32)
|
|
230
|
+
col_p = ::FFI::MemoryPointer.new(:uint32)
|
|
231
|
+
begin
|
|
232
|
+
loop do
|
|
233
|
+
st = FFI.yeptris_stream_iter_next(it, doc_p, idx_p)
|
|
234
|
+
doc_ptr = doc_p.read_pointer
|
|
235
|
+
break if st == FFI::OK && doc_ptr.null? # the stream is over
|
|
236
|
+
|
|
237
|
+
index = FFI.read_c_size_t(idx_p)
|
|
238
|
+
if st == FFI::OK
|
|
239
|
+
doc = Document.without_finalizer(doc_ptr)
|
|
240
|
+
begin
|
|
241
|
+
yield doc.to_ruby, nil
|
|
242
|
+
ensure
|
|
243
|
+
doc.free
|
|
244
|
+
end
|
|
245
|
+
else
|
|
246
|
+
FFI.yeptris_stream_iter_status(it, line_p, col_p)
|
|
247
|
+
reason = st == FFI::ERROR_DEPTH ? "depth limit exceeded" : "parse error"
|
|
248
|
+
yield nil,
|
|
249
|
+
ParseError.new(
|
|
250
|
+
"stream document #{index}: #{reason} at line #{line_p.read_uint32}, " \
|
|
251
|
+
"column #{col_p.read_uint32}"
|
|
252
|
+
)
|
|
253
|
+
break if st == FFI::ERROR_MEMORY || st == FFI::ERROR_ENCODING
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
ensure
|
|
257
|
+
FFI.yeptris_stream_iter_free(it)
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
|
|
200
261
|
# The Marshal fast path when the loaded libyeptris has it (>= 0.1.11
|
|
201
262
|
# era builds), falling back to the columnar drain and finally the
|
|
202
263
|
# record drain — one code path, the fastest the library offers.
|
|
@@ -289,6 +350,16 @@ module Yeptris
|
|
|
289
350
|
Yeptris::FFI::BUILD_END => END_ENTRY }.freeze
|
|
290
351
|
|
|
291
352
|
def dump(obj, canonical: false, header: false, width: nil)
|
|
353
|
+
# The nil root rides the bare form (psych's dump(nil) == "\n",
|
|
354
|
+
# #290): the engine's r201 quoted-form law ("a document-root
|
|
355
|
+
# empty scalar rides the quoted form" -- the plain form does not
|
|
356
|
+
# re-parse, the roundtrip invariant) renders the built empty
|
|
357
|
+
# scalar as "" -- correct for the engine's generic serializer,
|
|
358
|
+
# wrong for the psych surface. The binding maps an empty stream
|
|
359
|
+
# back to nil on load (load\#docs.empty?\#nil), so the bare form
|
|
360
|
+
# round-trips THROUGH THE BINDING while keeping the engine's
|
|
361
|
+
# invariant untouched.
|
|
362
|
+
return header ? "--- \n" : "\n" if obj.nil? && !canonical
|
|
292
363
|
parts = []
|
|
293
364
|
blob = String.new(encoding: Encoding::BINARY)
|
|
294
365
|
off = [0]
|
data/lib/yeptris.rb
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module Yeptris
|
|
4
4
|
# The gem's version lives in the parent namespace's file — the last
|
|
5
5
|
# internal require (yeptris/version) retired with it.
|
|
6
|
-
VERSION = "0.6.
|
|
6
|
+
VERSION = "0.6.61.1".freeze
|
|
7
7
|
|
|
8
8
|
# Informational notices are OPT-IN (yeptris-ruby#217): consumers
|
|
9
9
|
# embed yeptris inside CLIs that assert clean stderr, and a
|
data/libyeptris.so
CHANGED
|
Binary file
|
|
@@ -29,6 +29,7 @@ set(YEPTRIS_SOURCES
|
|
|
29
29
|
yeptris/dom/mapindex.c
|
|
30
30
|
yeptris/dom/mutate.c
|
|
31
31
|
yeptris/parse.c
|
|
32
|
+
yeptris/parse/stream_iter.c
|
|
32
33
|
yeptris/build.c
|
|
33
34
|
yeptris/events/capture.c
|
|
34
35
|
yeptris/events/push.c
|
|
@@ -40,17 +41,23 @@ set(YEPTRIS_SOURCES
|
|
|
40
41
|
yeptris/resolve/core12.c
|
|
41
42
|
yeptris/resolve/compat11.c
|
|
42
43
|
yeptris/resolve/json12.c
|
|
44
|
+
yeptris/resolve/full12.c
|
|
43
45
|
yeptris/parse/numbers.c
|
|
44
46
|
yeptris/events/values.c
|
|
45
47
|
yeptris/schema.c
|
|
46
48
|
yeptris/validate/regexp.c
|
|
47
49
|
yeptris/validate/validate.c
|
|
48
50
|
yeptris/validate/compile.c
|
|
51
|
+
yeptris/validate/resources.c
|
|
49
52
|
yeptris/validate/jsonschema.c
|
|
53
|
+
yeptris/validate/registry.c
|
|
54
|
+
yeptris/validate/output.c
|
|
55
|
+
yeptris/validate/stream.c
|
|
50
56
|
yeptris/tape.c
|
|
51
57
|
yeptris/plan.c
|
|
52
58
|
|
|
53
59
|
yeptris/marshal.c
|
|
60
|
+
yeptris/marshal/to_json.c
|
|
54
61
|
yeptris/visit/json_visit.c
|
|
55
62
|
yeptris/visit/yaml_visit.c
|
|
56
63
|
yeptris/visit/dom_visit.c
|
|
@@ -24,7 +24,14 @@ extern "C" {
|
|
|
24
24
|
#endif
|
|
25
25
|
|
|
26
26
|
/* Emission options (13B). Versioned by size: initialize with
|
|
27
|
-
* {sizeof(yeptris_emit_options)} so future fields stay optional.
|
|
27
|
+
* {sizeof(yeptris_emit_options)} so future fields stay optional.
|
|
28
|
+
*
|
|
29
|
+
* Deliberately omitted: a flowLevel knob (libyaml's best_width +
|
|
30
|
+
* default_flow_style interplay). The engine's style chooser is
|
|
31
|
+
* recorded-style driven — flow is whatever the document recorded
|
|
32
|
+
* (plus the fixed canonical/JSON forms) — so there is no "switch to
|
|
33
|
+
* flow past level N" decision to expose; revisit only if a binding
|
|
34
|
+
* face actually needs PyYAML's default_flow_style mapping. */
|
|
28
35
|
typedef struct yeptris_emit_options {
|
|
29
36
|
uint32_t size; /* sizeof(yeptris_emit_options) */
|
|
30
37
|
int canonical; /* fixed form: flow collections, quoted strings,
|
|
@@ -32,13 +39,34 @@ typedef struct yeptris_emit_options {
|
|
|
32
39
|
* output re-serializes byte-identically */
|
|
33
40
|
int best_width; /* 0 = library default (80): flow collections
|
|
34
41
|
* wrap after a value when the current line
|
|
35
|
-
* exceeds the width (13B)
|
|
42
|
+
* exceeds the width (13B); with block_fold
|
|
43
|
+
* it is also the fold column for block
|
|
44
|
+
* scalars (#903) */
|
|
36
45
|
int explicit_doc_start; /* nonzero: every document carries the
|
|
37
46
|
* leading --- marker (Psych/libyaml's
|
|
38
47
|
* implicit=false parity). Default 0: a
|
|
39
48
|
* single document is emitted bare. Only
|
|
40
49
|
* read when the caller's struct is large
|
|
41
50
|
* enough (size-versioned). */
|
|
51
|
+
int best_indent; /* (#903) block indentation per level: the
|
|
52
|
+
* content column of a nested block mapping
|
|
53
|
+
* and the "- " item level. Out of range
|
|
54
|
+
* (< 2 or > 9, libyaml's clamp) or 0 = the
|
|
55
|
+
* library default 2. Only read when the
|
|
56
|
+
* caller's struct is large enough. */
|
|
57
|
+
int block_fold; /* (#903) nonzero: plain and single-quoted
|
|
58
|
+
* scalars in block context fold at
|
|
59
|
+
* best_width the way libyaml/Psych/PyYAML
|
|
60
|
+
* do — at an interior single space past the
|
|
61
|
+
* width the break replaces the space and
|
|
62
|
+
* the continuation re-indents to
|
|
63
|
+
* parent_col + best_indent. Default 0:
|
|
64
|
+
* block output is width-invariant (byte-
|
|
65
|
+
* identical with releases before the
|
|
66
|
+
* option). Keys and flow members never
|
|
67
|
+
* fold; canonical/JSON keep their fixed
|
|
68
|
+
* forms. Only read when the caller's
|
|
69
|
+
* struct is large enough. */
|
|
42
70
|
} yeptris_emit_options;
|
|
43
71
|
|
|
44
72
|
/* Options-aware entries; opts == NULL selects the fidelity mode
|
|
@@ -41,6 +41,79 @@ YEPTRIS_API YeptrisDocument yeptris_parse_ex(const char* buf, size_t len,
|
|
|
41
41
|
const YeptrisParseOptions* opts,
|
|
42
42
|
YeptrisStatus* status);
|
|
43
43
|
|
|
44
|
+
/* ---- tolerant per-document stream iteration (#921) ----------------------
|
|
45
|
+
*
|
|
46
|
+
* load_stream parses the whole stream and aborts on the first bad
|
|
47
|
+
* document; this iterator frames documents engine-side (the abort-at-
|
|
48
|
+
* DOCUMENT_END run — scanner-accurate: a quoted scalar spanning a
|
|
49
|
+
* marker-looking line never splits) and reports failures PER DOCUMENT:
|
|
50
|
+
* a parse-class error surfaces as the step's status with NULL *out, the
|
|
51
|
+
* error channel carrying the failed document's own line/col (each run
|
|
52
|
+
* starts at the frame), and the iterator resynced to the next line-
|
|
53
|
+
* start marker — the host keeps calling and keeps the valid documents.
|
|
54
|
+
*
|
|
55
|
+
* yeptris_stream_iter* it = yeptris_stream_iter_new(buf, len, &opts);
|
|
56
|
+
* YeptrisDocument doc;
|
|
57
|
+
* size_t index;
|
|
58
|
+
* YeptrisStatus st;
|
|
59
|
+
* while ((st = yeptris_stream_iter_next(it, &doc, &index)) == YEPTRIS_OK && doc != NULL) {
|
|
60
|
+
* // doc is document `index` of the stream; free it with
|
|
61
|
+
* // yeptris_document_free
|
|
62
|
+
* }
|
|
63
|
+
* // st == OK && doc == NULL: the stream is over; st != OK: document
|
|
64
|
+
* // `index` failed (per-document line/col via
|
|
65
|
+
* // yeptris_stream_iter_status), keep iterating.
|
|
66
|
+
*
|
|
67
|
+
* Memory: the caller owns each *out (yeptris_document_free). The
|
|
68
|
+
* iterator borrows `buf` until free. Each document parses twice (the
|
|
69
|
+
* boundary run + the slice parse) — the tolerance contract is the
|
|
70
|
+
* point; a single-pass upgrade rides the same seam when needed.
|
|
71
|
+
*/
|
|
72
|
+
typedef struct yeptris_stream_iter yeptris_stream_iter;
|
|
73
|
+
|
|
74
|
+
/* The iterator borrows `buf` until free; `opts` is borrowed (may be
|
|
75
|
+
* NULL: the 12_CORE defaults). NULL on arg/alloc failure. */
|
|
76
|
+
YEPTRIS_API yeptris_stream_iter* yeptris_stream_iter_new(const char* buf, size_t len,
|
|
77
|
+
const YeptrisParseOptions* opts);
|
|
78
|
+
|
|
79
|
+
/* The next document: OK + *out = the document (the caller frees it);
|
|
80
|
+
* a parse/DEPTH-class DOCUMENT failure: that status + *out = NULL +
|
|
81
|
+
* the error channel set for THAT document — the iterator has already
|
|
82
|
+
* resynced, keep calling; OK + *out = NULL: the stream is over;
|
|
83
|
+
* MEMORY/ENCODING: stream-fatal, the iterator is done. *index (may be
|
|
84
|
+
* NULL) is the 0-based stream document index this step consumed
|
|
85
|
+
* (failures consume an index too — the yield order is the stream's). */
|
|
86
|
+
YEPTRIS_API YeptrisStatus yeptris_stream_iter_next(yeptris_stream_iter* it, YeptrisDocument* out,
|
|
87
|
+
size_t* index);
|
|
88
|
+
|
|
89
|
+
/* The LAST step's per-document verdict and its 1-based line/col
|
|
90
|
+
* (0/0 when the last step was a success or the stream end). */
|
|
91
|
+
YEPTRIS_API YeptrisStatus yeptris_stream_iter_status(const yeptris_stream_iter* it, uint32_t* line,
|
|
92
|
+
uint32_t* col);
|
|
93
|
+
|
|
94
|
+
/* The last successful step's document SLICE inside the iterator's
|
|
95
|
+
* buffer space (post-gate: BOM/transcode/normalization may have moved
|
|
96
|
+
* the buffer — the offsets are relative to the CURRENT buf the
|
|
97
|
+
* iterator holds, which is the space `yeptris_stream_iter_next`'s
|
|
98
|
+
* documents live in). Hosts that materialize through their own value
|
|
99
|
+
* route (the Python/Rust/TS drains) re-parse exactly these bytes and
|
|
100
|
+
* inherit the engine's framing without a DOM walk: one typing SSOT —
|
|
101
|
+
* the drain — and scanner-accurate frames. ARG on NULL; ARG when the
|
|
102
|
+
* last step was not a successful document. */
|
|
103
|
+
YEPTRIS_API YeptrisStatus yeptris_stream_iter_slice(const yeptris_stream_iter* it, size_t* off,
|
|
104
|
+
size_t* len);
|
|
105
|
+
|
|
106
|
+
/* The iterator's ACTIVE buffer (the caller's bytes, or the post-gate
|
|
107
|
+
* owned copy after a BOM strip / UTF-16-32 transcode / NEL-LS-PS
|
|
108
|
+
* normalization) and its length. `yeptris_stream_iter_slice`'s offsets
|
|
109
|
+
* index THIS buffer — hosts copy their frame bytes out of here
|
|
110
|
+
* (ctypes.string_at / Rust slice / TS Buffer) and re-parse them through
|
|
111
|
+
* their own drain. Borrowed: valid until yeptris_stream_iter_free. */
|
|
112
|
+
YEPTRIS_API YeptrisStatus yeptris_stream_iter_buffer(const yeptris_stream_iter* it,
|
|
113
|
+
const char** buf, size_t* len);
|
|
114
|
+
|
|
115
|
+
YEPTRIS_API void yeptris_stream_iter_free(yeptris_stream_iter* it);
|
|
116
|
+
|
|
44
117
|
#ifdef __cplusplus
|
|
45
118
|
}
|
|
46
119
|
#endif
|
|
@@ -46,6 +46,14 @@ typedef enum {
|
|
|
46
46
|
YEPTRIS_SCHEMA_11_COMPAT, /* libyaml/Psych implicit typing */
|
|
47
47
|
YEPTRIS_SCHEMA_12_JSON, /* spec 10.2: JSON productions; plain
|
|
48
48
|
* scalars matching none are errors (#882) */
|
|
49
|
+
YEPTRIS_SCHEMA_12_FULL, /* the full 1.2 family (#906 slice 3):
|
|
50
|
+
* core typing + RFC3339-era timestamps
|
|
51
|
+
* (spec 2.22's four forms; the yaml.org
|
|
52
|
+
* type repository carried forward) and
|
|
53
|
+
* the merge/value words; !!binary rides
|
|
54
|
+
* as passthrough. A validation family:
|
|
55
|
+
* explicit !!timestamp content must
|
|
56
|
+
* re-resolve through the classifier. */
|
|
49
57
|
} YeptrisSchema;
|
|
50
58
|
|
|
51
59
|
/* Canonical tag URI for a core id ("tag:yaml.org,2002:str"); NULL for
|
|
@@ -7,21 +7,52 @@
|
|
|
7
7
|
* consistency (spec 10.3 resolution) and mapping-key uniqueness
|
|
8
8
|
* (spec 3.2.1.3: keys compare by canonical form — 0o13 and 0xB
|
|
9
9
|
* are the same key). Under YEPTRIS_SCHEMA_12_JSON the spec 10.2
|
|
10
|
-
* family applies:
|
|
11
|
-
* (the
|
|
12
|
-
*
|
|
10
|
+
* family applies: implicit resolution uses ONLY the JSON
|
|
11
|
+
* productions (the core extensions — 0o/0x radix, "+12.3",
|
|
12
|
+
* "True"/"~" casings — stay strings, per example 10.8's Invalid
|
|
13
|
+
* list), mapping keys must be strings (a key resolving to a
|
|
14
|
+
* non-string production is KEY_NOT_STRING; a no-production plain
|
|
15
|
+
* key IS a string, per example 10.8), explicit non-JSON tags are
|
|
16
|
+
* rejected; core checks still run. Under YEPTRIS_SCHEMA_12_FULL
|
|
17
|
+
* the spec 10.4 "other schema" family applies — the core schema
|
|
18
|
+
* "extended with additional tag resolution rules": untagged plains
|
|
19
|
+
* also resolve RFC3339-era timestamps (spec example 2.22's
|
|
20
|
+
* canonical/iso8601/spaced/date forms, classified by PyYAML's
|
|
21
|
+
* timestamp regex as the practice oracle) and the merge/value
|
|
22
|
+
* words, while explicit !!timestamp content must re-resolve
|
|
23
|
+
* through the same classifier (TAG_MISMATCH otherwise). !!binary
|
|
24
|
+
* rides as passthrough (base64 shaping is a construction concern);
|
|
25
|
+
* core checks still run. The 1.1 numeric quirks (underscores,
|
|
26
|
+
* sexagesimal, leading-0 octal, y/n booleans) stay with
|
|
27
|
+
* 11_COMPAT — full is spec-refereed, not psych-refereed.
|
|
13
28
|
*
|
|
14
29
|
* 2. JSON SCHEMA validation (`yeptris_json_schema_validate`): the
|
|
15
30
|
* schema arrives as bytes (parsed with the same engine), the
|
|
16
31
|
* target against it — draft 2020-12 keyword subset (see the entry
|
|
17
32
|
* comment). Unknown keywords are ignored, per 2020-12.
|
|
18
33
|
*
|
|
34
|
+
* The COMPILED-schema economy (`yeptris_schema_*`) retains one parsed
|
|
35
|
+
* schema for many instance streams; the TAG-DRIVEN registry
|
|
36
|
+
* (`yeptris_schema_registry_*`, #906 slice 4) binds compiled schemas
|
|
37
|
+
* to user tags over the family walk (`yeptris_validate_ex`). The
|
|
38
|
+
* report converts to the published JSON-Schema output shape
|
|
39
|
+
* (`yeptris_validate_report_write`, #906 slice 5).
|
|
40
|
+
*
|
|
19
41
|
* Every diagnostic carries a JSON-pointer instance path ("/a/b/0" —
|
|
20
42
|
* ~0/~1 escaped), a YEPTRIS_DIAG_* code, a bounded expected/got
|
|
21
43
|
* detail, and the offending node's 1-based line/column (0 = unknown:
|
|
22
44
|
* scalars whose bytes the DOM owns in its arena have no input
|
|
23
45
|
* position; the path still identifies them exactly).
|
|
24
46
|
*
|
|
47
|
+
* STREAMS (#885 item 4): a validated stream is addressed as an array
|
|
48
|
+
* of documents. When the input holds MORE THAN ONE document, every
|
|
49
|
+
* diagnostic path is prefixed with its document's index segment —
|
|
50
|
+
* "/1/a/b" is a/b of document 1 (0-based), so diagnostics name their
|
|
51
|
+
* document even when the miss is unpositioned (an empty document's
|
|
52
|
+
* Error-row scalar has no line/col). Line/col/offset stay
|
|
53
|
+
* input-absolute. Streams with a single document keep the bare
|
|
54
|
+
* instance pointers — existing consumers' paths are unchanged.
|
|
55
|
+
*
|
|
25
56
|
* Results are WHOLE REPORTS: one call, no per-diagnostic callback —
|
|
26
57
|
* the caller drains the flat array and frees the report once.
|
|
27
58
|
*/
|
|
@@ -84,6 +115,9 @@ typedef enum {
|
|
|
84
115
|
YEPTRIS_DIAG_MIN_CONTAINS = 31,
|
|
85
116
|
YEPTRIS_DIAG_MAX_CONTAINS = 32,
|
|
86
117
|
YEPTRIS_DIAG_DEPENDENT_REQUIRED = 33,
|
|
118
|
+
/* the 2020-12 unevaluated* annotation model (the sota sweep) */
|
|
119
|
+
YEPTRIS_DIAG_UNEVALUATED_PROPERTY = 34, /* no sibling/applicator evaluated it */
|
|
120
|
+
YEPTRIS_DIAG_UNEVALUATED_ITEM = 35,
|
|
87
121
|
} YeptrisDiagCode;
|
|
88
122
|
|
|
89
123
|
/* Bounded diagnostic text; always NUL-terminated (over-long paths and
|
|
@@ -118,7 +152,14 @@ YEPTRIS_API void yeptris_validate_report_free(yeptris_validate_report* report);
|
|
|
118
152
|
|
|
119
153
|
/* Parses `buf` (the same front door as yeptris_parse_ex: encodings,
|
|
120
154
|
* BOM, NEL normalization) and validates every document of the stream
|
|
121
|
-
* against `schema
|
|
155
|
+
* against `schema` — the strict lanes: explicit-tag consistency,
|
|
156
|
+
* canonical-form key uniqueness, (12_JSON) string keys over the JSON
|
|
157
|
+
* productions, and (12_FULL) timestamp content against the full
|
|
158
|
+
* family's classifier. Paths are root-relative per document; a
|
|
159
|
+
* multi-document stream prefixes them with the document index (see
|
|
160
|
+
* STREAMS above), so diagnostics name their document. The parse's own
|
|
161
|
+
* guards compose: a document past the engine's depth cap fails the
|
|
162
|
+
* parse (YEPTRIS_ERROR_DEPTH) before any validation runs.
|
|
122
163
|
*
|
|
123
164
|
* Status: YEPTRIS_OK (valid; *out is a report — possibly with zero
|
|
124
165
|
* diagnostics for an empty stream); YEPTRIS_ERROR_SCHEMA (invalid:
|
|
@@ -135,22 +176,67 @@ YEPTRIS_API YeptrisStatus yeptris_validate(const char* buf, size_t len, YeptrisS
|
|
|
135
176
|
YEPTRIS_API YeptrisStatus yeptris_validate_document(YeptrisDocument doc, YeptrisSchema schema,
|
|
136
177
|
yeptris_validate_report** out);
|
|
137
178
|
|
|
138
|
-
/*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
179
|
+
/* The EVENT-ROUTE twin of yeptris_validate (#902): the same parse
|
|
180
|
+
* (front-end, depth/encoding guards, statuses — the DOM route's
|
|
181
|
+
* sink-entry seam) feeding a streaming validator state machine. The
|
|
182
|
+
* family lanes ride the event walk itself; NO node tree is ever
|
|
183
|
+
* built. Everything observable is the DOM route's, by construction
|
|
184
|
+
* and by the differential gate:
|
|
185
|
+
*
|
|
186
|
+
* - diagnostics: the same code rail (0-35 after the sweep), the same report shape and
|
|
187
|
+
* cap, the same JSON-pointer paths and the stream face's
|
|
188
|
+
* per-document attribution — emitted in the DOM walk's order (a
|
|
189
|
+
* mapping's own tag check, its duplicate-key misses, then its
|
|
190
|
+
* pairs' content);
|
|
191
|
+
* - positions: the DOM route's region law — a diagnostic sits at the
|
|
192
|
+
* node's input-borrowed value bytes (0/0 when the engine pooled
|
|
193
|
+
* them), so line/col/offset match bit for bit;
|
|
194
|
+
* - statuses: OK / SCHEMA / PARSE / DEPTH / ENCODING / MEMORY / ARG,
|
|
195
|
+
* byte-identical argument gates (NULL with length, 11_COMPAT).
|
|
196
|
+
* All three families (12_CORE / 12_JSON / 12_FULL) ride both
|
|
197
|
+
* routes with identical verdicts.
|
|
198
|
+
*
|
|
199
|
+
* The compiled JSON Schema lane (yeptris_schema_validate) keeps the
|
|
200
|
+
* DOM route: its evaluator needs random access (uniqueItems, contains,
|
|
201
|
+
* required); a streaming twin waits for #901's annotation-model seam.
|
|
202
|
+
*
|
|
203
|
+
* Memory: the caller owns *out; free it with
|
|
204
|
+
* yeptris_validate_report_free. */
|
|
205
|
+
YEPTRIS_API YeptrisStatus yeptris_validate_stream(const char* buf, size_t len, YeptrisSchema schema,
|
|
206
|
+
yeptris_validate_report** out);
|
|
207
|
+
|
|
208
|
+
/* JSON Schema draft 2020-12 subset (#882 slice 2; #885 item 2; the
|
|
209
|
+
* 2020-12 sota sweep). `schema` is parsed with the same engine (JSON
|
|
210
|
+
* is YAML flow); document 0 of the stream is the schema. Keyword
|
|
211
|
+
* subset: type, enum, const, pattern, minimum, maximum,
|
|
212
|
+
* exclusiveMinimum, exclusiveMaximum (numeric, 2020-12 form),
|
|
213
|
+
* multipleOf (libm-free quotient test),
|
|
214
|
+
* minLength/maxLength (code points), minItems/maxItems, uniqueItems,
|
|
215
|
+
* contains (+ the minContains/maxContains qualifiers), items
|
|
216
|
+
* (+ prefixItems; the draft-07 array form rides as prefixItems),
|
|
217
|
+
* properties, required, patternProperties, propertyNames,
|
|
218
|
+
* minProperties/maxProperties, additionalProperties (bool or schema;
|
|
219
|
+
* excludes patternProperties matches), dependentRequired,
|
|
220
|
+
* dependentSchemas, if/then/else, allOf/anyOf/oneOf/not,
|
|
221
|
+
* unevaluatedProperties/unevaluatedItems (the 2020-12 annotation
|
|
222
|
+
* model: evaluations collect upward through the in-place applicators,
|
|
223
|
+
* a failed branch annotates nothing, and nothing crosses an
|
|
224
|
+
* instance-location boundary), $ref, $dynamicRef, boolean schemas.
|
|
225
|
+
* REFERENCES: $id base-URI composition (RFC 3986 path merge),
|
|
226
|
+
* $anchor/$dynamicAnchor plain-name fragments scoped to their nearest
|
|
227
|
+
* $id resource, JSON Pointer fragments with the percent layer
|
|
228
|
+
* (%25 -> '%', then ~0/~1), and $dynamicRef's runtime dynamic scope
|
|
229
|
+
* (the OUTERMOST schema resource in scope defining the anchor). No
|
|
230
|
+
* network: a reference resolves only against the schema's own
|
|
231
|
+
* identifier space — an external target (the metaschema, an HTTP
|
|
232
|
+
* fixture) is a DIAG_REF, never a fetch. Boolean schemas
|
|
233
|
+
* (`true`/`false`) apply. Unknown keywords and known keywords with
|
|
234
|
+
* unreadable values are ignored (2020-12). Instance types ride the
|
|
235
|
+
* core-schema resolution (the YAML->JSON data model): "y" is boolean,
|
|
236
|
+
* 1.0 is integer. The IETF WG's next-edition draft
|
|
237
|
+
* (draft-ietf-jsonschema-json-schema-00) carries these same keyword
|
|
238
|
+
* semantics — no evaluator delta; the diff record is
|
|
239
|
+
* docs/schema/ietf-wg-draft-delta.md.
|
|
154
240
|
*
|
|
155
241
|
* Status: as yeptris_validate, plus YEPTRIS_ERROR_ARG when the schema
|
|
156
242
|
* bytes hold no document, and YEPTRIS_ERROR_PARSE when they do not
|
|
@@ -175,7 +261,9 @@ YEPTRIS_API YeptrisStatus yeptris_json_schema_validate(const char* schema, size_
|
|
|
175
261
|
*
|
|
176
262
|
* yeptris_schema_validate keeps yeptris_json_schema_validate's exact
|
|
177
263
|
* status/report contract; diagnostics enumerate every miss across
|
|
178
|
-
* every document of the instance stream
|
|
264
|
+
* every document of the instance stream — the stream face's document
|
|
265
|
+
* attribution applies (see STREAMS above): a multi-document stream's
|
|
266
|
+
* paths carry the document index. yeptris_schema_free releases
|
|
179
267
|
* the handle and everything it owns in ONE call (no refcounting) —
|
|
180
268
|
* afterwards the handle is DEAD: passing it anywhere is undefined,
|
|
181
269
|
* exactly like a freed document. NULL is accepted (a no-op).
|
|
@@ -193,6 +281,119 @@ YEPTRIS_API YeptrisStatus yeptris_schema_validate(yeptris_schema* s, const char*
|
|
|
193
281
|
|
|
194
282
|
YEPTRIS_API void yeptris_schema_free(yeptris_schema* s);
|
|
195
283
|
|
|
284
|
+
/* ---- the TAG-DRIVEN SCHEMA registry (#906 slice 4) -----------------------
|
|
285
|
+
*
|
|
286
|
+
* The dialect table's reserved slot: a compiled schema binds to a user
|
|
287
|
+
* tag, so a document node carrying `!shape` (its EXPLICIT tag, exactly
|
|
288
|
+
* the resolved bytes the DOM exposes — `!shape`, `!<tag:...>`, or a
|
|
289
|
+
* `%TAG`-resolved URI; `!!x` arrives as `tag:yaml.org,2002:x`) has its
|
|
290
|
+
* SUBTREE validated against the bound schema. Registration is the only
|
|
291
|
+
* extension point (OCP): the family walk reads the registry, it never
|
|
292
|
+
* grows schema branches.
|
|
293
|
+
*
|
|
294
|
+
* Matching is byte-exact on the tag's resolved form and fires only on
|
|
295
|
+
* an explicit tag — implicit (plain) typing never triggers a binding.
|
|
296
|
+
* An unregistered tag passes untouched: no diagnostic, no lane. The
|
|
297
|
+
* hook rides the DOM family walk (yeptris_validate_ex /
|
|
298
|
+
* yeptris_validate_document_ex): roots, sequence items and mapping
|
|
299
|
+
* VALUES (a tagged mapping KEY is not registry-validated — its
|
|
300
|
+
* instance path is undefined in the walk's model). Diagnostics from a
|
|
301
|
+
* bound subtree land at the tag site: the tag node's own path + the
|
|
302
|
+
* schema walk's instance pointers, with the offending node's
|
|
303
|
+
* line/col/offset; the report cap and codes are the shared rail.
|
|
304
|
+
* Bindings COMPOSE: a node inside a bound subtree that carries its own
|
|
305
|
+
* registered tag is validated by both schemas.
|
|
306
|
+
*
|
|
307
|
+
* THE REGISTRY LAW (the document-ownership law, no refcounting): the
|
|
308
|
+
* registry BORROWS the compiled schemas it binds — it owns nothing
|
|
309
|
+
* they own. A bound schema must OUTLIVE the registry: free the
|
|
310
|
+
* registry first (yeptris_schema_registry_free), then the schemas.
|
|
311
|
+
* Freeing a bound schema while its registry lives leaves the registry
|
|
312
|
+
* dead (a later lookup is undefined), exactly like a freed document.
|
|
313
|
+
* NULL is accepted everywhere a handle is (a NULL registry is simply
|
|
314
|
+
* no bindings; yeptris_schema_registry_free(NULL) is a no-op).
|
|
315
|
+
*
|
|
316
|
+
* Thread law: one registry per thread, like documents and schemas —
|
|
317
|
+
* it is mutable under register and read-only during validation;
|
|
318
|
+
* read-only sharing across threads (no register in flight) is safe. */
|
|
319
|
+
typedef struct yeptris_schema_registry yeptris_schema_registry;
|
|
320
|
+
|
|
321
|
+
/* A fresh empty registry; NULL on allocation failure. */
|
|
322
|
+
YEPTRIS_API yeptris_schema_registry* yeptris_schema_registry_new(void);
|
|
323
|
+
|
|
324
|
+
/* Binds `tag` (copied — nothing borrows the caller's bytes beyond the
|
|
325
|
+
* call) to the compiled `schema` (borrowed — see THE REGISTRY LAW).
|
|
326
|
+
* Status: YEPTRIS_OK; YEPTRIS_ERROR_ARG (NULL handle, an empty tag,
|
|
327
|
+
* or a NULL schema); YEPTRIS_ERROR_MEMORY. Re-registering a tag
|
|
328
|
+
* REPLACES the binding (last registration wins). */
|
|
329
|
+
YEPTRIS_API YeptrisStatus yeptris_schema_registry_register(yeptris_schema_registry* reg,
|
|
330
|
+
const char* tag, size_t tag_len,
|
|
331
|
+
const yeptris_schema* schema);
|
|
332
|
+
|
|
333
|
+
/* The schema bound to `tag` (exact bytes), or NULL. Memory: borrowed
|
|
334
|
+
* from the registry — valid until a register replaces the tag or the
|
|
335
|
+
* registry is freed. */
|
|
336
|
+
YEPTRIS_API const yeptris_schema* yeptris_schema_registry_lookup(const yeptris_schema_registry* reg,
|
|
337
|
+
const char* tag, size_t tag_len);
|
|
338
|
+
|
|
339
|
+
YEPTRIS_API void yeptris_schema_registry_free(yeptris_schema_registry* reg);
|
|
340
|
+
|
|
341
|
+
/* Validation options (size-versioned like yeptris_emit_options:
|
|
342
|
+
* initialize with {sizeof(yeptris_validate_options)} so future fields
|
|
343
|
+
* stay optional; NULL selects the defaults). */
|
|
344
|
+
typedef struct yeptris_validate_options {
|
|
345
|
+
uint32_t size; /* sizeof(yeptris_validate_options) */
|
|
346
|
+
/* The tag-driven registry (#906 slice 4): NULL = none. Only read
|
|
347
|
+
* when the caller's struct is large enough (size-versioned). The
|
|
348
|
+
* registry is borrowed for the call; see THE REGISTRY LAW above. */
|
|
349
|
+
const yeptris_schema_registry* registry;
|
|
350
|
+
} yeptris_validate_options;
|
|
351
|
+
|
|
352
|
+
/* yeptris_validate / yeptris_validate_document with options: the
|
|
353
|
+
* family walk plus, when a registry is attached, the tag-driven
|
|
354
|
+
* schema applications described above. Everything else (statuses,
|
|
355
|
+
* report shape, paths, positions) is the flat face's, unchanged. */
|
|
356
|
+
YEPTRIS_API YeptrisStatus yeptris_validate_ex(const char* buf, size_t len, YeptrisSchema schema,
|
|
357
|
+
const yeptris_validate_options* opts,
|
|
358
|
+
yeptris_validate_report** out);
|
|
359
|
+
|
|
360
|
+
YEPTRIS_API YeptrisStatus yeptris_validate_document_ex(YeptrisDocument doc, YeptrisSchema schema,
|
|
361
|
+
const yeptris_validate_options* opts,
|
|
362
|
+
yeptris_validate_report** out);
|
|
363
|
+
|
|
364
|
+
/* ---- the structured OUTPUT face (#906 slice 5) ---------------------------
|
|
365
|
+
*
|
|
366
|
+
* The report as the json-schema.org RECOMMENDED OUTPUT shape (core
|
|
367
|
+
* spec section 12; the meta-schema at
|
|
368
|
+
* https://json-schema.org/draft/2020-12/output/schema): one root
|
|
369
|
+
* output unit — {"valid", "keywordLocation", "instanceLocation"} and,
|
|
370
|
+
* when the report carries diagnostics, "errors" — with one child unit
|
|
371
|
+
* per diagnostic {valid, keywordLocation, instanceLocation, error}.
|
|
372
|
+
* This is the published BASIC form: the report is flat by the
|
|
373
|
+
* enumerated-misses law, so the schema-structured DETAILED/VERBOSE
|
|
374
|
+
* hierarchies (which need per-miss schema-side keyword paths the flat
|
|
375
|
+
* report does not carry) are not derivable from it. keywordLocation
|
|
376
|
+
* is derived from the diagnostic code — the keyword's name segment
|
|
377
|
+
* ("/type", "/required", ...; the family codes and the bookkeeping
|
|
378
|
+
* codes sit at the root pointer ""); it is a JSON Pointer, but NOT
|
|
379
|
+
* necessarily resolvable in the schema (the flat report carries no
|
|
380
|
+
* schema path). absoluteKeywordLocation is never emitted, and $ref
|
|
381
|
+
* sites report the root pointer, so the output always satisfies the
|
|
382
|
+
* published meta-schema. Strings are JSON-escaped (RFC 8259); the
|
|
383
|
+
* bytes are UTF-8; the transform is pure and deterministic — the same
|
|
384
|
+
* report always produces the same bytes.
|
|
385
|
+
*
|
|
386
|
+
* buf == NULL: returns the exact byte count needed, writes nothing.
|
|
387
|
+
* Otherwise writes at most cap bytes (NUL-terminated when cap
|
|
388
|
+
* allows) and returns the count written; when cap is too small
|
|
389
|
+
* nothing is written and the needed size is returned. Returns 0 on a
|
|
390
|
+
* NULL report (use the flat face for those — the transform never
|
|
391
|
+
* invents a verdict).
|
|
392
|
+
*
|
|
393
|
+
* Memory: writes into the caller's buffer; borrows nothing. */
|
|
394
|
+
YEPTRIS_API size_t yeptris_validate_report_write(const yeptris_validate_report* report, char* buf,
|
|
395
|
+
size_t cap);
|
|
396
|
+
|
|
196
397
|
#ifdef __cplusplus
|
|
197
398
|
}
|
|
198
399
|
#endif
|