teptris 0.3.4.1-arm-linux → 0.3.6.2-arm-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/teptris_ext/engine/README.md +1 -1
- data/ext/teptris_ext/engine/src/include/teptris/teptris.h +17 -0
- data/ext/teptris_ext/engine/src/include/teptris/version.h +1 -1
- data/ext/teptris_ext/engine/src/teptris/emit/emit_shared.h +419 -0
- data/ext/teptris_ext/engine/src/teptris/emit/emitter.c +1 -404
- data/ext/teptris_ext/engine/src/teptris/emit/writer.c +575 -0
- data/ext/teptris_ext/materialize.c +125 -21
- data/lib/teptris/3.3/teptris_ext.so +0 -0
- data/lib/teptris/3.4/teptris_ext.so +0 -0
- data/lib/teptris/4.0/teptris_ext.so +0 -0
- data/lib/teptris/toml.rb +18 -0
- data/lib/teptris/version.rb +1 -1
- data/sig/teptris.rbs +6 -0
- metadata +4 -2
|
@@ -0,0 +1,575 @@
|
|
|
1
|
+
/* Streaming TOML writer: an op-stream in, TOML text out.
|
|
2
|
+
*
|
|
3
|
+
* Fuses the builder's DOM construction and the emitter's tree walk
|
|
4
|
+
* into one pass: bindings that walk host objects (Python dicts, JS
|
|
5
|
+
* objects) encode an op-stream instead of calling builder_put_* per
|
|
6
|
+
* value and re-emitting from the DOM. Sections emit as
|
|
7
|
+
* [dotted.headers] / [[aot.headers]] with full paths; arrays and
|
|
8
|
+
* inline tables render inline.
|
|
9
|
+
*
|
|
10
|
+
* Op grammar (little-endian, mirroring the flatten payload styles):
|
|
11
|
+
* 0x00 END-OF-CHUNK
|
|
12
|
+
* 0x01 KEY u8 klen <bytes> (klen 0 clears the pending key)
|
|
13
|
+
* 0x02 STRING u32 len <bytes>
|
|
14
|
+
* 0x03 INT i64
|
|
15
|
+
* 0x04 FLOAT f64
|
|
16
|
+
* 0x05 FALSE
|
|
17
|
+
* 0x06 TRUE
|
|
18
|
+
* 0x07 DATETIME u8 kind(4..7) <25 B, same layout as flatten>
|
|
19
|
+
* 0x08 BEGIN-TABLE section header ([k] / [a.b])
|
|
20
|
+
* 0x09 BEGIN-ARRAY inline array as a value
|
|
21
|
+
* 0x0A BEGIN-AOT array-of-tables ([[k]], elements via BEGIN-TABLE)
|
|
22
|
+
* 0x0B BEGIN-INLINE-TABLE {inline table: array element or keyed value}
|
|
23
|
+
* 0x0C CLOSE
|
|
24
|
+
* 0x0D EMPTY-TABLE (value {})
|
|
25
|
+
* 0x0E EMPTY-ARRAY (value [])
|
|
26
|
+
*
|
|
27
|
+
* Caller contract: within each table, feed every scalar BEFORE any
|
|
28
|
+
* nested table/AOT - TOML forbids keys after a sub-table header, and
|
|
29
|
+
* the writer enforces that with ERR_STATE instead of emitting invalid
|
|
30
|
+
* TOML. */
|
|
31
|
+
#include <stdlib.h>
|
|
32
|
+
#include <string.h>
|
|
33
|
+
|
|
34
|
+
#include "emit_shared.h"
|
|
35
|
+
#include "teptris/teptris.h"
|
|
36
|
+
|
|
37
|
+
enum {
|
|
38
|
+
W_END = 0x00,
|
|
39
|
+
W_KEY = 0x01,
|
|
40
|
+
W_STRING = 0x02,
|
|
41
|
+
W_INT = 0x03,
|
|
42
|
+
W_FLOAT = 0x04,
|
|
43
|
+
W_FALSE = 0x05,
|
|
44
|
+
W_TRUE = 0x06,
|
|
45
|
+
W_DATETIME = 0x07,
|
|
46
|
+
W_BEGIN_TABLE = 0x08,
|
|
47
|
+
W_BEGIN_ARRAY = 0x09,
|
|
48
|
+
W_BEGIN_AOT = 0x0A,
|
|
49
|
+
W_BEGIN_INLINE_TABLE = 0x0B,
|
|
50
|
+
W_CLOSE = 0x0C,
|
|
51
|
+
W_EMPTY_TABLE = 0x0D,
|
|
52
|
+
W_EMPTY_ARRAY = 0x0E
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
enum {
|
|
56
|
+
F_TABLE, /* section table (root or [dotted]) or an AOT element */
|
|
57
|
+
F_ARRAY, /* inline array */
|
|
58
|
+
F_AOT, /* the AOT itself: contributes its key to element paths */
|
|
59
|
+
F_ITAB /* inline table */
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
typedef struct wframe {
|
|
63
|
+
struct wframe *down;
|
|
64
|
+
int kind;
|
|
65
|
+
char *key; /* TBL section component; AOT key; else NULL */
|
|
66
|
+
size_t key_len;
|
|
67
|
+
int first; /* inline separator state */
|
|
68
|
+
int saw_subtable; /* TBL: a nested section was opened under us */
|
|
69
|
+
} wframe;
|
|
70
|
+
|
|
71
|
+
struct teptris_writer {
|
|
72
|
+
ebuf out;
|
|
73
|
+
char *key; /* pending key */
|
|
74
|
+
size_t key_len;
|
|
75
|
+
wframe *top;
|
|
76
|
+
int finished;
|
|
77
|
+
teptris_status st;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
static wframe *w_push(teptris_writer *w, int kind, const char *k,
|
|
81
|
+
size_t klen);
|
|
82
|
+
|
|
83
|
+
teptris_writer *teptris_writer_new(void)
|
|
84
|
+
{
|
|
85
|
+
teptris_writer *w = calloc(1, sizeof(*w));
|
|
86
|
+
if (w != NULL) {
|
|
87
|
+
/* implicit root table: tracks root-level value/sub-table
|
|
88
|
+
* ordering; never closed by CLOSE */
|
|
89
|
+
w_push(w, F_TABLE, NULL, 0);
|
|
90
|
+
w->st = TEPTRIS_OK;
|
|
91
|
+
}
|
|
92
|
+
return w;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
void teptris_writer_free(teptris_writer *w)
|
|
96
|
+
{
|
|
97
|
+
if (w == NULL) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
while (w->top != NULL) {
|
|
101
|
+
wframe *f = w->top;
|
|
102
|
+
w->top = f->down;
|
|
103
|
+
free(f->key);
|
|
104
|
+
free(f);
|
|
105
|
+
}
|
|
106
|
+
free(w->key);
|
|
107
|
+
free(w->out.p);
|
|
108
|
+
free(w);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
static void w_take_key(teptris_writer *w, const char *k, size_t klen)
|
|
112
|
+
{
|
|
113
|
+
free(w->key);
|
|
114
|
+
w->key = NULL;
|
|
115
|
+
w->key_len = 0;
|
|
116
|
+
if (klen > 0) {
|
|
117
|
+
w->key = malloc(klen);
|
|
118
|
+
if (w->key == NULL) {
|
|
119
|
+
w->st = TEPTRIS_ERR_ALLOC;
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
memcpy(w->key, k, klen);
|
|
123
|
+
w->key_len = klen;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
static void w_clear_key(teptris_writer *w)
|
|
128
|
+
{
|
|
129
|
+
free(w->key);
|
|
130
|
+
w->key = NULL;
|
|
131
|
+
w->key_len = 0;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/* push with an OWNED key (transfers the malloc from the caller) */
|
|
135
|
+
static wframe *w_push_steal(teptris_writer *w, int kind, char *k,
|
|
136
|
+
size_t klen)
|
|
137
|
+
{
|
|
138
|
+
wframe *f = calloc(1, sizeof(*f));
|
|
139
|
+
if (f == NULL) {
|
|
140
|
+
free(k);
|
|
141
|
+
w->st = TEPTRIS_ERR_ALLOC;
|
|
142
|
+
return NULL;
|
|
143
|
+
}
|
|
144
|
+
f->down = w->top;
|
|
145
|
+
f->kind = kind;
|
|
146
|
+
f->key = k;
|
|
147
|
+
f->key_len = klen;
|
|
148
|
+
w->top = f;
|
|
149
|
+
return f;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
static wframe *w_push(teptris_writer *w, int kind, const char *k,
|
|
153
|
+
size_t klen)
|
|
154
|
+
{
|
|
155
|
+
wframe *f = calloc(1, sizeof(*f));
|
|
156
|
+
if (f == NULL) {
|
|
157
|
+
w->st = TEPTRIS_ERR_ALLOC;
|
|
158
|
+
return NULL;
|
|
159
|
+
}
|
|
160
|
+
f->down = w->top;
|
|
161
|
+
f->kind = kind;
|
|
162
|
+
if (klen > 0) {
|
|
163
|
+
f->key = malloc(klen);
|
|
164
|
+
if (f->key == NULL) {
|
|
165
|
+
free(f);
|
|
166
|
+
w->st = TEPTRIS_ERR_ALLOC;
|
|
167
|
+
return NULL;
|
|
168
|
+
}
|
|
169
|
+
memcpy(f->key, k, klen);
|
|
170
|
+
f->key_len = klen;
|
|
171
|
+
}
|
|
172
|
+
w->top = f;
|
|
173
|
+
return f;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/* dotted path of all keyed frames down the stack, outermost first;
|
|
177
|
+
* with_tail appends the pending key as the last component */
|
|
178
|
+
static void w_path(teptris_writer *w, int with_tail)
|
|
179
|
+
{
|
|
180
|
+
wframe *stack[600];
|
|
181
|
+
int n = 0;
|
|
182
|
+
for (wframe *f = w->top; f != NULL && n < 600; f = f->down) {
|
|
183
|
+
stack[n++] = f;
|
|
184
|
+
}
|
|
185
|
+
int first = 1;
|
|
186
|
+
for (int i = n - 1; i >= 0; i--) {
|
|
187
|
+
wframe *f = stack[i];
|
|
188
|
+
if ((f->kind == F_TABLE || f->kind == F_AOT) && f->key != NULL) {
|
|
189
|
+
if (!first) {
|
|
190
|
+
eb_c(&w->out, '.');
|
|
191
|
+
}
|
|
192
|
+
emit_key(&w->out, (teptris_view){f->key, f->key_len});
|
|
193
|
+
first = 0;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (with_tail && w->key != NULL) {
|
|
197
|
+
if (!first) {
|
|
198
|
+
eb_c(&w->out, '.');
|
|
199
|
+
}
|
|
200
|
+
emit_key(&w->out, (teptris_view){w->key, w->key_len});
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/* section headers follow the previous line directly (emitter style) */
|
|
205
|
+
static void w_sep(teptris_writer *w)
|
|
206
|
+
{
|
|
207
|
+
(void)w;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
static void w_sep_val(teptris_writer *w, wframe *f)
|
|
211
|
+
{
|
|
212
|
+
if (f->first) {
|
|
213
|
+
eb_put(&w->out, ", ", 2);
|
|
214
|
+
}
|
|
215
|
+
f->first = 1;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/* emit "key = " in a section/inline-table context; arrays take bare
|
|
219
|
+
* values with separators */
|
|
220
|
+
static void w_keyed_prefix(teptris_writer *w)
|
|
221
|
+
{
|
|
222
|
+
wframe *f = w->top;
|
|
223
|
+
if (f != NULL && f->kind == F_ARRAY) {
|
|
224
|
+
w_sep_val(w, f);
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
if (w->key == NULL) {
|
|
228
|
+
w->st = TEPTRIS_ERR_ARG;
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
if (f != NULL && f->saw_subtable) {
|
|
232
|
+
w->st = TEPTRIS_ERR_STATE; /* value after a nested table header */
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
emit_key(&w->out, (teptris_view){w->key, w->key_len});
|
|
236
|
+
eb_put(&w->out, " = ", 3);
|
|
237
|
+
w_clear_key(w);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
static void w_end_line(teptris_writer *w)
|
|
241
|
+
{
|
|
242
|
+
wframe *f = w->top;
|
|
243
|
+
if (f == NULL || f->kind == F_TABLE) {
|
|
244
|
+
eb_c(&w->out, '\n');
|
|
245
|
+
}
|
|
246
|
+
/* inside inline arrays/tables the separator or close comes next */
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
teptris_status teptris_writer_feed(teptris_writer *w, const uint8_t *ops,
|
|
250
|
+
size_t len)
|
|
251
|
+
{
|
|
252
|
+
if (w == NULL || (ops == NULL && len > 0)) {
|
|
253
|
+
return TEPTRIS_ERR_ARG;
|
|
254
|
+
}
|
|
255
|
+
if (w->finished) {
|
|
256
|
+
return TEPTRIS_ERR_STATE;
|
|
257
|
+
}
|
|
258
|
+
size_t i = 0;
|
|
259
|
+
while (i < len && w->st == TEPTRIS_OK) {
|
|
260
|
+
uint8_t op = ops[i++];
|
|
261
|
+
switch (op) {
|
|
262
|
+
case W_END:
|
|
263
|
+
return w->st;
|
|
264
|
+
case W_KEY: {
|
|
265
|
+
if (i >= len) {
|
|
266
|
+
w->st = TEPTRIS_ERR_ARG;
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
269
|
+
uint8_t klen = ops[i++];
|
|
270
|
+
if (i + klen > len) {
|
|
271
|
+
w->st = TEPTRIS_ERR_ARG;
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
w_take_key(w, (const char *)ops + i, klen);
|
|
275
|
+
i += klen;
|
|
276
|
+
break;
|
|
277
|
+
}
|
|
278
|
+
case W_STRING: {
|
|
279
|
+
if (i + 4 > len) {
|
|
280
|
+
w->st = TEPTRIS_ERR_ARG;
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
283
|
+
uint32_t vlen = (uint32_t)ops[i] |
|
|
284
|
+
((uint32_t)ops[i + 1] << 8) |
|
|
285
|
+
((uint32_t)ops[i + 2] << 16) |
|
|
286
|
+
((uint32_t)ops[i + 3] << 24);
|
|
287
|
+
i += 4;
|
|
288
|
+
if (i + vlen > len) {
|
|
289
|
+
w->st = TEPTRIS_ERR_ARG;
|
|
290
|
+
break;
|
|
291
|
+
}
|
|
292
|
+
w_keyed_prefix(w);
|
|
293
|
+
if (w->st != TEPTRIS_OK) {
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
emit_string_value(&w->out,
|
|
297
|
+
(teptris_view){(const char *)ops + i, vlen});
|
|
298
|
+
i += vlen;
|
|
299
|
+
w_end_line(w);
|
|
300
|
+
break;
|
|
301
|
+
}
|
|
302
|
+
case W_INT: {
|
|
303
|
+
if (i + 8 > len) {
|
|
304
|
+
w->st = TEPTRIS_ERR_ARG;
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
307
|
+
uint64_t u = 0;
|
|
308
|
+
for (int b = 0; b < 8; b++) {
|
|
309
|
+
u |= (uint64_t)ops[i + b] << (8 * b); /* little-endian */
|
|
310
|
+
}
|
|
311
|
+
int64_t v;
|
|
312
|
+
memcpy(&v, &u, 8);
|
|
313
|
+
i += 8;
|
|
314
|
+
w_keyed_prefix(w);
|
|
315
|
+
if (w->st != TEPTRIS_OK) {
|
|
316
|
+
break;
|
|
317
|
+
}
|
|
318
|
+
emit_i64(&w->out, v);
|
|
319
|
+
w_end_line(w);
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
case W_FLOAT: {
|
|
323
|
+
if (i + 8 > len) {
|
|
324
|
+
w->st = TEPTRIS_ERR_ARG;
|
|
325
|
+
break;
|
|
326
|
+
}
|
|
327
|
+
uint64_t u = 0;
|
|
328
|
+
for (int b = 0; b < 8; b++) {
|
|
329
|
+
u |= (uint64_t)ops[i + b] << (8 * b); /* little-endian */
|
|
330
|
+
}
|
|
331
|
+
double d;
|
|
332
|
+
memcpy(&d, &u, 8);
|
|
333
|
+
i += 8;
|
|
334
|
+
w_keyed_prefix(w);
|
|
335
|
+
if (w->st != TEPTRIS_OK) {
|
|
336
|
+
break;
|
|
337
|
+
}
|
|
338
|
+
emit_float(&w->out, d);
|
|
339
|
+
w_end_line(w);
|
|
340
|
+
break;
|
|
341
|
+
}
|
|
342
|
+
case W_FALSE:
|
|
343
|
+
case W_TRUE: {
|
|
344
|
+
w_keyed_prefix(w);
|
|
345
|
+
if (w->st != TEPTRIS_OK) {
|
|
346
|
+
break;
|
|
347
|
+
}
|
|
348
|
+
if (op == W_TRUE) {
|
|
349
|
+
eb_put(&w->out, "true", 4);
|
|
350
|
+
} else {
|
|
351
|
+
eb_put(&w->out, "false", 5);
|
|
352
|
+
}
|
|
353
|
+
w_end_line(w);
|
|
354
|
+
break;
|
|
355
|
+
}
|
|
356
|
+
case W_DATETIME: {
|
|
357
|
+
if (i + 26 > len) { /* kind + i64 year + 5 + u32 ns + i64 off */
|
|
358
|
+
w->st = TEPTRIS_ERR_ARG;
|
|
359
|
+
break;
|
|
360
|
+
}
|
|
361
|
+
uint8_t kb = ops[i];
|
|
362
|
+
if (kb < 4 || kb > 7) {
|
|
363
|
+
w->st = TEPTRIS_ERR_ARG;
|
|
364
|
+
break;
|
|
365
|
+
}
|
|
366
|
+
teptris_datetime dt;
|
|
367
|
+
uint64_t yr = 0, off = 0, ns = 0;
|
|
368
|
+
for (int b = 0; b < 8; b++) {
|
|
369
|
+
yr |= (uint64_t)ops[i + 1 + b] << (8 * b); /* LE */
|
|
370
|
+
off |= (uint64_t)ops[i + 18 + b] << (8 * b);
|
|
371
|
+
}
|
|
372
|
+
for (int b = 0; b < 4; b++) {
|
|
373
|
+
ns |= (uint64_t)ops[i + 14 + b] << (8 * b);
|
|
374
|
+
}
|
|
375
|
+
dt.year = (int32_t)yr;
|
|
376
|
+
dt.month = ops[i + 9];
|
|
377
|
+
dt.day = ops[i + 10];
|
|
378
|
+
dt.hour = ops[i + 11];
|
|
379
|
+
dt.minute = ops[i + 12];
|
|
380
|
+
dt.second = ops[i + 13];
|
|
381
|
+
memcpy(&dt.nanosecond, &ns, 4);
|
|
382
|
+
dt.offset_seconds = (int32_t)off;
|
|
383
|
+
i += 26;
|
|
384
|
+
w_keyed_prefix(w);
|
|
385
|
+
if (w->st != TEPTRIS_OK) {
|
|
386
|
+
break;
|
|
387
|
+
}
|
|
388
|
+
emit_dt(&w->out, &dt, (teptris_kind)kb);
|
|
389
|
+
w_end_line(w);
|
|
390
|
+
break;
|
|
391
|
+
if (w->st != TEPTRIS_OK) {
|
|
392
|
+
break;
|
|
393
|
+
}
|
|
394
|
+
emit_dt(&w->out, &dt, (teptris_kind)kb);
|
|
395
|
+
w_end_line(w);
|
|
396
|
+
break;
|
|
397
|
+
}
|
|
398
|
+
case W_BEGIN_TABLE: {
|
|
399
|
+
wframe *t = w->top;
|
|
400
|
+
if (t != NULL && (t->kind == F_ARRAY || t->kind == F_ITAB)) {
|
|
401
|
+
/* sections cannot live inside inline containers; use
|
|
402
|
+
* BEGIN_INLINE_TABLE there */
|
|
403
|
+
w->st = TEPTRIS_ERR_ARG;
|
|
404
|
+
break;
|
|
405
|
+
}
|
|
406
|
+
if (t != NULL && t->kind == F_AOT) {
|
|
407
|
+
/* element: [[path]] header, keyless frame */
|
|
408
|
+
w_sep(w);
|
|
409
|
+
eb_put(&w->out, "[[", 2);
|
|
410
|
+
w_path(w, 0);
|
|
411
|
+
eb_put(&w->out, "]]\n", 3);
|
|
412
|
+
w_clear_key(w);
|
|
413
|
+
w_push(w, F_TABLE, NULL, 0);
|
|
414
|
+
break;
|
|
415
|
+
}
|
|
416
|
+
if (w->key == NULL) {
|
|
417
|
+
w->st = TEPTRIS_ERR_ARG;
|
|
418
|
+
break;
|
|
419
|
+
}
|
|
420
|
+
if (t != NULL) {
|
|
421
|
+
t->saw_subtable = 1;
|
|
422
|
+
}
|
|
423
|
+
w_sep(w);
|
|
424
|
+
eb_c(&w->out, '[');
|
|
425
|
+
w_path(w, 1);
|
|
426
|
+
eb_put(&w->out, "]\n", 2);
|
|
427
|
+
char *k = w->key; /* frame takes ownership */
|
|
428
|
+
size_t klen = w->key_len;
|
|
429
|
+
w->key = NULL;
|
|
430
|
+
w->key_len = 0;
|
|
431
|
+
w_push_steal(w, F_TABLE, k, klen);
|
|
432
|
+
break;
|
|
433
|
+
}
|
|
434
|
+
case W_BEGIN_AOT: {
|
|
435
|
+
if (w->key == NULL) {
|
|
436
|
+
w->st = TEPTRIS_ERR_ARG;
|
|
437
|
+
break;
|
|
438
|
+
}
|
|
439
|
+
wframe *t = w->top;
|
|
440
|
+
if (t != NULL && t->kind != F_TABLE) {
|
|
441
|
+
w->st = TEPTRIS_ERR_ARG;
|
|
442
|
+
break;
|
|
443
|
+
}
|
|
444
|
+
if (t != NULL) {
|
|
445
|
+
t->saw_subtable = 1;
|
|
446
|
+
}
|
|
447
|
+
char *k = w->key; /* frame takes ownership */
|
|
448
|
+
size_t klen = w->key_len;
|
|
449
|
+
w->key = NULL;
|
|
450
|
+
w->key_len = 0;
|
|
451
|
+
w_push_steal(w, F_AOT, k, klen);
|
|
452
|
+
break;
|
|
453
|
+
}
|
|
454
|
+
case W_BEGIN_ARRAY: {
|
|
455
|
+
wframe *t = w->top;
|
|
456
|
+
if (t != NULL && t->kind == F_AOT) {
|
|
457
|
+
w->st = TEPTRIS_ERR_ARG;
|
|
458
|
+
break;
|
|
459
|
+
}
|
|
460
|
+
if (t == NULL || t->kind == F_TABLE || t->kind == F_ITAB) {
|
|
461
|
+
if (w->key == NULL) {
|
|
462
|
+
w->st = TEPTRIS_ERR_ARG;
|
|
463
|
+
break;
|
|
464
|
+
}
|
|
465
|
+
if (t != NULL && t->saw_subtable) {
|
|
466
|
+
w->st = TEPTRIS_ERR_STATE;
|
|
467
|
+
break;
|
|
468
|
+
}
|
|
469
|
+
emit_key(&w->out, (teptris_view){w->key, w->key_len});
|
|
470
|
+
eb_put(&w->out, " = [", 4);
|
|
471
|
+
w_clear_key(w);
|
|
472
|
+
} else { /* F_ARRAY: nested inline array */
|
|
473
|
+
w_sep_val(w, t);
|
|
474
|
+
eb_c(&w->out, '[');
|
|
475
|
+
}
|
|
476
|
+
w_push(w, F_ARRAY, NULL, 0);
|
|
477
|
+
break;
|
|
478
|
+
}
|
|
479
|
+
case W_BEGIN_INLINE_TABLE: {
|
|
480
|
+
wframe *t = w->top;
|
|
481
|
+
if (t != NULL && t->kind == F_ARRAY) {
|
|
482
|
+
if (w->key != NULL) {
|
|
483
|
+
w->st = TEPTRIS_ERR_ARG;
|
|
484
|
+
break;
|
|
485
|
+
}
|
|
486
|
+
w_sep_val(w, t);
|
|
487
|
+
} else {
|
|
488
|
+
if (w->key == NULL) {
|
|
489
|
+
w->st = TEPTRIS_ERR_ARG;
|
|
490
|
+
break;
|
|
491
|
+
}
|
|
492
|
+
if (t != NULL && t->saw_subtable) {
|
|
493
|
+
w->st = TEPTRIS_ERR_STATE;
|
|
494
|
+
break;
|
|
495
|
+
}
|
|
496
|
+
emit_key(&w->out, (teptris_view){w->key, w->key_len});
|
|
497
|
+
eb_put(&w->out, " = ", 3);
|
|
498
|
+
w_clear_key(w);
|
|
499
|
+
}
|
|
500
|
+
eb_c(&w->out, '{');
|
|
501
|
+
w_push(w, F_ITAB, NULL, 0);
|
|
502
|
+
break;
|
|
503
|
+
}
|
|
504
|
+
case W_CLOSE: {
|
|
505
|
+
wframe *f = w->top;
|
|
506
|
+
if (f == NULL || f->down == NULL) {
|
|
507
|
+
w->st = TEPTRIS_ERR_ARG; /* nothing (or only the root) open */
|
|
508
|
+
break;
|
|
509
|
+
}
|
|
510
|
+
int kind = f->kind;
|
|
511
|
+
w->top = f->down;
|
|
512
|
+
free(f->key);
|
|
513
|
+
free(f);
|
|
514
|
+
if (kind == F_ARRAY) {
|
|
515
|
+
eb_c(&w->out, ']');
|
|
516
|
+
w_end_line(w);
|
|
517
|
+
} else if (kind == F_ITAB) {
|
|
518
|
+
eb_c(&w->out, '}');
|
|
519
|
+
w_end_line(w);
|
|
520
|
+
}
|
|
521
|
+
break;
|
|
522
|
+
}
|
|
523
|
+
case W_EMPTY_TABLE:
|
|
524
|
+
case W_EMPTY_ARRAY: {
|
|
525
|
+
w_keyed_prefix(w);
|
|
526
|
+
if (w->st != TEPTRIS_OK) {
|
|
527
|
+
break;
|
|
528
|
+
}
|
|
529
|
+
if (op == W_EMPTY_TABLE) {
|
|
530
|
+
eb_put(&w->out, "{}", 2);
|
|
531
|
+
} else {
|
|
532
|
+
eb_put(&w->out, "[]", 2);
|
|
533
|
+
}
|
|
534
|
+
w_end_line(w);
|
|
535
|
+
break;
|
|
536
|
+
}
|
|
537
|
+
default:
|
|
538
|
+
w->st = TEPTRIS_ERR_ARG;
|
|
539
|
+
break;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
return w->st;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
teptris_status teptris_writer_finish(teptris_writer *w, char **buf,
|
|
546
|
+
size_t *len)
|
|
547
|
+
{
|
|
548
|
+
if (w == NULL || buf == NULL || len == NULL) {
|
|
549
|
+
return TEPTRIS_ERR_ARG;
|
|
550
|
+
}
|
|
551
|
+
*buf = NULL;
|
|
552
|
+
*len = 0;
|
|
553
|
+
if (w->top == NULL || w->top->down != NULL) {
|
|
554
|
+
return TEPTRIS_ERR_STATE; /* unclosed containers */
|
|
555
|
+
}
|
|
556
|
+
if (w->st != TEPTRIS_OK) {
|
|
557
|
+
return w->st;
|
|
558
|
+
}
|
|
559
|
+
w->finished = 1;
|
|
560
|
+
if (w->out.p == NULL) {
|
|
561
|
+
char *empty = malloc(1);
|
|
562
|
+
if (empty == NULL) {
|
|
563
|
+
return TEPTRIS_ERR_ALLOC;
|
|
564
|
+
}
|
|
565
|
+
empty[0] = '\0';
|
|
566
|
+
*buf = empty;
|
|
567
|
+
*len = 0;
|
|
568
|
+
return TEPTRIS_OK;
|
|
569
|
+
}
|
|
570
|
+
w->out.p[w->out.len] = '\0';
|
|
571
|
+
*buf = w->out.p;
|
|
572
|
+
*len = w->out.len;
|
|
573
|
+
w->out.p = NULL; /* ownership transferred */
|
|
574
|
+
return TEPTRIS_OK;
|
|
575
|
+
}
|