Line data Source code
1 : #define _DEFAULT_SOURCE
2 : #include "fd_toml.h"
3 : #include "../../util/fd_util.h"
4 : #include <ctype.h>
5 : #include <math.h>
6 :
7 : /* Implementation note:
8 :
9 : The lexer/parser of fd_toml.c is a simpler backtracking recursive
10 : descent parser. A minimal amount of lookahead tuning is implemented;
11 : mostly just fast failure paths. Obvious performance wins are
12 : possible by adding more speculative lookaheads that lead the CPU down
13 : "happy paths" such as long strings of ASCII.
14 :
15 : The indexer into fd_pod blindly inserts using fd_pod_insert, which
16 : may not be the most efficient allocation strategy. */
17 :
18 : /* fd_toml_cur_t is a cursor object. It is safe to copy this object via
19 : assignment to implement backtracking. */
20 :
21 : struct fd_toml_cur {
22 : ulong lineno;
23 : char const * data;
24 : };
25 :
26 : typedef struct fd_toml_cur fd_toml_cur_t;
27 :
28 : /* fd_toml_parser_t is the internal parser state. It implements the
29 : lexer/parser itself, logic to unescape and buffer, and logic to
30 : compose the data into an fd_pod_t. */
31 :
32 : struct fd_toml_parser {
33 : fd_toml_cur_t c;
34 : char const * data_end; /* points one past EOF */
35 : uchar * pod; /* pod provided by user */
36 : int error; /* hint: fatal pod error occurred */
37 :
38 : /* The current buffered string (either for both keys and values) */
39 :
40 : uchar * scratch; /* base of scratch buf */
41 : uchar * scratch_cur; /* next free byte in scratch buf */
42 : uchar * scratch_end; /* points one past scratch buf */
43 :
44 : /* Buffered keys */
45 :
46 : uint key_len;
47 : char key[ FD_TOML_PATH_MAX ]; /* cstr */
48 : };
49 :
50 : typedef struct fd_toml_parser fd_toml_parser_t;
51 :
52 : /* Accumulate and insert data into fd_pod *****************************/
53 :
54 : static void
55 4605 : fd_toml_str_init( fd_toml_parser_t * parser ) {
56 4605 : parser->scratch_cur = parser->scratch;
57 4605 : }
58 :
59 : static int
60 : fd_toml_str_append( fd_toml_parser_t * parser,
61 : void const * data,
62 0 : ulong sz ) {
63 :
64 0 : if( FD_UNLIKELY( parser->scratch_cur + sz >= parser->scratch_end ) ) {
65 0 : parser->error = FD_TOML_ERR_SCRATCH;
66 0 : return 0;
67 0 : }
68 :
69 0 : fd_memcpy( parser->scratch_cur, data, sz );
70 0 : parser->scratch_cur += sz;
71 0 : return 1;
72 0 : }
73 :
74 : static int
75 : fd_toml_str_append_byte( fd_toml_parser_t * parser,
76 54120 : int c ) {
77 :
78 54120 : if( FD_UNLIKELY( parser->scratch_cur >= parser->scratch_end ) ) {
79 0 : parser->error = FD_TOML_ERR_SCRATCH;
80 0 : return 0;
81 0 : }
82 :
83 54120 : parser->scratch_cur[0] = (uchar)c;
84 54120 : parser->scratch_cur++;
85 54120 : return 1;
86 54120 : }
87 :
88 : /* fd_toml_str_append_utf8 appends the UTF-8 encoding of the given
89 : Unicode code point (<=UINT_MAX). If rune is not a valid code point,
90 : writes the replacement code point instead. */
91 :
92 : static int
93 : fd_toml_str_append_utf8( fd_toml_parser_t * parser,
94 0 : long rune ) {
95 :
96 0 : if( FD_UNLIKELY( parser->scratch_cur + 4 >= parser->scratch_end ) ) {
97 0 : parser->error = FD_TOML_ERR_SCRATCH;
98 0 : return 0;
99 0 : }
100 :
101 0 : parser->scratch_cur = (uchar *)fd_cstr_append_utf8( (char *)parser->scratch_cur, (uint)rune );
102 0 : return 1;
103 0 : }
104 :
105 : /* Backtracking recursive-descent parser ******************************/
106 :
107 : /* fd_toml_advance advances the parser cursor by 'n' chars. Counts line
108 : numbers while advancing. If you now for sure that the next 'n' chars
109 : don't contain any new lines, use fd_toml_advance_inline instead. */
110 :
111 : static void /* consider aggressive inline */
112 : fd_toml_advance( fd_toml_parser_t * parser,
113 31605 : ulong n ) {
114 :
115 31605 : char const * p = parser->c.data;
116 31605 : char const * next = p + n;
117 31605 : if( FD_UNLIKELY( next > parser->data_end ) ) {
118 0 : FD_LOG_CRIT(( "fd_toml_advance out of bounds" ));
119 0 : }
120 :
121 : /* consider unroll */
122 31605 : ulong lines = 0UL;
123 63210 : for( ; p < next; p++ ) {
124 31605 : if( *p == '\n' ) lines++;
125 31605 : }
126 :
127 31605 : parser->c.lineno += lines;
128 31605 : parser->c.data = next;
129 31605 : }
130 :
131 : static inline void
132 : fd_toml_advance_inline( fd_toml_parser_t * parser,
133 1168860 : ulong n ) {
134 1168860 : parser->c.data += n;
135 1168860 : }
136 :
137 : static int
138 732 : fd_toml_upsert_empty_pod( fd_toml_parser_t * parser ) {
139 732 : if( !fd_pod_query_subpod( parser->pod, parser->key ) ) {
140 732 : uchar subpod_mem[ FD_POD_FOOTPRINT_MIN ];
141 732 : uchar * subpod = fd_pod_join( fd_pod_new( subpod_mem, FD_POD_FOOTPRINT_MIN ) );
142 732 : if( FD_UNLIKELY( !fd_pod_insert( parser->pod, parser->key, FD_POD_VAL_TYPE_SUBPOD, FD_POD_FOOTPRINT_MIN, subpod ) ) ) {
143 0 : parser->error = FD_TOML_ERR_POD;
144 0 : return 0;
145 0 : }
146 732 : fd_pod_delete( fd_pod_leave( subpod ) );
147 732 : }
148 732 : return 1;
149 732 : }
150 :
151 : /* fd_toml_avail returns the number of bytes available for parsing. */
152 :
153 : static inline ulong
154 1415268 : fd_toml_avail( fd_toml_parser_t const * parser ) {
155 1415268 : if( FD_UNLIKELY( parser->c.data > parser->data_end ) ) {
156 0 : FD_LOG_CRIT(( "Parse cursor is out of bounds" ));
157 0 : }
158 1415268 : return (ulong)parser->data_end - (ulong)parser->c.data;
159 1415268 : }
160 :
161 : #define SUB_PARSE( fn_call ) \
162 97245 : __extension__ ({ \
163 97245 : fd_toml_cur_t const _macro_backtrack = parser->c; \
164 97245 : int ret = fn_call; \
165 97245 : if( !ret ) { \
166 66105 : if( parser->error ) return 0; \
167 66105 : parser->c = _macro_backtrack; \
168 66105 : } \
169 97245 : ret; \
170 97245 : })
171 :
172 : #define EXPECT_CHAR(_c) \
173 29772 : do { \
174 29772 : if( FD_UNLIKELY( !fd_toml_avail( parser ) ) ) return 0; \
175 29772 : if( FD_UNLIKELY( parser->c.data[0] != (_c) ) ) return 0; \
176 29748 : fd_toml_advance_inline( parser, 1UL ); \
177 2178 : } while(0);
178 :
179 : /* Begin fd_toml_parse_{...} functions. All these functions attempt
180 : take a single argument, the parser. Each function attempts to match
181 : a token and returns 1 on success. If the token was not matched,
182 : returns 0. On success, the cursor is advanced to one past the read
183 : token. On failure, the cursor may arbitrarily advance within bounds.
184 : Parsers can gracefully recover from failure (backtrack) by restoring
185 : the fd_toml_cur_t object to its original state. */
186 :
187 : static int fd_toml_parse_keyval( fd_toml_parser_t * parser );
188 : static int fd_toml_parse_val ( fd_toml_parser_t * parser );
189 :
190 : /* ws = *wschar
191 : wschar = %x20 ; Space
192 : wschar =/ %x09 ; Horizontal tab */
193 :
194 : static int
195 38664 : fd_toml_parse_ws( fd_toml_parser_t * parser ) {
196 :
197 163512 : while( fd_toml_avail( parser ) ) {
198 163398 : char c = parser->c.data[0];
199 163398 : if( c != ' ' && c != '\t' ) break;
200 124848 : fd_toml_advance_inline( parser, 1UL );
201 124848 : }
202 :
203 38664 : return 1;
204 38664 : }
205 :
206 : /* comment-start-symbol = %x23
207 : non-ascii = %x80-D7FF / %xE000-10FFFF
208 : non-eol = %x09 / %x20-7F / non-ascii
209 :
210 : comment = comment-start-symbol *non-eol */
211 :
212 : static int
213 25677 : fd_toml_parse_comment( fd_toml_parser_t * parser ) {
214 25677 : if( FD_UNLIKELY( !fd_toml_avail( parser ) ) ) return 0;
215 25563 : if( FD_UNLIKELY( parser->c.data[0] != '#' ) ) return 0;
216 20226 : fd_toml_advance_inline( parser, 1UL );
217 :
218 981726 : while( fd_toml_avail( parser ) ) {
219 981726 : uint c = (uchar)parser->c.data[0];
220 981726 : if( FD_LIKELY( (c==0x09) |
221 981726 : (c>=0x20 && c<0x7F) |
222 981726 : (c>=0x80) ) ) {
223 961500 : fd_toml_advance_inline( parser, 1UL );
224 961500 : } else {
225 20226 : break;
226 20226 : }
227 981726 : }
228 :
229 20226 : return 1;
230 25563 : }
231 :
232 : /* quotation-mark = %x22 */
233 :
234 : static int
235 30057 : fd_toml_parse_quotation_mark( fd_toml_parser_t * parser ) {
236 30057 : if( FD_UNLIKELY( !fd_toml_avail( parser ) ) ) return 0;
237 30033 : if( FD_UNLIKELY( parser->c.data[0] != '"' ) ) return 0;
238 1806 : fd_toml_advance_inline( parser, 1UL );
239 1806 : return 1;
240 30033 : }
241 :
242 : /* basic-unescaped = wschar / %x21 / %x23-5B / %x5D-7E / non-ascii */
243 :
244 : static int
245 7338 : fd_toml_parse_basic_unescaped( fd_toml_parser_t * parser ) {
246 :
247 7338 : if( FD_UNLIKELY( !fd_toml_avail( parser ) ) ) return 0;
248 :
249 7338 : int c = (uchar)parser->c.data[0];
250 7338 : if( FD_LIKELY( (c==' ') | (c=='\t') |
251 7338 : (c==0x21) |
252 7338 : (c>=0x23 && c<=0x5B) |
253 7338 : (c>=0x5D && c<=0x7E) |
254 7338 : (c>=0x80) ) ) { /* ok */ }
255 903 : else {
256 903 : return 0;
257 903 : }
258 :
259 6435 : fd_toml_str_append_byte( parser, (uchar)c );
260 6435 : fd_toml_advance( parser, 1UL );
261 6435 : return 1;
262 7338 : }
263 :
264 : /* fd_toml_xdigit converts a char to a hex digit. Assumes that the
265 : char matches [0-9a-fA-F] */
266 :
267 : FD_FN_CONST static inline uint
268 0 : fd_toml_xdigit( int c ) {
269 0 : c = tolower( c );
270 0 : c = fd_int_if( c>'9', c-'a'+10, c-'0' );
271 0 : return (uint)c;
272 0 : }
273 :
274 : /* escaped = escape escape-seq-char
275 : escape = %x5C ; \
276 : escape-seq-char = %x22 ; " quotation mark U+0022
277 : escape-seq-char =/ %x5C ; \ reverse solidus U+005C
278 : escape-seq-char =/ %x62 ; b backspace U+0008
279 : escape-seq-char =/ %x66 ; f form feed U+000C
280 : escape-seq-char =/ %x6E ; n line feed U+000A
281 : escape-seq-char =/ %x72 ; r carriage return U+000D
282 : escape-seq-char =/ %x74 ; t tab U+0009
283 : escape-seq-char =/ %x75 4HEXDIG ; uXXXX U+XXXX
284 : escape-seq-char =/ %x55 8HEXDIG ; UXXXXXXXX U+XXXXXXXX */
285 :
286 : static int
287 903 : fd_toml_parse_escaped( fd_toml_parser_t * parser ) {
288 :
289 903 : if( FD_UNLIKELY( fd_toml_avail( parser ) < 2UL ) ) return 0;
290 891 : if( FD_UNLIKELY( parser->c.data[0] != '\\' ) ) return 0;
291 0 : int kind = parser->c.data[1];
292 0 : fd_toml_advance_inline( parser, 2UL );
293 :
294 0 : int valid = 1;
295 0 : uint rune;
296 0 : switch( kind ) {
297 0 : case 'b':
298 0 : fd_toml_str_append_byte( parser, '\b' );
299 0 : return 1;
300 0 : case 'f':
301 0 : fd_toml_str_append_byte( parser, '\f' );
302 0 : return 1;
303 0 : case 'n':
304 0 : fd_toml_str_append_byte( parser, '\n' );
305 0 : return 1;
306 0 : case 'r':
307 0 : fd_toml_str_append_byte( parser, '\r' );
308 0 : return 1;
309 0 : case 't':
310 0 : fd_toml_str_append_byte( parser, '\t' );
311 0 : return 1;
312 0 : case '"':
313 0 : case '\\':
314 0 : fd_toml_str_append_byte( parser, kind );
315 0 : return 1;
316 0 : case 'u':
317 0 : if( FD_UNLIKELY( fd_toml_avail( parser ) < 4UL ) ) return 0;
318 0 : for( ulong j=0; j<4; j++ ) valid &= fd_isxdigit( parser->c.data[j] );
319 0 : if( FD_UNLIKELY( !valid ) ) return 0;
320 0 : rune = ( fd_toml_xdigit( parser->c.data[0] )<<12 );
321 0 : rune |= ( fd_toml_xdigit( parser->c.data[1] )<< 8 );
322 0 : rune |= ( fd_toml_xdigit( parser->c.data[2] )<< 4 );
323 0 : rune |= ( fd_toml_xdigit( parser->c.data[3] ) );
324 0 : if( FD_UNLIKELY( !fd_toml_str_append_utf8( parser, rune ) ) ) return 0;
325 0 : fd_toml_advance_inline( parser, 4UL );
326 0 : return 1;
327 0 : case 'U':
328 0 : if( FD_UNLIKELY( fd_toml_avail( parser ) < 8UL ) ) return 0;
329 0 : for( ulong j=0; j<8; j++ ) valid &= fd_isxdigit( parser->c.data[j] );
330 0 : if( FD_UNLIKELY( !valid ) ) return 0;
331 0 : rune = ( fd_toml_xdigit( parser->c.data[0] )<<28 );
332 0 : rune |= ( fd_toml_xdigit( parser->c.data[1] )<<24 );
333 0 : rune |= ( fd_toml_xdigit( parser->c.data[2] )<<20 );
334 0 : rune |= ( fd_toml_xdigit( parser->c.data[3] )<<16 );
335 0 : rune |= ( fd_toml_xdigit( parser->c.data[4] )<<12 );
336 0 : rune |= ( fd_toml_xdigit( parser->c.data[5] )<< 8 );
337 0 : rune |= ( fd_toml_xdigit( parser->c.data[6] )<< 4 );
338 0 : rune |= ( fd_toml_xdigit( parser->c.data[7] ) );
339 0 : if( FD_UNLIKELY( !fd_toml_str_append_utf8( parser, rune ) ) ) return 0;
340 0 : fd_toml_advance_inline( parser, 8UL );
341 0 : return 1;
342 0 : default:
343 0 : return 0;
344 0 : }
345 0 : }
346 :
347 : /* basic-char = basic-unescaped / escaped */
348 :
349 : static int
350 7338 : fd_toml_parse_basic_char( fd_toml_parser_t * parser ) {
351 7338 : if( FD_LIKELY( SUB_PARSE( fd_toml_parse_basic_unescaped( parser ) ) ) ) return 1;
352 903 : if( FD_LIKELY( SUB_PARSE( fd_toml_parse_escaped ( parser ) ) ) ) return 1;
353 903 : return 0;
354 903 : }
355 :
356 : /* basic-string = quotation-mark *basic-char quotation-mark */
357 :
358 : static int
359 29154 : fd_toml_parse_basic_string( fd_toml_parser_t * parser ) {
360 29154 : if( FD_UNLIKELY( !SUB_PARSE( fd_toml_parse_quotation_mark( parser ) ) ) ) return 0;
361 903 : fd_toml_str_init( parser );
362 7338 : while( SUB_PARSE( fd_toml_parse_basic_char( parser ) ) ) {}
363 903 : if( FD_UNLIKELY( !SUB_PARSE( fd_toml_parse_quotation_mark( parser ) ) ) ) return 0;
364 903 : return 1;
365 903 : }
366 :
367 : /* apostrophe = %x27 ; ' apostrophe */
368 :
369 : static int
370 28251 : fd_toml_parse_apostrophe( fd_toml_parser_t * parser ) {
371 28251 : if( FD_UNLIKELY( !fd_toml_avail( parser ) ) ) return 0;
372 28227 : if( FD_UNLIKELY( parser->c.data[0] != '\'' ) ) return 0;
373 0 : fd_toml_advance_inline( parser, 1UL );
374 0 : return 1;
375 28227 : }
376 :
377 : /* literal-char = %x09 / %x20-26 / %x28-7E / non-ascii */
378 :
379 : static int
380 0 : fd_toml_parse_literal_char( fd_toml_parser_t * parser ) {
381 :
382 0 : if( FD_UNLIKELY( !fd_toml_avail( parser ) ) ) return 0;
383 :
384 0 : int c = (uchar)parser->c.data[0];
385 0 : if( FD_LIKELY( (c==0x09) |
386 0 : (c>=0x20 && c<=0x26) |
387 0 : (c>=0x28 && c<=0x7E) |
388 0 : (c>=0x80) ) ) { /* ok */ }
389 0 : else {
390 0 : return 0;
391 0 : }
392 :
393 0 : fd_toml_str_append_byte( parser, c );
394 0 : fd_toml_advance( parser, 1UL );
395 0 : return 1;
396 0 : }
397 :
398 : /* literal-string = apostrophe *literal-char apostrophe */
399 :
400 : static int
401 28251 : fd_toml_parse_literal_string( fd_toml_parser_t * parser ) {
402 28251 : if( FD_UNLIKELY( !SUB_PARSE( fd_toml_parse_apostrophe( parser ) ) ) ) return 0;
403 0 : fd_toml_str_init( parser );
404 0 : while( SUB_PARSE( fd_toml_parse_literal_char( parser ) ) ) {}
405 0 : if( FD_UNLIKELY( !SUB_PARSE( fd_toml_parse_apostrophe( parser ) ) ) ) return 0;
406 0 : return 1;
407 0 : }
408 :
409 : /* quoted-key = basic-string / literal-string */
410 :
411 : static int
412 26562 : fd_toml_parse_quoted_key( fd_toml_parser_t * parser ) {
413 26562 : if( FD_LIKELY( SUB_PARSE( fd_toml_parse_basic_string ( parser ) ) ) ) return 1;
414 26562 : if( FD_LIKELY( SUB_PARSE( fd_toml_parse_literal_string( parser ) ) ) ) return 1;
415 26562 : return 0;
416 26562 : }
417 :
418 : /* unquoted-key = 1*( ALPHA / DIGIT / %x2D / %x5F ) ; A-Z / a-z / 0-9 / - / _ */
419 :
420 : static int
421 73320 : fd_toml_is_unquoted_key_char( int c ) {
422 73320 : return (c>='A' && c<='Z') |
423 73320 : (c>='a' && c<='z') |
424 73320 : (c>='0' && c<='9') |
425 73320 : (c=='-') |
426 73320 : (c=='_');
427 73320 : }
428 :
429 : static int
430 26562 : fd_toml_parse_unquoted_key( fd_toml_parser_t * parser ) {
431 26562 : if( FD_UNLIKELY( !fd_toml_avail( parser ) ) ) return 0;
432 26538 : int c = (uchar)parser->c.data[0];
433 26538 : if( FD_UNLIKELY( !fd_toml_is_unquoted_key_char( c ) ) ) return 0;
434 3702 : fd_toml_str_init( parser );
435 :
436 3702 : fd_toml_str_append_byte( parser, c );
437 3702 : fd_toml_advance_inline( parser, 1UL );
438 :
439 46782 : while( fd_toml_avail( parser ) ) {
440 46782 : c = (uchar)parser->c.data[0];
441 46782 : if( FD_LIKELY( fd_toml_is_unquoted_key_char( c ) ) ) {
442 43080 : fd_toml_str_append_byte( parser, c );
443 43080 : fd_toml_advance_inline( parser, 1UL );
444 43080 : } else {
445 3702 : break;
446 3702 : }
447 46782 : }
448 3702 : return 1;
449 26538 : }
450 :
451 : /* simple-key = quoted-key / unquoted-key */
452 :
453 : static int
454 26562 : fd_toml_parse_simple_key( fd_toml_parser_t * parser ) {
455 26562 : if( FD_LIKELY( SUB_PARSE( fd_toml_parse_quoted_key ( parser ) ) ) ) goto add;
456 26562 : if( FD_LIKELY( SUB_PARSE( fd_toml_parse_unquoted_key( parser ) ) ) ) goto add;
457 22860 : return 0;
458 :
459 3702 : add:
460 3702 : do {
461 3702 : uint old_key_len = parser->key_len;
462 3702 : ulong suffix_len = (ulong)parser->scratch_cur - (ulong)parser->scratch;
463 3702 : ulong key_len = (ulong)old_key_len + suffix_len + 1;
464 3702 : if( FD_UNLIKELY( key_len > sizeof(parser->key) ) ) {
465 0 : FD_LOG_WARNING(( "TOML parse error: key is too long: \"%.*s%.*s\"",
466 0 : (int)old_key_len, parser->key,
467 0 : (int)suffix_len, (char *)parser->scratch ));
468 0 : parser->error = FD_TOML_ERR_KEY;
469 0 : return 0;
470 0 : }
471 :
472 3702 : char * key_cur = fd_cstr_init( parser->key + old_key_len );
473 3702 : key_cur = fd_cstr_append_text( key_cur, (char const *)parser->scratch, suffix_len );
474 3702 : fd_cstr_fini( key_cur );
475 3702 : parser->key_len = (uint)( key_cur - parser->key );
476 3702 : return 1;
477 3702 : } while(0);
478 3702 : }
479 :
480 : /* dot-sep = ws %x2E ws ; . Period */
481 :
482 : static int
483 3702 : fd_toml_parse_dot_sep( fd_toml_parser_t * parser ) {
484 3702 : fd_toml_parse_ws( parser );
485 3702 : EXPECT_CHAR( '.' );
486 714 : fd_toml_parse_ws( parser );
487 714 : return 1;
488 3702 : }
489 :
490 : /* dotted-key = simple-key 1*( dot-sep simple-key ) */
491 :
492 : static int
493 25848 : fd_toml_parse_dotted_key( fd_toml_parser_t * parser ) {
494 25848 : if( FD_UNLIKELY( !SUB_PARSE( fd_toml_parse_simple_key( parser ) ) ) ) return 0;
495 3702 : while( fd_toml_avail( parser ) ) {
496 3702 : if( FD_UNLIKELY( !SUB_PARSE( fd_toml_parse_dot_sep( parser ) ) ) ) break;
497 :
498 : /* Add trailing dot */
499 714 : if( parser->key_len + 2 > sizeof(parser->key) ) {
500 0 : parser->error = FD_TOML_ERR_KEY;
501 0 : return 0;
502 0 : }
503 714 : parser->key[ parser->key_len++ ] = '.';
504 714 : parser->key[ parser->key_len ] = '\x00';
505 :
506 714 : if( FD_UNLIKELY( !SUB_PARSE( fd_toml_parse_simple_key( parser ) ) ) ) return 0;
507 714 : }
508 2988 : return 1;
509 2988 : }
510 :
511 : /* key = simple-key / dotted-key
512 :
513 : Doing simple-key *( dot-sep simple-key ) instead to simplify code */
514 :
515 : static int
516 25848 : fd_toml_parse_key( fd_toml_parser_t * parser ) {
517 25848 : return fd_toml_parse_dotted_key( parser );
518 25848 : }
519 :
520 : /* keyval-sep = ws %x3D ws */
521 :
522 : static int
523 2424 : fd_toml_parse_keyval_sep( fd_toml_parser_t * parser ) {
524 2424 : fd_toml_parse_ws( parser );
525 2424 : if( FD_UNLIKELY( !fd_toml_avail( parser ) ) ) return 0;
526 2424 : if( FD_UNLIKELY( parser->c.data[0] != '=' ) ) return 0;
527 2424 : fd_toml_advance_inline( parser, 1UL );
528 2424 : fd_toml_parse_ws( parser );
529 2424 : return 1;
530 2424 : }
531 :
532 : /* ml-basic-string-delim = 3quotation-mark */
533 :
534 : static int
535 2592 : fd_toml_parse_ml_basic_string_delim( fd_toml_parser_t * parser ) {
536 2592 : if( FD_UNLIKELY( parser->c.data + 3 > parser->data_end ) ) return 0;
537 2580 : if( FD_UNLIKELY( ( parser->c.data[0] != '"' ) |
538 2580 : ( parser->c.data[1] != '"' ) |
539 2580 : ( parser->c.data[2] != '"' ) ) ) return 0;
540 0 : fd_toml_advance_inline( parser, 3UL );
541 0 : return 1;
542 2580 : }
543 :
544 : /* mlb-unescaped = wschar / %x21 / %x23-5B / %x5D-7E / non-ascii */
545 :
546 : static int
547 0 : fd_toml_parse_mlb_unescaped( fd_toml_parser_t * parser ) {
548 0 : return fd_toml_parse_basic_unescaped( parser );
549 0 : }
550 :
551 : /* mlb-escaped-nl = escape ws newline *( wschar / newline ) */
552 :
553 : static int
554 0 : fd_toml_parse_mlb_escaped_nl( fd_toml_parser_t * parser ) {
555 0 : if( FD_UNLIKELY( fd_toml_avail( parser ) < 2UL ) ) return 0;
556 0 : if( FD_UNLIKELY( parser->c.data[0] != '\\' ) ) return 0;
557 0 : fd_toml_advance_inline( parser, 1UL );
558 0 : SUB_PARSE( fd_toml_parse_ws( parser ) );
559 0 : if( FD_UNLIKELY( !fd_toml_avail( parser ) ) ) return 0;
560 0 : if( FD_UNLIKELY( parser->c.data[0] != '\n' ) ) return 0;
561 0 : while( fd_toml_avail( parser ) ) {
562 0 : int c = (uchar)parser->c.data[0];
563 0 : if( (c==' ') | (c=='\t') | (c=='\n') ) {
564 0 : fd_toml_advance( parser, 1UL );
565 0 : } else {
566 0 : break;
567 0 : }
568 0 : }
569 0 : return 1;
570 0 : }
571 :
572 : /* mlb-content = mlb-char / newline / mlb-escaped-nl
573 : mlb-char = mlb-unescaped / escaped */
574 :
575 : static int
576 0 : fd_toml_parse_mlb_content( fd_toml_parser_t * parser ) {
577 0 : if( FD_UNLIKELY( !fd_toml_avail( parser ) ) ) return 0;
578 0 : if( FD_LIKELY( SUB_PARSE( fd_toml_parse_mlb_unescaped( parser ) ) ) ) return 1;
579 0 : if( FD_LIKELY( SUB_PARSE( fd_toml_parse_escaped ( parser ) ) ) ) return 1;
580 0 : if( FD_LIKELY( parser->c.data[0] == '\n' ) ) {
581 0 : fd_toml_str_append_byte( parser, '\n' );
582 0 : fd_toml_advance( parser, 1UL );
583 0 : return 1;
584 0 : }
585 0 : if( FD_LIKELY( SUB_PARSE( fd_toml_parse_mlb_escaped_nl( parser ) ) ) ) return 1;
586 0 : return 0;
587 0 : }
588 :
589 : /* mlb-quotes = 1*2quotation-mark
590 : Note: This is used to allow normal quotes (", "") inside a multiline
591 : basic comment (""") */
592 :
593 : static int
594 0 : fd_toml_parse_mlb_quotes( fd_toml_parser_t * parser ) {
595 :
596 : /* Count number of quotes */
597 0 : char const * begin = parser->c.data;
598 0 : ulong quote_cnt = 0UL;
599 0 : while( fd_toml_avail( parser ) && parser->c.data[0] == '"' ) {
600 0 : fd_toml_advance_inline( parser, 1UL );
601 0 : quote_cnt++;
602 0 : }
603 :
604 0 : if( !quote_cnt || quote_cnt > 5 ) return 0;
605 0 : if( quote_cnt < 3 ) {
606 0 : fd_toml_str_append( parser, begin, quote_cnt );
607 0 : return 1;
608 0 : }
609 0 : if( quote_cnt==3 ) return 0;
610 :
611 : /* Backtrack by 3 quotes, as those might be the multiline */
612 0 : parser->c.data -= 3;
613 0 : quote_cnt -= 3;
614 0 : fd_toml_str_append( parser, begin, quote_cnt );
615 0 : return 1;
616 0 : }
617 :
618 : /* ml-basic-body = *mlb-content *( mlb-quotes 1*mlb-content ) [ mlb-quotes ] */
619 :
620 : static int
621 0 : fd_toml_parse_ml_basic_body( fd_toml_parser_t * parser ) {
622 0 : while( SUB_PARSE( fd_toml_parse_mlb_content( parser ) ) ) {}
623 0 : for(;;) {
624 0 : if( FD_UNLIKELY( !SUB_PARSE( fd_toml_parse_mlb_quotes ( parser ) ) ) ) break;
625 0 : if( FD_UNLIKELY( !SUB_PARSE( fd_toml_parse_mlb_content( parser ) ) ) ) break;
626 0 : while( SUB_PARSE( fd_toml_parse_mlb_content( parser ) ) ) {}
627 0 : }
628 0 : SUB_PARSE( fd_toml_parse_mlb_quotes( parser ) );
629 0 : return 1;
630 0 : }
631 :
632 : /* ml-basic-string = ml-basic-string-delim [ newline ] ml-basic-body ml-basic-string-delim */
633 :
634 : static int
635 2592 : fd_toml_parse_ml_basic_string( fd_toml_parser_t * parser ) {
636 2592 : if( FD_UNLIKELY( !SUB_PARSE( fd_toml_parse_ml_basic_string_delim( parser ) ) ) ) return 0;
637 0 : if( FD_UNLIKELY( !fd_toml_avail( parser ) ) ) return 0;
638 0 : if( parser->c.data[0] == '\n' ) {
639 0 : fd_toml_advance( parser, 1UL );
640 0 : }
641 0 : fd_toml_str_init( parser );
642 0 : if( FD_UNLIKELY( !SUB_PARSE( fd_toml_parse_ml_basic_body ( parser ) ) ) ) return 0;
643 0 : if( FD_UNLIKELY( !SUB_PARSE( fd_toml_parse_ml_basic_string_delim( parser ) ) ) ) return 0;
644 0 : return 1;
645 0 : }
646 :
647 : /* mll-quotes = 1*2apostrophe
648 : Note: This is used to allow normal quotes (', '') inside a multiline
649 : literal comment (''') */
650 :
651 : static int
652 0 : fd_toml_parse_mll_quotes( fd_toml_parser_t * parser ) {
653 :
654 : /* Count number of quotes */
655 0 : char const * begin = parser->c.data;
656 0 : ulong quote_cnt = 0UL;
657 0 : while( fd_toml_avail( parser ) && parser->c.data[0] == '\'' ) {
658 0 : fd_toml_advance_inline( parser, 1UL );
659 0 : quote_cnt++;
660 0 : }
661 :
662 0 : if( !quote_cnt || quote_cnt > 5 ) return 0;
663 0 : if( quote_cnt < 3 ) {
664 0 : fd_toml_str_append( parser, begin, quote_cnt );
665 0 : return 1;
666 0 : }
667 0 : if( quote_cnt==3 ) return 0;
668 :
669 : /* Backtrack by 3 quotes, as those might be the multiline */
670 0 : parser->c.data -= 3;
671 0 : quote_cnt -= 3;
672 0 : fd_toml_str_append( parser, begin, quote_cnt );
673 0 : return 1;
674 0 : }
675 :
676 : /* mll-content = mll-char / newline
677 : mll-char = %x09 / %x20-26 / %x28-7E / non-ascii */
678 :
679 : static int
680 0 : fd_toml_parse_mll_content( fd_toml_parser_t * parser ) {
681 0 : if( FD_UNLIKELY( !fd_toml_avail( parser ) ) ) return 0;
682 :
683 0 : int c = (uchar)parser->c.data[0];
684 0 : if( FD_LIKELY( (c==0x09) |
685 0 : (c>=0x20 && c<=0x26) |
686 0 : (c>=0x28 && c<=0x7E) |
687 0 : (c>=0x80) |
688 0 : (c=='\n') ) ) {
689 : /* ok */
690 0 : } else {
691 0 : return 0;
692 0 : }
693 0 : if( FD_UNLIKELY( !fd_toml_str_append_byte( parser, c ) ) ) return 0;
694 :
695 0 : fd_toml_advance( parser, 1UL );
696 0 : return 1;
697 0 : }
698 :
699 : /* ml-literal-body = *mll-content *( mll-quotes 1*mll-content ) [ mll-quotes ] */
700 :
701 : static int
702 0 : fd_toml_parse_ml_literal_body( fd_toml_parser_t * parser ) {
703 0 : while( SUB_PARSE( fd_toml_parse_mll_content( parser ) ) ) {}
704 0 : for(;;) {
705 0 : if( FD_UNLIKELY( !SUB_PARSE( fd_toml_parse_mll_quotes ( parser ) ) ) ) break;
706 0 : if( FD_UNLIKELY( !SUB_PARSE( fd_toml_parse_mll_content( parser ) ) ) ) break;
707 0 : while( SUB_PARSE( fd_toml_parse_mll_content( parser ) ) ) {}
708 0 : }
709 0 : SUB_PARSE( fd_toml_parse_mll_quotes( parser ) );
710 0 : return 1;
711 0 : }
712 :
713 : /* ml-literal-string-delim = 3apostrophe */
714 :
715 : static int
716 1689 : fd_toml_parse_ml_literal_string_delim( fd_toml_parser_t * parser ) {
717 1689 : if( FD_UNLIKELY( parser->c.data + 3 > parser->data_end ) ) return 0;
718 1677 : if( FD_UNLIKELY( ( parser->c.data[0] != '\'' ) |
719 1677 : ( parser->c.data[1] != '\'' ) |
720 1677 : ( parser->c.data[2] != '\'' ) ) ) return 0;
721 0 : fd_toml_advance_inline( parser, 3UL );
722 0 : return 1;
723 1677 : }
724 :
725 : /* ml-literal-string = ml-literal-string-delim [ newline ] ml-literal-body
726 : ml-literal-string-delim */
727 :
728 : static int
729 1689 : fd_toml_parse_ml_literal_string( fd_toml_parser_t * parser ) {
730 1689 : if( FD_UNLIKELY( !SUB_PARSE( fd_toml_parse_ml_literal_string_delim( parser ) ) ) ) return 0;
731 0 : if( FD_UNLIKELY( !fd_toml_avail( parser ) ) ) return 0;
732 0 : if( parser->c.data[0] == '\n' ) {
733 0 : fd_toml_advance( parser, 1UL );
734 0 : }
735 0 : fd_toml_str_init( parser );
736 0 : if( FD_UNLIKELY( !SUB_PARSE( fd_toml_parse_ml_literal_body ( parser ) ) ) ) return 0;
737 0 : if( FD_UNLIKELY( !SUB_PARSE( fd_toml_parse_ml_literal_string_delim( parser ) ) ) ) return 0;
738 0 : return 1;
739 0 : }
740 :
741 : /* string = ml-basic-string / basic-string / ml-literal-string / literal-string */
742 :
743 : static int
744 2592 : fd_toml_parse_string( fd_toml_parser_t * parser ) {
745 2592 : if( FD_LIKELY( SUB_PARSE( fd_toml_parse_ml_basic_string ( parser ) ) ) ) goto add;
746 2592 : if( FD_LIKELY( SUB_PARSE( fd_toml_parse_basic_string ( parser ) ) ) ) goto add;
747 1689 : if( FD_LIKELY( SUB_PARSE( fd_toml_parse_ml_literal_string( parser ) ) ) ) goto add;
748 1689 : if( FD_LIKELY( SUB_PARSE( fd_toml_parse_literal_string ( parser ) ) ) ) goto add;
749 1689 : return 0;
750 903 : add:
751 903 : if( FD_UNLIKELY( !fd_toml_str_append_byte( parser, 0 ) ) ) return 0;
752 903 : if( FD_UNLIKELY( !fd_pod_insert(
753 903 : parser->pod, parser->key, FD_POD_VAL_TYPE_CSTR,
754 903 : (ulong)parser->scratch_cur - (ulong)parser->scratch,
755 903 : (char *)parser->scratch ) ) ) {
756 0 : parser->error = FD_TOML_ERR_POD;
757 0 : return 0;
758 0 : }
759 903 : return 1;
760 903 : }
761 :
762 : /* boolean = true / false */
763 :
764 : static int
765 1689 : fd_toml_parse_boolean( fd_toml_parser_t * parser ) {
766 1689 : int boolv = 0;
767 1689 : if( parser->c.data + 4 > parser->data_end ) return 0;
768 1656 : if( 0==memcmp( parser->c.data, "true", 4 ) ) {
769 192 : fd_toml_advance_inline( parser, 4 );
770 192 : boolv = 1;
771 192 : goto add;
772 192 : }
773 1464 : if( parser->c.data + 5 > parser->data_end ) return 0;
774 1452 : if( 0==memcmp( parser->c.data, "false", 5 ) ) {
775 174 : fd_toml_advance_inline( parser, 5 );
776 174 : boolv = 0;
777 174 : goto add;
778 174 : }
779 1278 : return 0;
780 366 : add:
781 366 : if( FD_UNLIKELY( !fd_pod_insert_int( parser->pod, parser->key, boolv ) ) ) {
782 0 : parser->error = FD_TOML_ERR_POD;
783 0 : return 0;
784 0 : }
785 366 : return 1;
786 366 : }
787 :
788 : /* ws-comment-newline = *( wschar / [ comment ] newline ) */
789 :
790 : static int
791 393 : fd_toml_parse_ws_comment_newline_inner( fd_toml_parser_t * parser ) {
792 393 : if( FD_UNLIKELY( !fd_toml_avail( parser ) ) ) return 0;
793 393 : int c = (uchar)parser->c.data[0];
794 393 : if( FD_UNLIKELY( c == ' ' || c == '\t' ) ) {
795 0 : fd_toml_advance_inline( parser, 1UL );
796 0 : return 1;
797 0 : }
798 786 : SUB_PARSE( fd_toml_parse_comment( parser ) );
799 786 : if( FD_UNLIKELY( !fd_toml_avail( parser ) ) ) return 0;
800 393 : if( FD_UNLIKELY( parser->c.data[0] != '\n' ) ) return 0;
801 0 : fd_toml_advance( parser, 1UL );
802 0 : return 1;
803 393 : }
804 :
805 : static int
806 393 : fd_toml_parse_ws_comment_newline( fd_toml_parser_t * parser ) {
807 393 : while( SUB_PARSE( fd_toml_parse_ws_comment_newline_inner( parser ) ) ) {}
808 393 : return 1;
809 393 : }
810 :
811 : /* array-values = ws-comment-newline val ws-comment-newline array-sep array-values
812 : array-values =/ ws-comment-newline val ws-comment-newline [ array-sep ] */
813 :
814 : static int
815 168 : fd_toml_parse_array_values( fd_toml_parser_t * parser ) {
816 :
817 168 : uint old_len = parser->key_len;
818 168 : char * suffix_cstr = parser->key + parser->key_len;
819 168 : if( FD_UNLIKELY( suffix_cstr + 22 > parser->key + sizeof(parser->key) ) ) {
820 : /* array index might be OOB (see python3 -c 'print(len(str(1<<64)))') */
821 0 : parser->error = FD_TOML_ERR_KEY;
822 0 : return 0;
823 0 : }
824 :
825 : /* Unrolled tail recursion with backtracking */
826 :
827 168 : fd_toml_cur_t backtrack = parser->c;
828 168 : for( ulong j=0;; j++ ) {
829 168 : char * child_key = fd_cstr_append_char( suffix_cstr, '.' );
830 168 : child_key = fd_cstr_append_ulong_as_text( child_key, 0, 0, j, fd_ulong_base10_dig_cnt( j ) );
831 168 : fd_cstr_fini( child_key );
832 168 : parser->key_len = (uint)( child_key - parser->key );
833 :
834 168 : fd_toml_parse_ws_comment_newline( parser );
835 168 : if( FD_UNLIKELY( !fd_toml_parse_val( parser ) ) ) {
836 111 : parser->c = backtrack;
837 111 : break;
838 111 : }
839 :
840 57 : FD_LOG_DEBUG(( "Added key %s", parser->key ));
841 :
842 57 : fd_toml_parse_ws_comment_newline( parser );
843 :
844 57 : backtrack = parser->c;
845 57 : if( fd_toml_avail( parser ) && parser->c.data[0] == ',' ) {
846 0 : fd_toml_advance_inline( parser, 1UL );
847 57 : } else {
848 57 : break;
849 57 : }
850 0 : backtrack = parser->c;
851 0 : }
852 :
853 : /* Undo array index */
854 :
855 168 : fd_cstr_fini( suffix_cstr );
856 168 : parser->key_len = old_len;
857 168 : return 1;
858 168 : }
859 :
860 : /* array = array-open [ array-values ] ws-comment-newline array-close
861 :
862 : array-open = %x5B ; [
863 : array-close = %x5D ; ] */
864 :
865 : static int
866 1323 : fd_toml_parse_array( fd_toml_parser_t * parser ) {
867 1323 : uint key_len = parser->key_len;
868 :
869 1323 : EXPECT_CHAR( '[' );
870 168 : fd_toml_upsert_empty_pod( parser );
871 168 : SUB_PARSE( fd_toml_parse_array_values ( parser ) );
872 168 : SUB_PARSE( fd_toml_parse_ws_comment_newline( parser ) );
873 168 : EXPECT_CHAR( ']' );
874 :
875 168 : parser->key_len = key_len;
876 168 : parser->key[ key_len ] = 0;
877 :
878 168 : return 1;
879 168 : }
880 :
881 : /* inline-table-sep = ws %x2C ws ; , Comma */
882 :
883 : static int
884 0 : fd_toml_parse_inline_table_sep( fd_toml_parser_t * parser ) {
885 0 : fd_toml_parse_ws( parser );
886 0 : if( FD_UNLIKELY( !fd_toml_avail( parser ) ) ) return 0;
887 0 : if( FD_UNLIKELY( parser->c.data[0] != ',' ) ) return 0;
888 0 : fd_toml_advance_inline( parser, 1UL );
889 0 : fd_toml_parse_ws( parser );
890 0 : return 1;
891 0 : }
892 :
893 : /* inline-table-keyvals = keyval [ inline-table-sep inline-table-keyvals ] */
894 :
895 : static int
896 0 : fd_toml_parse_inline_table_keyvals( fd_toml_parser_t * parser ) {
897 :
898 : /* Unrolled tail recursion with backtracking */
899 :
900 0 : if( !fd_toml_parse_keyval( parser ) ) return 0;
901 0 : fd_toml_cur_t backtrack = parser->c;
902 0 : for(;;) {
903 0 : if( !fd_toml_parse_inline_table_sep( parser ) ) {
904 0 : parser->c = backtrack;
905 0 : break;
906 0 : }
907 0 : if( !fd_toml_parse_keyval( parser ) ) return 0;
908 0 : backtrack = parser->c;
909 0 : }
910 :
911 0 : return 1;
912 0 : }
913 :
914 : /* inline-table = inline-table-open [ inline-table-keyvals ] inline-table-close
915 :
916 : inline-table-open = %x7B ws ; {
917 : inline-table-close = ws %x7D ; } */
918 :
919 : static int
920 1155 : fd_toml_parse_inline_table( fd_toml_parser_t * parser ) {
921 :
922 1155 : EXPECT_CHAR( '{' );
923 0 : fd_toml_parse_ws( parser );
924 :
925 0 : uint old_key_len = parser->key_len;
926 0 : if( parser->key_len + 2 > sizeof(parser->key) ) {
927 0 : parser->error = FD_TOML_ERR_KEY;
928 0 : return 0;
929 0 : }
930 :
931 0 : parser->key[ parser->key_len ] = '\x00';
932 0 : fd_toml_upsert_empty_pod( parser );
933 :
934 0 : parser->key[ parser->key_len++ ] = '.';
935 0 : parser->key[ parser->key_len ] = '\x00';
936 :
937 0 : while( SUB_PARSE( fd_toml_parse_inline_table_keyvals( parser ) ) ) {}
938 :
939 0 : fd_toml_parse_ws( parser );
940 0 : EXPECT_CHAR( '}' );
941 :
942 0 : parser->key_len = old_key_len;
943 0 : parser->key[ old_key_len ] = '\x00';
944 0 : return 1;
945 0 : }
946 :
947 : /* dec-int = [ minus / plus ] unsigned-dec-int
948 : unsigned-dec-int = DIGIT / digit1-9 1*( DIGIT / underscore DIGIT ) */
949 :
950 : struct fd_toml_dec {
951 : ulong res;
952 : uint len;
953 : uchar neg : 1;
954 : };
955 :
956 : typedef struct fd_toml_dec fd_toml_dec_t;
957 :
958 : /* zero-prefixable-int = DIGIT *( DIGIT / underscore DIGIT )
959 :
960 : fd_toml_parse_zero_prefixable_int parses [0-9](_[0-9]|[0-9])*
961 : Assumes the first digit has been validated prior to call. */
962 :
963 : static int
964 : fd_toml_parse_zero_prefixable_int( fd_toml_parser_t * parser,
965 1917 : fd_toml_dec_t * dec ) {
966 :
967 1917 : uint len = 0U;
968 1917 : ulong digits = 0UL;
969 1917 : int allow_underscore = 0;
970 7392 : for(;;) {
971 7392 : if( FD_UNLIKELY( allow_underscore && parser->c.data[0] == '_' ) ) {
972 135 : allow_underscore = 0;
973 135 : fd_toml_advance_inline( parser, 1UL );
974 135 : if( FD_UNLIKELY( !fd_toml_avail( parser ) ) ) return 0;
975 135 : if( FD_UNLIKELY( !fd_isdigit( parser->c.data[0] ) ) ) return 0;
976 7257 : } else {
977 7257 : int digit = (uchar)parser->c.data[0];
978 7257 : if( FD_UNLIKELY(
979 7257 : __builtin_umull_overflow( digits, 10, &digits ) ||
980 7257 : __builtin_uaddl_overflow( digits, (ulong)( digit - '0' ), &digits ) ) ) {
981 0 : parser->error = FD_TOML_ERR_RANGE;
982 0 : return 0;
983 0 : }
984 7257 : len++;
985 7257 : fd_toml_advance_inline( parser, 1UL );
986 7257 : if( !fd_toml_avail( parser ) ) break;
987 7191 : if( !fd_isdigit( parser->c.data[0] ) && parser->c.data[0] != '_' ) break;
988 5340 : allow_underscore = 1;
989 5340 : }
990 7392 : }
991 :
992 1917 : dec->res = digits;
993 1917 : dec->len = len;
994 1917 : return 1;
995 1917 : }
996 :
997 : static int
998 : fd_toml_parse_dec_int_( fd_toml_parser_t * parser,
999 2262 : fd_toml_dec_t * dec ) {
1000 2262 : if( FD_UNLIKELY( !fd_toml_avail( parser ) ) ) return 0;
1001 2262 : int c = (uchar)parser->c.data[0];
1002 :
1003 2262 : int neg = 0;
1004 2262 : switch( c ) {
1005 9 : case '-':
1006 9 : neg = 1;
1007 9 : __attribute__((fallthrough));
1008 9 : case '+':
1009 9 : fd_toml_advance_inline( parser, 1UL );
1010 9 : break;
1011 2262 : }
1012 :
1013 2262 : if( FD_UNLIKELY( !fd_toml_avail( parser ) ) ) return 0;
1014 2262 : int first_digit = (uchar)parser->c.data[0];
1015 2262 : if( first_digit == '0' ) {
1016 177 : dec->res = 0UL;
1017 177 : dec->neg = !!neg;
1018 177 : fd_toml_advance_inline( parser, 1UL );
1019 177 : return 1;
1020 177 : }
1021 :
1022 2085 : if( FD_UNLIKELY( first_digit<='0' || first_digit>'9' ) ) return 0;
1023 :
1024 1863 : dec->neg = !!neg;
1025 1863 : return fd_toml_parse_zero_prefixable_int( parser, dec );
1026 2085 : }
1027 :
1028 : static int
1029 1107 : fd_toml_parse_dec_int( fd_toml_parser_t * parser ) {
1030 1107 : fd_toml_dec_t dec = {0};
1031 1107 : if( FD_UNLIKELY( !fd_toml_parse_dec_int_( parser, &dec ) ) ) return 0;
1032 996 : long val = (long)dec.res;
1033 996 : val = fd_long_if( dec.neg, -val, val );
1034 996 : if( FD_UNLIKELY( !fd_pod_insert_long( parser->pod, parser->key, val ) ) ) {
1035 0 : parser->error = FD_TOML_ERR_POD;
1036 0 : return 0;
1037 0 : }
1038 996 : return 1;
1039 996 : }
1040 :
1041 : /* hex-int = hex-prefix HEXDIG *( HEXDIG / underscore HEXDIG ) */
1042 :
1043 : static int
1044 1107 : fd_toml_parse_hex_int( fd_toml_parser_t * parser ) {
1045 1107 : if( FD_UNLIKELY( fd_toml_avail( parser ) < 3 ) ) return 0;
1046 1095 : if( FD_UNLIKELY( parser->c.data[0] != '0' ) ) return 0;
1047 78 : if( FD_UNLIKELY( parser->c.data[1] != 'x' ) ) return 0;
1048 0 : if( FD_UNLIKELY( !fd_isxdigit( parser->c.data[2] ) ) ) return 0; /* at least one digit */
1049 0 : fd_toml_advance_inline( parser, 2UL );
1050 :
1051 0 : ulong res = 0UL;
1052 0 : int allow_underscore = 0;
1053 0 : for(;;) {
1054 0 : int digit = (uchar)parser->c.data[0];
1055 0 : if( FD_UNLIKELY( allow_underscore && digit == '_' ) ) {
1056 0 : allow_underscore = 0;
1057 0 : fd_toml_advance_inline( parser, 1UL );
1058 0 : if( FD_UNLIKELY( !fd_toml_avail( parser ) ) ) return 0;
1059 0 : if( FD_UNLIKELY( !fd_isxdigit( parser->c.data[0] ) ) ) return 0;
1060 0 : } else {
1061 0 : if( !fd_isxdigit( digit ) ) break;
1062 0 : if( FD_UNLIKELY( res>>60 ) ) {
1063 0 : parser->error = FD_TOML_ERR_RANGE;
1064 0 : return 0;
1065 0 : }
1066 0 : res <<= 4;
1067 0 : res |= fd_toml_xdigit( digit );
1068 0 : fd_toml_advance_inline( parser, 1UL );
1069 0 : if( !fd_toml_avail( parser ) ) break;
1070 0 : allow_underscore = 1;
1071 0 : }
1072 0 : }
1073 :
1074 0 : if( FD_UNLIKELY( !fd_pod_insert_long( parser->pod, parser->key, (long)res ) ) ) {
1075 0 : parser->error = FD_TOML_ERR_POD;
1076 0 : return 0;
1077 0 : }
1078 :
1079 0 : return 1;
1080 0 : }
1081 :
1082 : /* oct-int = oct-prefix digit0-7 *( digit0-7 / underscore digit0-7 ) */
1083 :
1084 : static inline int
1085 0 : fd_toml_is_odigit( int c ) {
1086 0 : return c>='0' && c<'8';
1087 0 : }
1088 :
1089 : static int
1090 1107 : fd_toml_parse_oct_int( fd_toml_parser_t * parser ) {
1091 1107 : if( FD_UNLIKELY( fd_toml_avail( parser ) < 3 ) ) return 0;
1092 1095 : if( FD_UNLIKELY( parser->c.data[0] != '0' ) ) return 0;
1093 78 : if( FD_UNLIKELY( parser->c.data[1] != 'o' ) ) return 0;
1094 0 : if( FD_UNLIKELY( !fd_toml_is_odigit( parser->c.data[2] ) ) ) return 0; /* at least one digit */
1095 0 : fd_toml_advance_inline( parser, 2UL );
1096 :
1097 0 : ulong res = 0UL;
1098 0 : int allow_underscore = 0;
1099 0 : for(;;) {
1100 0 : int digit = (uchar)parser->c.data[0];
1101 0 : if( allow_underscore && digit == '_' ) {
1102 0 : allow_underscore = 0;
1103 0 : fd_toml_advance_inline( parser, 1UL );
1104 0 : if( FD_UNLIKELY( !fd_toml_avail( parser ) ) ) return 0;
1105 0 : if( FD_UNLIKELY( !fd_toml_is_odigit( parser->c.data[0] ) ) ) return 0;
1106 0 : } else {
1107 0 : if( !fd_toml_is_odigit( digit ) ) break;
1108 0 : if( FD_UNLIKELY( res>>61 ) ) {
1109 0 : parser->error = FD_TOML_ERR_RANGE;
1110 0 : return 0;
1111 0 : }
1112 0 : res <<= 3;
1113 0 : res |= (ulong)( digit - '0' );
1114 0 : fd_toml_advance_inline( parser, 1UL );
1115 0 : if( !fd_toml_avail( parser ) ) break;
1116 0 : allow_underscore = 1;
1117 0 : }
1118 0 : }
1119 :
1120 0 : if( FD_UNLIKELY( !fd_pod_insert_long( parser->pod, parser->key, (long)res ) ) ) {
1121 0 : parser->error = FD_TOML_ERR_POD;
1122 0 : return 0;
1123 0 : }
1124 :
1125 0 : return 1;
1126 0 : }
1127 :
1128 : /* bin-int = bin-prefix digit0-1 *( digit0-1 / underscore digit0-1 ) */
1129 :
1130 : static inline int
1131 0 : fd_toml_is_bdigit( int c ) {
1132 0 : return c=='0' || c=='1';
1133 0 : }
1134 :
1135 : static int
1136 1107 : fd_toml_parse_bin_int( fd_toml_parser_t * parser ) {
1137 1107 : if( FD_UNLIKELY( fd_toml_avail( parser ) < 3 ) ) return 0;
1138 1095 : if( FD_UNLIKELY( parser->c.data[0] != '0' ) ) return 0;
1139 78 : if( FD_UNLIKELY( parser->c.data[1] != 'b' ) ) return 0;
1140 0 : if( FD_UNLIKELY( !fd_toml_is_bdigit( parser->c.data[2] ) ) ) return 0; /* at least one digit */
1141 0 : fd_toml_advance_inline( parser, 2UL );
1142 :
1143 : /* TODO OVERFLOW DETECTION */
1144 :
1145 0 : ulong res = 0UL;
1146 0 : int allow_underscore = 0;
1147 0 : for(;;) {
1148 0 : int digit = (uchar)parser->c.data[0];
1149 0 : if( FD_UNLIKELY( allow_underscore && digit == '_' ) ) {
1150 0 : allow_underscore = 0;
1151 0 : fd_toml_advance_inline( parser, 1UL );
1152 0 : if( FD_UNLIKELY( !fd_toml_avail( parser ) ) ) return 0;
1153 0 : if( FD_UNLIKELY( !fd_toml_is_bdigit( parser->c.data[0] ) ) ) return 0;
1154 0 : } else {
1155 0 : if( !fd_toml_is_bdigit( digit ) ) break;
1156 0 : if( FD_UNLIKELY( res>>63 ) ) {
1157 0 : parser->error = FD_TOML_ERR_RANGE;
1158 0 : return 0;
1159 0 : }
1160 0 : res <<= 1;
1161 0 : res |= (ulong)( digit - '0' );
1162 0 : fd_toml_advance_inline( parser, 1UL );
1163 0 : if( !fd_toml_avail( parser ) ) break;
1164 0 : allow_underscore = 1;
1165 0 : }
1166 0 : }
1167 :
1168 0 : if( FD_UNLIKELY( !fd_pod_insert_long( parser->pod, parser->key, (long)res ) ) ) {
1169 0 : parser->error = FD_TOML_ERR_POD;
1170 0 : return 0;
1171 0 : }
1172 :
1173 0 : return 1;
1174 0 : }
1175 :
1176 : /* integer = dec-int / hex-int / oct-int / bin-int */
1177 :
1178 : static int
1179 1107 : fd_toml_parse_integer( fd_toml_parser_t * parser ) {
1180 1107 : if( SUB_PARSE( fd_toml_parse_hex_int( parser ) ) ) return 1;
1181 1107 : if( SUB_PARSE( fd_toml_parse_oct_int( parser ) ) ) return 1;
1182 1107 : if( SUB_PARSE( fd_toml_parse_bin_int( parser ) ) ) return 1;
1183 1107 : if( SUB_PARSE( fd_toml_parse_dec_int( parser ) ) ) return 1;
1184 111 : return 0;
1185 1107 : }
1186 :
1187 : /* exp = "e" float-exp-part
1188 : float-exp-part = [ minus / plus ] zero-prefixable-int */
1189 :
1190 : static int
1191 : fd_toml_parse_exp( fd_toml_parser_t * parser,
1192 1035 : fd_toml_dec_t * exp ) {
1193 1035 : if( FD_UNLIKELY( fd_toml_avail( parser ) < 2 ) ) return 0;
1194 990 : switch( parser->c.data[0] ) {
1195 9 : case 'e': case 'E': break;
1196 981 : default: return 0;
1197 990 : }
1198 9 : fd_toml_advance_inline( parser, 1UL );
1199 :
1200 9 : switch( parser->c.data[0] ) {
1201 3 : case '-':
1202 3 : exp->neg = 1;
1203 3 : __attribute__((fallthrough));
1204 3 : case '+':
1205 3 : fd_toml_advance_inline( parser, 1UL );
1206 3 : if( FD_UNLIKELY( !fd_toml_avail( parser ) ) ) return 0;
1207 3 : break;
1208 9 : }
1209 :
1210 9 : int first_digit = (uchar)parser->c.data[0];
1211 9 : if( FD_UNLIKELY( first_digit<'0' || first_digit>'9' ) ) return 0;
1212 9 : if( FD_UNLIKELY( !fd_toml_parse_zero_prefixable_int( parser, exp ) ) ) return 0;
1213 9 : return 1;
1214 9 : }
1215 :
1216 : /* frac = decimal-point zero-prefixable-int
1217 : decimal-point = %x2E */
1218 :
1219 : static int
1220 : fd_toml_parse_frac( fd_toml_parser_t * parser,
1221 1035 : fd_toml_dec_t * frac ) {
1222 1035 : if( FD_UNLIKELY( fd_toml_avail( parser ) < 2 ) ) return 0;
1223 1029 : if( FD_UNLIKELY( parser->c.data[0] != '.' ) ) return 0;
1224 45 : fd_toml_advance_inline( parser, 1UL );
1225 :
1226 45 : int first_digit = (uchar)parser->c.data[0];
1227 45 : if( FD_UNLIKELY( first_digit<'0' || first_digit>'9' ) ) return 0;
1228 45 : if( FD_UNLIKELY( !fd_toml_parse_zero_prefixable_int( parser, frac ) ) ) return 0;
1229 45 : return 1;
1230 45 : }
1231 :
1232 : /* float = float-int-part ( exp / frac [ exp ] )
1233 : float-int-part = dec-int */
1234 :
1235 : static int
1236 1155 : fd_toml_parse_float_normal( fd_toml_parser_t * parser ) {
1237 :
1238 1155 : fd_toml_dec_t stem = {0};
1239 1155 : if( FD_UNLIKELY( !fd_toml_parse_dec_int_( parser, &stem ) ) ) return 0;
1240 1044 : if( FD_UNLIKELY( !fd_toml_avail( parser ) ) ) return 0;
1241 1035 : float res = (float)stem.res;
1242 :
1243 1035 : int ok = 0;
1244 1035 : fd_toml_dec_t frac_dec = {0};
1245 1035 : if( SUB_PARSE( fd_toml_parse_frac( parser, &frac_dec ) ) ) {
1246 45 : float frac = (float)frac_dec.res;
1247 132 : while( frac_dec.len-- ) frac /= 10.0f; /* use pow? */
1248 45 : res += frac;
1249 45 : ok = 1;
1250 45 : }
1251 :
1252 1035 : fd_toml_dec_t exp_dec = {0};
1253 1035 : if( !SUB_PARSE( fd_toml_parse_exp( parser, &exp_dec ) ) ) {
1254 1026 : if( FD_LIKELY( ok ) ) goto parsed;
1255 987 : return 0;
1256 1026 : }
1257 :
1258 9 : float exp = powf( exp_dec.neg ? 0.1f : 10.0f, (float)exp_dec.res );
1259 9 : res *= exp;
1260 :
1261 48 : parsed:
1262 48 : if( stem.neg ) res = -res;
1263 48 : if( FD_UNLIKELY( !fd_pod_insert_float( parser->pod, parser->key, res ) ) ) {
1264 0 : parser->error = FD_TOML_ERR_POD;
1265 0 : return 0;
1266 0 : }
1267 48 : return 1;
1268 48 : }
1269 :
1270 : /* special-float = [ minus / plus ] ( inf / nan )
1271 : inf = %x69.6e.66 ; inf
1272 : nan = %x6e.61.6e ; nan */
1273 :
1274 : static int
1275 1107 : fd_float_parse_float_special( fd_toml_parser_t * parser ) {
1276 1107 : if( FD_UNLIKELY( fd_toml_avail( parser ) < 3 ) ) return 0;
1277 1095 : int c = (uchar)parser->c.data[0];
1278 :
1279 1095 : switch( c ) {
1280 0 : case '-': case '+':
1281 0 : fd_toml_advance_inline( parser, 1UL );
1282 0 : if( FD_UNLIKELY( fd_toml_avail( parser ) < 3 ) ) return 0;
1283 0 : break;
1284 1095 : }
1285 :
1286 1095 : char const * str = parser->c.data;
1287 1095 : fd_toml_advance_inline( parser, 3UL );
1288 :
1289 1095 : if( 0==strncasecmp( str, "inf", 3 ) ) {
1290 0 : FD_LOG_WARNING(( "TOML parse error: float infinity is unsupported" ));
1291 0 : parser->error = FD_TOML_ERR_RANGE;
1292 0 : return 0;
1293 0 : }
1294 :
1295 1095 : if( 0==strncasecmp( str, "nan", 3 ) ) {
1296 0 : FD_LOG_WARNING(( "TOML parse error: float NaN is unsupported" ));
1297 0 : parser->error = FD_TOML_ERR_RANGE;
1298 0 : return 1;
1299 0 : }
1300 :
1301 1095 : return 0;
1302 1095 : }
1303 :
1304 : /* float = float-int-part ( exp / frac [ exp ] )
1305 : float =/ special-float */
1306 :
1307 : static int
1308 1155 : fd_toml_parse_float( fd_toml_parser_t * parser ) {
1309 1155 : if( SUB_PARSE( fd_toml_parse_float_normal ( parser ) ) ) return 1;
1310 1107 : if( SUB_PARSE( fd_float_parse_float_special( parser ) ) ) return 1;
1311 1107 : return 0;
1312 1107 : }
1313 :
1314 : /* val = string / boolean / array / inline-table / float / integer */
1315 :
1316 : static int
1317 2592 : fd_toml_parse_val( fd_toml_parser_t * parser ) {
1318 : /* consider some lookahead for better performance */
1319 2592 : if( SUB_PARSE( fd_toml_parse_string ( parser ) ) ) return 1;
1320 1689 : if( SUB_PARSE( fd_toml_parse_boolean ( parser ) ) ) return 1;
1321 1323 : if( SUB_PARSE( fd_toml_parse_array ( parser ) ) ) return 1;
1322 1155 : if( SUB_PARSE( fd_toml_parse_inline_table( parser ) ) ) return 1;
1323 : // if( SUB_PARSE( fd_toml_parse_date_time ( parser ) ) ) return 1; /* not supported */
1324 : /* NOTE: float and integer have a common dec-int prefix -- dedup for better performance */
1325 1155 : if( SUB_PARSE( fd_toml_parse_float ( parser ) ) ) return 1;
1326 1107 : if( SUB_PARSE( fd_toml_parse_integer ( parser ) ) ) return 1;
1327 111 : return 0;
1328 1107 : }
1329 :
1330 : /* keyval = key keyval-sep val */
1331 :
1332 : static int
1333 25284 : fd_toml_parse_keyval( fd_toml_parser_t * parser ) {
1334 25284 : uint old_key_len = parser->key_len;
1335 25284 : if( FD_UNLIKELY( !SUB_PARSE( fd_toml_parse_key( parser ) ) ) ) return 0;
1336 :
1337 2424 : if( FD_UNLIKELY( fd_pod_query( parser->pod, parser->key, NULL )==FD_POD_SUCCESS ) ) {
1338 0 : FD_LOG_WARNING(( "TOML parse error: duplicate key: \"%s\"", parser->key ));
1339 0 : parser->error = FD_TOML_ERR_DUP;
1340 0 : return 0;
1341 0 : }
1342 :
1343 2424 : if( FD_UNLIKELY( !SUB_PARSE( fd_toml_parse_keyval_sep( parser ) ) ) ) return 0;
1344 2424 : if( FD_UNLIKELY( !SUB_PARSE( fd_toml_parse_val ( parser ) ) ) ) return 0;
1345 :
1346 2424 : FD_LOG_DEBUG(( "Added key %s", parser->key ));
1347 2424 : parser->key[ old_key_len ] = 0;
1348 2424 : parser->key_len = old_key_len;
1349 2424 : return 1;
1350 2424 : }
1351 :
1352 : /* std-table = std-table-open key std-table-close
1353 :
1354 : std-table-open = %x5B ws ; [ Left square bracket
1355 : std-table-close = ws %x5D ; ] Right square bracket */
1356 :
1357 : static int
1358 22860 : fd_toml_parse_std_table( fd_toml_parser_t * parser ) {
1359 22860 : EXPECT_CHAR( '[' );
1360 564 : fd_toml_parse_ws( parser );
1361 :
1362 564 : parser->key[ parser->key_len = 0 ] = 0;
1363 564 : if( FD_UNLIKELY( !fd_toml_parse_key( parser ) ) ) return 0;
1364 : // FIXME: consider blocking duplicate tables?
1365 : //if( FD_UNLIKELY( fd_pod_query( parser->pod, parser->key, NULL )==FD_POD_SUCCESS ) ) {
1366 : // FD_LOG_WARNING(( "Duplicate table: \"%s\"", parser->key ));
1367 : // parser->error = FD_TOML_ERR_DUP;
1368 : // return 0;
1369 : //}
1370 564 : FD_LOG_DEBUG(( "Added table %.*s", (int)parser->key_len, parser->key ));
1371 :
1372 564 : fd_toml_parse_ws( parser );
1373 564 : EXPECT_CHAR( ']' );
1374 564 : return 1;
1375 564 : }
1376 :
1377 : /* array-table = array-table = array-table-open key array-table-close
1378 :
1379 : array-table-open = %x5B.5B ws ; [[ Double left square bracket
1380 : array-table-close = ws %x5D.5D ; ]] Double right square bracket */
1381 :
1382 : static int
1383 22860 : fd_toml_parse_array_table( fd_toml_parser_t * parser ) {
1384 22860 : if( fd_toml_avail( parser ) < 2UL ) return 0;
1385 22836 : if( ( parser->c.data[0] != '[' ) |
1386 22836 : ( parser->c.data[1] != '[' ) ) return 0;
1387 0 : fd_toml_advance_inline( parser, 2UL );
1388 :
1389 0 : fd_toml_parse_ws( parser );
1390 :
1391 : /* Set parser->key to path to array */
1392 :
1393 0 : parser->key[ parser->key_len = 0 ] = 0;
1394 0 : if( FD_UNLIKELY( !SUB_PARSE( fd_toml_parse_key( parser ) ) ) ) return 0;
1395 :
1396 : /* Count number of predecessors */
1397 :
1398 0 : ulong idx = 0UL;
1399 0 : uchar const * subpod = fd_pod_query_subpod( parser->pod, parser->key );
1400 0 : if( subpod ) {
1401 0 : idx = fd_pod_cnt( subpod );
1402 0 : }
1403 :
1404 : /* Append array index to path */
1405 :
1406 0 : char * key_c = parser->key + parser->key_len;
1407 0 : if( FD_UNLIKELY( key_c + 22 > parser->key + sizeof(parser->key) ) ) {
1408 : /* array index might be OOB (see python3 -c 'print(len(str(1<<64)))') */
1409 0 : parser->error = FD_TOML_ERR_KEY;
1410 0 : return 0;
1411 0 : }
1412 0 : key_c = fd_cstr_append_char( key_c, '.' );
1413 0 : key_c = fd_cstr_append_ulong_as_text( key_c, 0, 0, idx, fd_ulong_base10_dig_cnt( idx ) );
1414 0 : fd_cstr_fini( key_c );
1415 0 : parser->key_len = (uint)( key_c - parser->key );
1416 :
1417 0 : FD_LOG_DEBUG(( "Added array table %.*s", (int)parser->key_len, parser->key ));
1418 :
1419 : /* Continue parsing */
1420 :
1421 0 : fd_toml_parse_ws( parser );
1422 :
1423 0 : if( FD_UNLIKELY( fd_toml_avail( parser ) < 2UL ) ) return 0;
1424 0 : if( FD_UNLIKELY( ( parser->c.data[0] != ']' ) |
1425 0 : ( parser->c.data[1] != ']' ) ) ) return 0;
1426 0 : fd_toml_advance_inline( parser, 2UL );
1427 0 : return 1;
1428 0 : }
1429 :
1430 : /* table = std-table / array-table */
1431 :
1432 : static int
1433 22860 : fd_toml_parse_table( fd_toml_parser_t * parser ) {
1434 22860 : if( SUB_PARSE( fd_toml_parse_array_table( parser ) ) ) goto add;
1435 22860 : if( SUB_PARSE( fd_toml_parse_std_table ( parser ) ) ) goto add;
1436 22296 : return 0;
1437 564 : add:
1438 564 : fd_toml_upsert_empty_pod( parser );
1439 : /* Add trailing dot */
1440 564 : if( parser->key_len + 2 > sizeof(parser->key) ) {
1441 0 : parser->error = FD_TOML_ERR_KEY;
1442 0 : return 0;
1443 0 : }
1444 564 : parser->key[ parser->key_len++ ] = '.';
1445 564 : parser->key[ parser->key_len ] = '\x00';
1446 564 : return 1;
1447 564 : }
1448 :
1449 : /* expression = ws [ comment ]
1450 : expression =/ ws keyval ws [ comment ]
1451 : expression =/ ws table ws [ comment ] */
1452 :
1453 : static int
1454 25284 : fd_toml_parse_expression( fd_toml_parser_t * parser ) {
1455 :
1456 25284 : fd_toml_parse_ws( parser );
1457 :
1458 25284 : if( FD_LIKELY( SUB_PARSE( fd_toml_parse_keyval( parser ) ) ) ) {
1459 2424 : fd_toml_parse_ws( parser );
1460 2424 : }
1461 22860 : else if( FD_LIKELY( SUB_PARSE( fd_toml_parse_table( parser ) ) ) ) {
1462 564 : fd_toml_parse_ws( parser );
1463 564 : }
1464 :
1465 25284 : SUB_PARSE( fd_toml_parse_comment( parser ) );
1466 25284 : return 1;
1467 25284 : }
1468 :
1469 : /* toml = expression *( newline expression ) */
1470 :
1471 : static int
1472 114 : fd_toml_parse_toml( fd_toml_parser_t * parser ) {
1473 :
1474 114 : if( FD_UNLIKELY( !fd_toml_parse_expression( parser ) ) ) return 0;
1475 :
1476 25284 : for(;;) {
1477 25284 : if( FD_UNLIKELY( parser->error ) ) break;
1478 25284 : if( FD_UNLIKELY( !fd_toml_avail( parser ) ) ) break;
1479 25170 : if( FD_UNLIKELY( parser->c.data[0] != '\n' ) ) break;
1480 25170 : fd_toml_advance( parser, 1UL );
1481 25170 : if( FD_UNLIKELY( !fd_toml_parse_expression( parser ) ) ) return 0;
1482 25170 : }
1483 :
1484 114 : return 1;
1485 114 : }
1486 :
1487 : int
1488 : fd_toml_parse( void const * toml,
1489 : ulong toml_sz,
1490 : uchar * pod,
1491 : uchar * scratch,
1492 : ulong scratch_sz,
1493 114 : fd_toml_err_info_t * opt_err ) {
1494 :
1495 114 : static fd_toml_err_info_t _dummy_err[1];
1496 114 : if( !opt_err ) opt_err = _dummy_err;
1497 114 : opt_err->line = 0UL;
1498 :
1499 114 : if( FD_UNLIKELY( !toml_sz ) ) return FD_TOML_SUCCESS;
1500 114 : if( FD_UNLIKELY( !scratch_sz ) ) {
1501 0 : FD_LOG_WARNING(( "zero scratch_sz" ));
1502 0 : return FD_TOML_ERR_SCRATCH;
1503 0 : }
1504 :
1505 114 : fd_toml_parser_t parser[1] = {{
1506 114 : .c = {
1507 114 : .data = toml,
1508 114 : .lineno = 1UL,
1509 114 : },
1510 114 : .data_end = (char const *)toml + toml_sz,
1511 114 : .pod = pod,
1512 114 : .scratch = scratch,
1513 114 : .scratch_cur = scratch,
1514 114 : .scratch_end = scratch + scratch_sz
1515 114 : }};
1516 :
1517 114 : int ok = fd_toml_parse_toml( parser );
1518 114 : opt_err->line = parser->c.lineno;
1519 :
1520 114 : if( FD_UNLIKELY( (!ok) | (fd_toml_avail( parser ) > 0) ) ) {
1521 0 : return fd_int_if( !!parser->error, parser->error, FD_TOML_ERR_PARSE );
1522 0 : }
1523 :
1524 114 : return FD_TOML_SUCCESS;
1525 114 : }
1526 :
1527 : FD_FN_CONST char const *
1528 0 : fd_toml_strerror( int err ) {
1529 0 : switch( err ) {
1530 0 : case FD_TOML_SUCCESS: return "success";
1531 0 : case FD_TOML_ERR_POD: return "out of memory in output pod";
1532 0 : case FD_TOML_ERR_SCRATCH: return "out of memory in scratch region";
1533 0 : case FD_TOML_ERR_KEY: return "oversize key";
1534 0 : case FD_TOML_ERR_DUP: return "duplicate key";
1535 0 : case FD_TOML_ERR_RANGE: return "integer overflow";
1536 0 : case FD_TOML_ERR_PARSE: return "parse failure";
1537 0 : default: return "unknown error";
1538 0 : }
1539 0 : }
|