MRTKLIB 0.7.14
Modernized GNSS Positioning Library
Loading...
Searching...
No Matches
toml.c
Go to the documentation of this file.
1/*
2
3 MIT License
4
5 Copyright (c) CK Tan
6 https://github.com/cktan/tomlc99
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in all
16 copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25
26*/
27#define _POSIX_C_SOURCE 200809L
28#include "toml.h"
29#include <assert.h>
30#include <ctype.h>
31#include <errno.h>
32#include <stdbool.h>
33#include <stdint.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37
38static void *(*ppmalloc)(size_t) = malloc;
39static void (*ppfree)(void *) = free;
40
41void toml_set_memutil(void *(*xxmalloc)(size_t), void (*xxfree)(void *)) {
42 if (xxmalloc)
43 ppmalloc = xxmalloc;
44 if (xxfree)
45 ppfree = xxfree;
46}
47
48#define ALIGN8(sz) (((sz) + 7) & ~7)
49#define MALLOC(a) ppmalloc(a)
50#define FREE(a) ppfree(a)
51
52#define malloc(x) error - forbidden - use MALLOC instead
53#define free(x) error - forbidden - use FREE instead
54#define calloc(x, y) error - forbidden - use CALLOC instead
55
56static void *CALLOC(size_t nmemb, size_t sz) {
57 int nb = ALIGN8(sz) * nmemb;
58 void *p = MALLOC(nb);
59 if (p) {
60 memset(p, 0, nb);
61 }
62 return p;
63}
64
65// some old platforms define strdup macro -- drop it.
66#undef strdup
67#define strdup(x) error - forbidden - use STRDUP instead
68
69static char *STRDUP(const char *s) {
70 int len = strlen(s);
71 char *p = MALLOC(len + 1);
72 if (p) {
73 memcpy(p, s, len);
74 p[len] = 0;
75 }
76 return p;
77}
78
79// some old platforms define strndup macro -- drop it.
80#undef strndup
81#define strndup(x) error - forbiden - use STRNDUP instead
82
83static char *STRNDUP(const char *s, size_t n) {
84 size_t len = strnlen(s, n);
85 char *p = MALLOC(len + 1);
86 if (p) {
87 memcpy(p, s, len);
88 p[len] = 0;
89 }
90 return p;
91}
92
93/**
94 * Convert a char in utf8 into UCS, and store it in *ret.
95 * Return #bytes consumed or -1 on failure.
96 */
97int toml_utf8_to_ucs(const char *orig, int len, int64_t *ret) {
98 const unsigned char *buf = (const unsigned char *)orig;
99 unsigned i = *buf++;
100 int64_t v;
101
102 /* 0x00000000 - 0x0000007F:
103 0xxxxxxx
104 */
105 if (0 == (i >> 7)) {
106 if (len < 1)
107 return -1;
108 v = i;
109 return *ret = v, 1;
110 }
111 /* 0x00000080 - 0x000007FF:
112 110xxxxx 10xxxxxx
113 */
114 if (0x6 == (i >> 5)) {
115 if (len < 2)
116 return -1;
117 v = i & 0x1f;
118 for (int j = 0; j < 1; j++) {
119 i = *buf++;
120 if (0x2 != (i >> 6))
121 return -1;
122 v = (v << 6) | (i & 0x3f);
123 }
124 return *ret = v, (const char *)buf - orig;
125 }
126
127 /* 0x00000800 - 0x0000FFFF:
128 1110xxxx 10xxxxxx 10xxxxxx
129 */
130 if (0xE == (i >> 4)) {
131 if (len < 3)
132 return -1;
133 v = i & 0x0F;
134 for (int j = 0; j < 2; j++) {
135 i = *buf++;
136 if (0x2 != (i >> 6))
137 return -1;
138 v = (v << 6) | (i & 0x3f);
139 }
140 return *ret = v, (const char *)buf - orig;
141 }
142
143 /* 0x00010000 - 0x001FFFFF:
144 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
145 */
146 if (0x1E == (i >> 3)) {
147 if (len < 4)
148 return -1;
149 v = i & 0x07;
150 for (int j = 0; j < 3; j++) {
151 i = *buf++;
152 if (0x2 != (i >> 6))
153 return -1;
154 v = (v << 6) | (i & 0x3f);
155 }
156 return *ret = v, (const char *)buf - orig;
157 }
158
159 /* 0x00200000 - 0x03FFFFFF:
160 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
161 */
162 if (0x3E == (i >> 2)) {
163 if (len < 5)
164 return -1;
165 v = i & 0x03;
166 for (int j = 0; j < 4; j++) {
167 i = *buf++;
168 if (0x2 != (i >> 6))
169 return -1;
170 v = (v << 6) | (i & 0x3f);
171 }
172 return *ret = v, (const char *)buf - orig;
173 }
174
175 /* 0x04000000 - 0x7FFFFFFF:
176 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
177 */
178 if (0x7e == (i >> 1)) {
179 if (len < 6)
180 return -1;
181 v = i & 0x01;
182 for (int j = 0; j < 5; j++) {
183 i = *buf++;
184 if (0x2 != (i >> 6))
185 return -1;
186 v = (v << 6) | (i & 0x3f);
187 }
188 return *ret = v, (const char *)buf - orig;
189 }
190 return -1;
191}
192
193/**
194 * Convert a UCS char to utf8 code, and return it in buf.
195 * Return #bytes used in buf to encode the char, or
196 * -1 on error.
197 */
198int toml_ucs_to_utf8(int64_t code, char buf[6]) {
199 /* http://stackoverflow.com/questions/6240055/manually-converting-unicode-codepoints-into-utf-8-and-utf-16
200 */
201 /* The UCS code values 0xd800–0xdfff (UTF-16 surrogates) as well
202 * as 0xfffe and 0xffff (UCS noncharacters) should not appear in
203 * conforming UTF-8 streams.
204 */
205 if (0xd800 <= code && code <= 0xdfff)
206 return -1;
207 if (0xfffe <= code && code <= 0xffff)
208 return -1;
209
210 /* 0x00000000 - 0x0000007F:
211 0xxxxxxx
212 */
213 if (code < 0)
214 return -1;
215 if (code <= 0x7F) {
216 buf[0] = (unsigned char)code;
217 return 1;
218 }
219
220 /* 0x00000080 - 0x000007FF:
221 110xxxxx 10xxxxxx
222 */
223 if (code <= 0x000007FF) {
224 buf[0] = (unsigned char)(0xc0 | (code >> 6));
225 buf[1] = (unsigned char)(0x80 | (code & 0x3f));
226 return 2;
227 }
228
229 /* 0x00000800 - 0x0000FFFF:
230 1110xxxx 10xxxxxx 10xxxxxx
231 */
232 if (code <= 0x0000FFFF) {
233 buf[0] = (unsigned char)(0xe0 | (code >> 12));
234 buf[1] = (unsigned char)(0x80 | ((code >> 6) & 0x3f));
235 buf[2] = (unsigned char)(0x80 | (code & 0x3f));
236 return 3;
237 }
238
239 /* 0x00010000 - 0x001FFFFF:
240 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
241 */
242 if (code <= 0x001FFFFF) {
243 buf[0] = (unsigned char)(0xf0 | (code >> 18));
244 buf[1] = (unsigned char)(0x80 | ((code >> 12) & 0x3f));
245 buf[2] = (unsigned char)(0x80 | ((code >> 6) & 0x3f));
246 buf[3] = (unsigned char)(0x80 | (code & 0x3f));
247 return 4;
248 }
249
250 /* 0x00200000 - 0x03FFFFFF:
251 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
252 */
253 if (code <= 0x03FFFFFF) {
254 buf[0] = (unsigned char)(0xf8 | (code >> 24));
255 buf[1] = (unsigned char)(0x80 | ((code >> 18) & 0x3f));
256 buf[2] = (unsigned char)(0x80 | ((code >> 12) & 0x3f));
257 buf[3] = (unsigned char)(0x80 | ((code >> 6) & 0x3f));
258 buf[4] = (unsigned char)(0x80 | (code & 0x3f));
259 return 5;
260 }
261
262 /* 0x04000000 - 0x7FFFFFFF:
263 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
264 */
265 if (code <= 0x7FFFFFFF) {
266 buf[0] = (unsigned char)(0xfc | (code >> 30));
267 buf[1] = (unsigned char)(0x80 | ((code >> 24) & 0x3f));
268 buf[2] = (unsigned char)(0x80 | ((code >> 18) & 0x3f));
269 buf[3] = (unsigned char)(0x80 | ((code >> 12) & 0x3f));
270 buf[4] = (unsigned char)(0x80 | ((code >> 6) & 0x3f));
271 buf[5] = (unsigned char)(0x80 | (code & 0x3f));
272 return 6;
273 }
274
275 return -1;
276}
277
278/*
279 * TOML has 3 data structures: value, array, table.
280 * Each of them can have identification key.
281 */
284 const char *key; /* key to this value */
285 const char *val; /* the raw value */
286};
287
290 int valtype; /* for value kind: 'i'nt, 'd'ouble, 'b'ool, 's'tring, 't'ime,
291 'D'ate, 'T'imestamp */
292 char *val;
295};
296
298 const char *key; /* key to this array */
299 int kind; /* element kind: 'v'alue, 'a'rray, or 't'able, 'm'ixed */
300 int type; /* for value kind: 'i'nt, 'd'ouble, 'b'ool, 's'tring, 't'ime,
301 'D'ate, 'T'imestamp, 'm'ixed */
302
303 int nitem; /* number of elements */
305};
306
308 const char *key; /* key to this table */
309 bool implicit; /* table was created implicitly */
310 bool readonly; /* no more modification allowed */
311
312 /* key-values in the table */
313 int nkval;
315
316 /* arrays in the table */
317 int narr;
319
320 /* tables in the table */
321 int ntab;
323};
324
325static inline void xfree(const void *x) {
326 if (x)
327 FREE((void *)(intptr_t)x);
328}
329
343
344typedef struct token_t token_t;
345struct token_t {
348 char *ptr; /* points into context->start */
349 int len;
350 int eof;
351};
352
353typedef struct context_t context_t;
354struct context_t {
355 char *start;
356 char *stop;
357 char *errbuf;
359
363
364 struct {
365 int top;
366 char *key[10];
367 token_t tok[10];
369};
370
371#define STRINGIFY(x) #x
372#define TOSTRING(x) STRINGIFY(x)
373#define FLINE __FILE__ ":" TOSTRING(__LINE__)
374
375static int next_token(context_t *ctx, int dotisspecial);
376
377/*
378 Error reporting. Call when an error is detected. Always return -1.
379*/
380static int e_outofmemory(context_t *ctx, const char *fline) {
381 snprintf(ctx->errbuf, ctx->errbufsz, "ERROR: out of memory (%s)", fline);
382 return -1;
383}
384
385static int e_internal(context_t *ctx, const char *fline) {
386 snprintf(ctx->errbuf, ctx->errbufsz, "internal error (%s)", fline);
387 return -1;
388}
389
390static int e_syntax(context_t *ctx, int lineno, const char *msg) {
391 snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, msg);
392 return -1;
393}
394
395static int e_badkey(context_t *ctx, int lineno) {
396 snprintf(ctx->errbuf, ctx->errbufsz, "line %d: bad key", lineno);
397 return -1;
398}
399
400static int e_keyexists(context_t *ctx, int lineno) {
401 snprintf(ctx->errbuf, ctx->errbufsz, "line %d: key exists", lineno);
402 return -1;
403}
404
405static int e_forbid(context_t *ctx, int lineno, const char *msg) {
406 snprintf(ctx->errbuf, ctx->errbufsz, "line %d: %s", lineno, msg);
407 return -1;
408}
409
410static void *expand(void *p, int sz, int newsz) {
411 void *s = MALLOC(newsz);
412 if (!s)
413 return 0;
414
415 if (p) {
416 memcpy(s, p, sz);
417 FREE(p);
418 }
419 return s;
420}
421
422static void **expand_ptrarr(void **p, int n) {
423 void **s = MALLOC((n + 1) * sizeof(void *));
424 if (!s)
425 return 0;
426
427 s[n] = 0;
428 if (p) {
429 memcpy(s, p, n * sizeof(void *));
430 FREE(p);
431 }
432 return s;
433}
434
436 toml_arritem_t *pp = expand(p, n * sizeof(*p), (n + 1) * sizeof(*p));
437 if (!pp)
438 return 0;
439
440 memset(&pp[n], 0, sizeof(pp[n]));
441 return pp;
442}
443
444static char *norm_lit_str(const char *src, int srclen, int multiline,
445 char *errbuf, int errbufsz) {
446 char *dst = 0; /* will write to dst[] and return it */
447 int max = 0; /* max size of dst[] */
448 int off = 0; /* cur offset in dst[] */
449 const char *sp = src;
450 const char *sq = src + srclen;
451 int ch;
452
453 /* scan forward on src */
454 for (;;) {
455 if (off >= max - 10) { /* have some slack for misc stuff */
456 int newmax = max + 50;
457 char *x = expand(dst, max, newmax);
458 if (!x) {
459 xfree(dst);
460 snprintf(errbuf, errbufsz, "out of memory");
461 return 0;
462 }
463 dst = x;
464 max = newmax;
465 }
466
467 /* finished? */
468 if (sp >= sq)
469 break;
470
471 ch = *sp++;
472 /* control characters other than tab is not allowed */
473 if ((0 <= ch && ch <= 0x08) || (0x0a <= ch && ch <= 0x1f) || (ch == 0x7f)) {
474 if (!(multiline && (ch == '\r' || ch == '\n'))) {
475 xfree(dst);
476 snprintf(errbuf, errbufsz, "invalid char U+%04x", ch);
477 return 0;
478 }
479 }
480
481 // a plain copy suffice
482 dst[off++] = ch;
483 }
484
485 dst[off++] = 0;
486 return dst;
487}
488
489/*
490 * Convert src to raw unescaped utf-8 string.
491 * Returns NULL if error with errmsg in errbuf.
492 */
493static char *norm_basic_str(const char *src, int srclen, int multiline,
494 char *errbuf, int errbufsz) {
495 char *dst = 0; /* will write to dst[] and return it */
496 int max = 0; /* max size of dst[] */
497 int off = 0; /* cur offset in dst[] */
498 const char *sp = src;
499 const char *sq = src + srclen;
500 int ch;
501
502 /* scan forward on src */
503 for (;;) {
504 if (off >= max - 10) { /* have some slack for misc stuff */
505 int newmax = max + 50;
506 char *x = expand(dst, max, newmax);
507 if (!x) {
508 xfree(dst);
509 snprintf(errbuf, errbufsz, "out of memory");
510 return 0;
511 }
512 dst = x;
513 max = newmax;
514 }
515
516 /* finished? */
517 if (sp >= sq)
518 break;
519
520 ch = *sp++;
521 if (ch != '\\') {
522 /* these chars must be escaped: U+0000 to U+0008, U+000A to U+001F, U+007F
523 */
524 if ((0 <= ch && ch <= 0x08) || (0x0a <= ch && ch <= 0x1f) ||
525 (ch == 0x7f)) {
526 if (!(multiline && (ch == '\r' || ch == '\n'))) {
527 xfree(dst);
528 snprintf(errbuf, errbufsz, "invalid char U+%04x", ch);
529 return 0;
530 }
531 }
532
533 // a plain copy suffice
534 dst[off++] = ch;
535 continue;
536 }
537
538 /* ch was backslash. we expect the escape char. */
539 if (sp >= sq) {
540 snprintf(errbuf, errbufsz, "last backslash is invalid");
541 xfree(dst);
542 return 0;
543 }
544
545 /* for multi-line, we want to kill line-ending-backslash ... */
546 if (multiline) {
547
548 // if there is only whitespace after the backslash ...
549 if (sp[strspn(sp, " \t\r")] == '\n') {
550 /* skip all the following whitespaces */
551 sp += strspn(sp, " \t\r\n");
552 continue;
553 }
554 }
555
556 /* get the escaped char */
557 ch = *sp++;
558 switch (ch) {
559 case 'u':
560 case 'U': {
561 int64_t ucs = 0;
562 int nhex = (ch == 'u' ? 4 : 8);
563 for (int i = 0; i < nhex; i++) {
564 if (sp >= sq) {
565 snprintf(errbuf, errbufsz, "\\%c expects %d hex chars", ch, nhex);
566 xfree(dst);
567 return 0;
568 }
569 ch = *sp++;
570 int v = ('0' <= ch && ch <= '9')
571 ? ch - '0'
572 : (('A' <= ch && ch <= 'F') ? ch - 'A' + 10 : -1);
573 if (-1 == v) {
574 snprintf(errbuf, errbufsz, "invalid hex chars for \\u or \\U");
575 xfree(dst);
576 return 0;
577 }
578 ucs = ucs * 16 + v;
579 }
580 int n = toml_ucs_to_utf8(ucs, &dst[off]);
581 if (-1 == n) {
582 snprintf(errbuf, errbufsz, "illegal ucs code in \\u or \\U");
583 xfree(dst);
584 return 0;
585 }
586 off += n;
587 }
588 continue;
589
590 case 'b':
591 ch = '\b';
592 break;
593 case 't':
594 ch = '\t';
595 break;
596 case 'n':
597 ch = '\n';
598 break;
599 case 'f':
600 ch = '\f';
601 break;
602 case 'r':
603 ch = '\r';
604 break;
605 case '"':
606 ch = '"';
607 break;
608 case '\\':
609 ch = '\\';
610 break;
611 default:
612 snprintf(errbuf, errbufsz, "illegal escape char \\%c", ch);
613 xfree(dst);
614 return 0;
615 }
616
617 dst[off++] = ch;
618 }
619
620 // Cap with NUL and return it.
621 dst[off++] = 0;
622 return dst;
623}
624
625/* Normalize a key. Convert all special chars to raw unescaped utf-8 chars. */
626static char *normalize_key(context_t *ctx, token_t strtok) {
627 const char *sp = strtok.ptr;
628 const char *sq = strtok.ptr + strtok.len;
629 int lineno = strtok.lineno;
630 char *ret;
631 int ch = *sp;
632 char ebuf[80];
633
634 /* handle quoted string */
635 if (ch == '\'' || ch == '\"') {
636 /* if ''' or """, take 3 chars off front and back. Else, take 1 char off. */
637 int multiline = 0;
638 if (sp[1] == ch && sp[2] == ch) {
639 sp += 3, sq -= 3;
640 multiline = 1;
641 } else
642 sp++, sq--;
643
644 if (ch == '\'') {
645 /* for single quote, take it verbatim. */
646 if (!(ret = STRNDUP(sp, sq - sp))) {
647 e_outofmemory(ctx, FLINE);
648 return 0;
649 }
650 } else {
651 /* for double quote, we need to normalize */
652 ret = norm_basic_str(sp, sq - sp, multiline, ebuf, sizeof(ebuf));
653 if (!ret) {
654 e_syntax(ctx, lineno, ebuf);
655 return 0;
656 }
657 }
658
659 /* newlines are not allowed in keys */
660 if (strchr(ret, '\n')) {
661 xfree(ret);
662 e_badkey(ctx, lineno);
663 return 0;
664 }
665 return ret;
666 }
667
668 /* for bare-key allow only this regex: [A-Za-z0-9_-]+ */
669 const char *xp;
670 for (xp = sp; xp != sq; xp++) {
671 int k = *xp;
672 if (isalnum(k))
673 continue;
674 if (k == '_' || k == '-')
675 continue;
676 e_badkey(ctx, lineno);
677 return 0;
678 }
679
680 /* dup and return it */
681 if (!(ret = STRNDUP(sp, sq - sp))) {
682 e_outofmemory(ctx, FLINE);
683 return 0;
684 }
685 return ret;
686}
687
688/*
689 * Look up key in tab. Return 0 if not found, or
690 * 'v'alue, 'a'rray or 't'able depending on the element.
691 */
692static int check_key(toml_table_t *tab, const char *key,
693 toml_keyval_t **ret_val, toml_array_t **ret_arr,
694 toml_table_t **ret_tab) {
695 int i;
696 void *dummy;
697
698 if (!ret_tab)
699 ret_tab = (toml_table_t **)&dummy;
700 if (!ret_arr)
701 ret_arr = (toml_array_t **)&dummy;
702 if (!ret_val)
703 ret_val = (toml_keyval_t **)&dummy;
704
705 *ret_tab = 0;
706 *ret_arr = 0;
707 *ret_val = 0;
708
709 for (i = 0; i < tab->nkval; i++) {
710 if (0 == strcmp(key, tab->kval[i]->key)) {
711 *ret_val = tab->kval[i];
712 return 'v';
713 }
714 }
715 for (i = 0; i < tab->narr; i++) {
716 if (0 == strcmp(key, tab->arr[i]->key)) {
717 *ret_arr = tab->arr[i];
718 return 'a';
719 }
720 }
721 for (i = 0; i < tab->ntab; i++) {
722 if (0 == strcmp(key, tab->tab[i]->key)) {
723 *ret_tab = tab->tab[i];
724 return 't';
725 }
726 }
727 return 0;
728}
729
730static int key_kind(toml_table_t *tab, const char *key) {
731 return check_key(tab, key, 0, 0, 0);
732}
733
734/* Create a keyval in the table.
735 */
737 token_t keytok) {
738 /* first, normalize the key to be used for lookup.
739 * remember to free it if we error out.
740 */
741 char *newkey = normalize_key(ctx, keytok);
742 if (!newkey)
743 return 0;
744
745 /* if key exists: error out. */
746 toml_keyval_t *dest = 0;
747 if (key_kind(tab, newkey)) {
748 xfree(newkey);
749 e_keyexists(ctx, keytok.lineno);
750 return 0;
751 }
752
753 /* make a new entry */
754 int n = tab->nkval;
755 toml_keyval_t **base;
756 if (0 == (base = (toml_keyval_t **)expand_ptrarr((void **)tab->kval, n))) {
757 xfree(newkey);
758 e_outofmemory(ctx, FLINE);
759 return 0;
760 }
761 tab->kval = base;
762
763 if (0 == (base[n] = (toml_keyval_t *)CALLOC(1, sizeof(*base[n])))) {
764 xfree(newkey);
765 e_outofmemory(ctx, FLINE);
766 return 0;
767 }
768 dest = tab->kval[tab->nkval++];
769
770 /* save the key in the new value struct */
771 dest->key = newkey;
772 return dest;
773}
774
775/* Create a table in the table.
776 */
778 token_t keytok) {
779 /* first, normalize the key to be used for lookup.
780 * remember to free it if we error out.
781 */
782 char *newkey = normalize_key(ctx, keytok);
783 if (!newkey)
784 return 0;
785
786 /* if key exists: error out */
787 toml_table_t *dest = 0;
788 if (check_key(tab, newkey, 0, 0, &dest)) {
789 xfree(newkey); /* don't need this anymore */
790
791 /* special case: if table exists, but was created implicitly ... */
792 if (dest && dest->implicit) {
793 /* we make it explicit now, and simply return it. */
794 dest->implicit = false;
795 return dest;
796 }
797 e_keyexists(ctx, keytok.lineno);
798 return 0;
799 }
800
801 /* create a new table entry */
802 int n = tab->ntab;
803 toml_table_t **base;
804 if (0 == (base = (toml_table_t **)expand_ptrarr((void **)tab->tab, n))) {
805 xfree(newkey);
806 e_outofmemory(ctx, FLINE);
807 return 0;
808 }
809 tab->tab = base;
810
811 if (0 == (base[n] = (toml_table_t *)CALLOC(1, sizeof(*base[n])))) {
812 xfree(newkey);
813 e_outofmemory(ctx, FLINE);
814 return 0;
815 }
816 dest = tab->tab[tab->ntab++];
817
818 /* save the key in the new table struct */
819 dest->key = newkey;
820 return dest;
821}
822
823/* Create an array in the table.
824 */
826 token_t keytok, char kind) {
827 /* first, normalize the key to be used for lookup.
828 * remember to free it if we error out.
829 */
830 char *newkey = normalize_key(ctx, keytok);
831 if (!newkey)
832 return 0;
833
834 /* if key exists: error out */
835 if (key_kind(tab, newkey)) {
836 xfree(newkey); /* don't need this anymore */
837 e_keyexists(ctx, keytok.lineno);
838 return 0;
839 }
840
841 /* make a new array entry */
842 int n = tab->narr;
843 toml_array_t **base;
844 if (0 == (base = (toml_array_t **)expand_ptrarr((void **)tab->arr, n))) {
845 xfree(newkey);
846 e_outofmemory(ctx, FLINE);
847 return 0;
848 }
849 tab->arr = base;
850
851 if (0 == (base[n] = (toml_array_t *)CALLOC(1, sizeof(*base[n])))) {
852 xfree(newkey);
853 e_outofmemory(ctx, FLINE);
854 return 0;
855 }
856 toml_array_t *dest = tab->arr[tab->narr++];
857
858 /* save the key in the new array struct */
859 dest->key = newkey;
860 dest->kind = kind;
861 return dest;
862}
863
865 toml_array_t *parent) {
866 const int n = parent->nitem;
867 toml_arritem_t *base = expand_arritem(parent->item, n);
868 if (!base) {
869 e_outofmemory(ctx, FLINE);
870 return 0;
871 }
872 parent->item = base;
873 parent->nitem++;
874 return &parent->item[n];
875}
876
877/* Create an array in an array
878 */
880 toml_array_t *parent) {
881 const int n = parent->nitem;
882 toml_arritem_t *base = expand_arritem(parent->item, n);
883 if (!base) {
884 e_outofmemory(ctx, FLINE);
885 return 0;
886 }
887 toml_array_t *ret = (toml_array_t *)CALLOC(1, sizeof(toml_array_t));
888 if (!ret) {
889 e_outofmemory(ctx, FLINE);
890 return 0;
891 }
892 base[n].arr = ret;
893 parent->item = base;
894 parent->nitem++;
895 return ret;
896}
897
898/* Create a table in an array
899 */
901 toml_array_t *parent) {
902 int n = parent->nitem;
903 toml_arritem_t *base = expand_arritem(parent->item, n);
904 if (!base) {
905 e_outofmemory(ctx, FLINE);
906 return 0;
907 }
908 toml_table_t *ret = (toml_table_t *)CALLOC(1, sizeof(toml_table_t));
909 if (!ret) {
910 e_outofmemory(ctx, FLINE);
911 return 0;
912 }
913 base[n].tab = ret;
914 parent->item = base;
915 parent->nitem++;
916 return ret;
917}
918
919static int skip_newlines(context_t *ctx, int isdotspecial) {
920 while (ctx->tok.tok == NEWLINE) {
921 if (next_token(ctx, isdotspecial))
922 return -1;
923 if (ctx->tok.eof)
924 break;
925 }
926 return 0;
927}
928
929static int parse_keyval(context_t *ctx, toml_table_t *tab);
930
931static inline int eat_token(context_t *ctx, tokentype_t typ, int isdotspecial,
932 const char *fline) {
933 if (ctx->tok.tok != typ)
934 return e_internal(ctx, fline);
935
936 if (next_token(ctx, isdotspecial))
937 return -1;
938
939 return 0;
940}
941
942/* We are at '{ ... }'.
943 * Parse the table.
944 */
946 if (eat_token(ctx, LBRACE, 1, FLINE))
947 return -1;
948
949 for (;;) {
950 if (ctx->tok.tok == NEWLINE)
951 return e_syntax(ctx, ctx->tok.lineno,
952 "newline not allowed in inline table");
953
954 /* until } */
955 if (ctx->tok.tok == RBRACE)
956 break;
957
958 if (ctx->tok.tok != STRING)
959 return e_syntax(ctx, ctx->tok.lineno, "expect a string");
960
961 if (parse_keyval(ctx, tab))
962 return -1;
963
964 if (ctx->tok.tok == NEWLINE)
965 return e_syntax(ctx, ctx->tok.lineno,
966 "newline not allowed in inline table");
967
968 /* on comma, continue to scan for next keyval */
969 if (ctx->tok.tok == COMMA) {
970 if (eat_token(ctx, COMMA, 1, FLINE))
971 return -1;
972 continue;
973 }
974 break;
975 }
976
977 if (eat_token(ctx, RBRACE, 1, FLINE))
978 return -1;
979
980 tab->readonly = 1;
981
982 return 0;
983}
984
985static int valtype(const char *val) {
987 if (*val == '\'' || *val == '"')
988 return 's';
989 if (0 == toml_rtob(val, 0))
990 return 'b';
991 if (0 == toml_rtoi(val, 0))
992 return 'i';
993 if (0 == toml_rtod(val, 0))
994 return 'd';
995 if (0 == toml_rtots(val, &ts)) {
996 if (ts.year && ts.hour)
997 return 'T'; /* timestamp */
998 if (ts.year)
999 return 'D'; /* date */
1000 return 't'; /* time */
1001 }
1002 return 'u'; /* unknown */
1003}
1004
1005/* We are at '[...]' */
1006static int parse_array(context_t *ctx, toml_array_t *arr) {
1007 if (eat_token(ctx, LBRACKET, 0, FLINE))
1008 return -1;
1009
1010 for (;;) {
1011 if (skip_newlines(ctx, 0))
1012 return -1;
1013
1014 /* until ] */
1015 if (ctx->tok.tok == RBRACKET)
1016 break;
1017
1018 switch (ctx->tok.tok) {
1019 case STRING: {
1020 /* set array kind if this will be the first entry */
1021 if (arr->kind == 0)
1022 arr->kind = 'v';
1023 else if (arr->kind != 'v')
1024 arr->kind = 'm';
1025
1026 char *val = ctx->tok.ptr;
1027 int vlen = ctx->tok.len;
1028
1029 /* make a new value in array */
1030 toml_arritem_t *newval = create_value_in_array(ctx, arr);
1031 if (!newval)
1032 return e_outofmemory(ctx, FLINE);
1033
1034 if (!(newval->val = STRNDUP(val, vlen)))
1035 return e_outofmemory(ctx, FLINE);
1036
1037 newval->valtype = valtype(newval->val);
1038
1039 /* set array type if this is the first entry */
1040 if (arr->nitem == 1)
1041 arr->type = newval->valtype;
1042 else if (arr->type != newval->valtype)
1043 arr->type = 'm'; /* mixed */
1044
1045 if (eat_token(ctx, STRING, 0, FLINE))
1046 return -1;
1047 break;
1048 }
1049
1050 case LBRACKET: { /* [ [array], [array] ... ] */
1051 /* set the array kind if this will be the first entry */
1052 if (arr->kind == 0)
1053 arr->kind = 'a';
1054 else if (arr->kind != 'a')
1055 arr->kind = 'm';
1056
1057 toml_array_t *subarr = create_array_in_array(ctx, arr);
1058 if (!subarr)
1059 return -1;
1060 if (parse_array(ctx, subarr))
1061 return -1;
1062 break;
1063 }
1064
1065 case LBRACE: { /* [ {table}, {table} ... ] */
1066 /* set the array kind if this will be the first entry */
1067 if (arr->kind == 0)
1068 arr->kind = 't';
1069 else if (arr->kind != 't')
1070 arr->kind = 'm';
1071
1072 toml_table_t *subtab = create_table_in_array(ctx, arr);
1073 if (!subtab)
1074 return -1;
1075 if (parse_inline_table(ctx, subtab))
1076 return -1;
1077 break;
1078 }
1079
1080 default:
1081 return e_syntax(ctx, ctx->tok.lineno, "syntax error");
1082 }
1083
1084 if (skip_newlines(ctx, 0))
1085 return -1;
1086
1087 /* on comma, continue to scan for next element */
1088 if (ctx->tok.tok == COMMA) {
1089 if (eat_token(ctx, COMMA, 0, FLINE))
1090 return -1;
1091 continue;
1092 }
1093 break;
1094 }
1095
1096 if (eat_token(ctx, RBRACKET, 1, FLINE))
1097 return -1;
1098 return 0;
1099}
1100
1101/* handle lines like these:
1102 key = "value"
1103 key = [ array ]
1104 key = { table }
1105*/
1106static int parse_keyval(context_t *ctx, toml_table_t *tab) {
1107 if (tab->readonly) {
1108 return e_forbid(ctx, ctx->tok.lineno,
1109 "cannot insert new entry into existing table");
1110 }
1111
1112 token_t key = ctx->tok;
1113 if (eat_token(ctx, STRING, 1, FLINE))
1114 return -1;
1115
1116 if (ctx->tok.tok == DOT) {
1117 /* handle inline dotted key.
1118 e.g.
1119 physical.color = "orange"
1120 physical.shape = "round"
1121 */
1122 toml_table_t *subtab = 0;
1123 {
1124 char *subtabstr = normalize_key(ctx, key);
1125 if (!subtabstr)
1126 return -1;
1127
1128 subtab = toml_table_in(tab, subtabstr);
1129 xfree(subtabstr);
1130 }
1131 if (!subtab) {
1132 subtab = create_keytable_in_table(ctx, tab, key);
1133 if (!subtab)
1134 return -1;
1135 }
1136 if (next_token(ctx, 1))
1137 return -1;
1138 if (parse_keyval(ctx, subtab))
1139 return -1;
1140 return 0;
1141 }
1142
1143 if (ctx->tok.tok != EQUAL) {
1144 return e_syntax(ctx, ctx->tok.lineno, "missing =");
1145 }
1146
1147 if (next_token(ctx, 0))
1148 return -1;
1149
1150 switch (ctx->tok.tok) {
1151 case STRING: { /* key = "value" */
1152 toml_keyval_t *keyval = create_keyval_in_table(ctx, tab, key);
1153 if (!keyval)
1154 return -1;
1155 token_t val = ctx->tok;
1156
1157 assert(keyval->val == 0);
1158 if (!(keyval->val = STRNDUP(val.ptr, val.len)))
1159 return e_outofmemory(ctx, FLINE);
1160
1161 if (next_token(ctx, 1))
1162 return -1;
1163
1164 return 0;
1165 }
1166
1167 case LBRACKET: { /* key = [ array ] */
1168 toml_array_t *arr = create_keyarray_in_table(ctx, tab, key, 0);
1169 if (!arr)
1170 return -1;
1171 if (parse_array(ctx, arr))
1172 return -1;
1173 return 0;
1174 }
1175
1176 case LBRACE: { /* key = { table } */
1177 toml_table_t *nxttab = create_keytable_in_table(ctx, tab, key);
1178 if (!nxttab)
1179 return -1;
1180 if (parse_inline_table(ctx, nxttab))
1181 return -1;
1182 return 0;
1183 }
1184
1185 default:
1186 return e_syntax(ctx, ctx->tok.lineno, "syntax error");
1187 }
1188 return 0;
1189}
1190
1191typedef struct tabpath_t tabpath_t;
1193 int cnt;
1195};
1196
1197/* at [x.y.z] or [[x.y.z]]
1198 * Scan forward and fill tabpath until it enters ] or ]]
1199 * There will be at least one entry on return.
1200 */
1201static int fill_tabpath(context_t *ctx) {
1202 int lineno = ctx->tok.lineno;
1203 int i;
1204
1205 /* clear tpath */
1206 for (i = 0; i < ctx->tpath.top; i++) {
1207 char **p = &ctx->tpath.key[i];
1208 xfree(*p);
1209 *p = 0;
1210 }
1211 ctx->tpath.top = 0;
1212
1213 for (;;) {
1214 if (ctx->tpath.top >= 10)
1215 return e_syntax(ctx, lineno,
1216 "table path is too deep; max allowed is 10.");
1217
1218 if (ctx->tok.tok != STRING)
1219 return e_syntax(ctx, lineno, "invalid or missing key");
1220
1221 char *key = normalize_key(ctx, ctx->tok);
1222 if (!key)
1223 return -1;
1224 ctx->tpath.tok[ctx->tpath.top] = ctx->tok;
1225 ctx->tpath.key[ctx->tpath.top] = key;
1226 ctx->tpath.top++;
1227
1228 if (next_token(ctx, 1))
1229 return -1;
1230
1231 if (ctx->tok.tok == RBRACKET)
1232 break;
1233
1234 if (ctx->tok.tok != DOT)
1235 return e_syntax(ctx, lineno, "invalid key");
1236
1237 if (next_token(ctx, 1))
1238 return -1;
1239 }
1240
1241 if (ctx->tpath.top <= 0)
1242 return e_syntax(ctx, lineno, "empty table selector");
1243
1244 return 0;
1245}
1246
1247/* Walk tabpath from the root, and create new tables on the way.
1248 * Sets ctx->curtab to the final table.
1249 */
1250static int walk_tabpath(context_t *ctx) {
1251 /* start from root */
1252 toml_table_t *curtab = ctx->root;
1253
1254 for (int i = 0; i < ctx->tpath.top; i++) {
1255 const char *key = ctx->tpath.key[i];
1256
1257 toml_keyval_t *nextval = 0;
1258 toml_array_t *nextarr = 0;
1259 toml_table_t *nexttab = 0;
1260 switch (check_key(curtab, key, &nextval, &nextarr, &nexttab)) {
1261 case 't':
1262 /* found a table. nexttab is where we will go next. */
1263 break;
1264
1265 case 'a':
1266 /* found an array. nexttab is the last table in the array. */
1267 if (nextarr->kind != 't')
1268 return e_internal(ctx, FLINE);
1269
1270 if (nextarr->nitem == 0)
1271 return e_internal(ctx, FLINE);
1272
1273 nexttab = nextarr->item[nextarr->nitem - 1].tab;
1274 break;
1275
1276 case 'v':
1277 return e_keyexists(ctx, ctx->tpath.tok[i].lineno);
1278
1279 default: { /* Not found. Let's create an implicit table. */
1280 int n = curtab->ntab;
1281 toml_table_t **base =
1282 (toml_table_t **)expand_ptrarr((void **)curtab->tab, n);
1283 if (0 == base)
1284 return e_outofmemory(ctx, FLINE);
1285
1286 curtab->tab = base;
1287
1288 if (0 == (base[n] = (toml_table_t *)CALLOC(1, sizeof(*base[n]))))
1289 return e_outofmemory(ctx, FLINE);
1290
1291 if (0 == (base[n]->key = STRDUP(key)))
1292 return e_outofmemory(ctx, FLINE);
1293
1294 nexttab = curtab->tab[curtab->ntab++];
1295
1296 /* tabs created by walk_tabpath are considered implicit */
1297 nexttab->implicit = true;
1298 } break;
1299 }
1300
1301 /* switch to next tab */
1302 curtab = nexttab;
1303 }
1304
1305 /* save it */
1306 ctx->curtab = curtab;
1307
1308 return 0;
1309}
1310
1311/* handle lines like [x.y.z] or [[x.y.z]] */
1312static int parse_select(context_t *ctx) {
1313 assert(ctx->tok.tok == LBRACKET);
1314
1315 /* true if [[ */
1316 int llb = (ctx->tok.ptr + 1 < ctx->stop && ctx->tok.ptr[1] == '[');
1317 /* need to detect '[[' on our own because next_token() will skip whitespace,
1318 and '[ [' would be taken as '[[', which is wrong. */
1319
1320 /* eat [ or [[ */
1321 if (eat_token(ctx, LBRACKET, 1, FLINE))
1322 return -1;
1323 if (llb) {
1324 assert(ctx->tok.tok == LBRACKET);
1325 if (eat_token(ctx, LBRACKET, 1, FLINE))
1326 return -1;
1327 }
1328
1329 if (fill_tabpath(ctx))
1330 return -1;
1331
1332 /* For [x.y.z] or [[x.y.z]], remove z from tpath.
1333 */
1334 token_t z = ctx->tpath.tok[ctx->tpath.top - 1];
1335 xfree(ctx->tpath.key[ctx->tpath.top - 1]);
1336 ctx->tpath.top--;
1337
1338 /* set up ctx->curtab */
1339 if (walk_tabpath(ctx))
1340 return -1;
1341
1342 if (!llb) {
1343 /* [x.y.z] -> create z = {} in x.y */
1344 toml_table_t *curtab = create_keytable_in_table(ctx, ctx->curtab, z);
1345 if (!curtab)
1346 return -1;
1347 ctx->curtab = curtab;
1348 } else {
1349 /* [[x.y.z]] -> create z = [] in x.y */
1350 toml_array_t *arr = 0;
1351 {
1352 char *zstr = normalize_key(ctx, z);
1353 if (!zstr)
1354 return -1;
1355 arr = toml_array_in(ctx->curtab, zstr);
1356 xfree(zstr);
1357 }
1358 if (!arr) {
1359 arr = create_keyarray_in_table(ctx, ctx->curtab, z, 't');
1360 if (!arr)
1361 return -1;
1362 }
1363 if (arr->kind != 't')
1364 return e_syntax(ctx, z.lineno, "array mismatch");
1365
1366 /* add to z[] */
1367 toml_table_t *dest;
1368 {
1369 toml_table_t *t = create_table_in_array(ctx, arr);
1370 if (!t)
1371 return -1;
1372
1373 if (0 == (t->key = STRDUP("__anon__")))
1374 return e_outofmemory(ctx, FLINE);
1375
1376 dest = t;
1377 }
1378
1379 ctx->curtab = dest;
1380 }
1381
1382 if (ctx->tok.tok != RBRACKET) {
1383 return e_syntax(ctx, ctx->tok.lineno, "expects ]");
1384 }
1385 if (llb) {
1386 if (!(ctx->tok.ptr + 1 < ctx->stop && ctx->tok.ptr[1] == ']')) {
1387 return e_syntax(ctx, ctx->tok.lineno, "expects ]]");
1388 }
1389 if (eat_token(ctx, RBRACKET, 1, FLINE))
1390 return -1;
1391 }
1392
1393 if (eat_token(ctx, RBRACKET, 1, FLINE))
1394 return -1;
1395
1396 if (ctx->tok.tok != NEWLINE)
1397 return e_syntax(ctx, ctx->tok.lineno, "extra chars after ] or ]]");
1398
1399 return 0;
1400}
1401
1402toml_table_t *toml_parse(char *conf, char *errbuf, int errbufsz) {
1403 context_t ctx;
1404
1405 // clear errbuf
1406 if (errbufsz <= 0)
1407 errbufsz = 0;
1408 if (errbufsz > 0)
1409 errbuf[0] = 0;
1410
1411 // init context
1412 memset(&ctx, 0, sizeof(ctx));
1413 ctx.start = conf;
1414 ctx.stop = ctx.start + strlen(conf);
1415 ctx.errbuf = errbuf;
1416 ctx.errbufsz = errbufsz;
1417
1418 // start with an artificial newline of length 0
1419 ctx.tok.tok = NEWLINE;
1420 ctx.tok.lineno = 1;
1421 ctx.tok.ptr = conf;
1422 ctx.tok.len = 0;
1423
1424 // make a root table
1425 if (0 == (ctx.root = CALLOC(1, sizeof(*ctx.root)))) {
1426 e_outofmemory(&ctx, FLINE);
1427 // Do not goto fail, root table not set up yet
1428 return 0;
1429 }
1430
1431 // set root as default table
1432 ctx.curtab = ctx.root;
1433
1434 /* Scan forward until EOF */
1435 for (token_t tok = ctx.tok; !tok.eof; tok = ctx.tok) {
1436 switch (tok.tok) {
1437
1438 case NEWLINE:
1439 if (next_token(&ctx, 1))
1440 goto fail;
1441 break;
1442
1443 case STRING:
1444 if (parse_keyval(&ctx, ctx.curtab))
1445 goto fail;
1446
1447 if (ctx.tok.tok != NEWLINE) {
1448 e_syntax(&ctx, ctx.tok.lineno, "extra chars after value");
1449 goto fail;
1450 }
1451
1452 if (eat_token(&ctx, NEWLINE, 1, FLINE))
1453 goto fail;
1454 break;
1455
1456 case LBRACKET: /* [ x.y.z ] or [[ x.y.z ]] */
1457 if (parse_select(&ctx))
1458 goto fail;
1459 break;
1460
1461 default:
1462 e_syntax(&ctx, tok.lineno, "syntax error");
1463 goto fail;
1464 }
1465 }
1466
1467 /* success */
1468 for (int i = 0; i < ctx.tpath.top; i++)
1469 xfree(ctx.tpath.key[i]);
1470 return ctx.root;
1471
1472fail:
1473 // Something bad has happened. Free resources and return error.
1474 for (int i = 0; i < ctx.tpath.top; i++)
1475 xfree(ctx.tpath.key[i]);
1476 toml_free(ctx.root);
1477 return 0;
1478}
1479
1480toml_table_t *toml_parse_file(FILE *fp, char *errbuf, int errbufsz) {
1481 int bufsz = 0;
1482 char *buf = 0;
1483 int off = 0;
1484
1485 /* read from fp into buf */
1486 while (!feof(fp)) {
1487
1488 if (off == bufsz) {
1489 int xsz = bufsz + 1000;
1490 char *x = expand(buf, bufsz, xsz);
1491 if (!x) {
1492 snprintf(errbuf, errbufsz, "out of memory");
1493 xfree(buf);
1494 return 0;
1495 }
1496 buf = x;
1497 bufsz = xsz;
1498 }
1499
1500 errno = 0;
1501 int n = fread(buf + off, 1, bufsz - off, fp);
1502 if (ferror(fp)) {
1503 snprintf(errbuf, errbufsz, "%s",
1504 errno ? strerror(errno) : "Error reading file");
1505 xfree(buf);
1506 return 0;
1507 }
1508 off += n;
1509 }
1510
1511 /* tag on a NUL to cap the string */
1512 if (off == bufsz) {
1513 int xsz = bufsz + 1;
1514 char *x = expand(buf, bufsz, xsz);
1515 if (!x) {
1516 snprintf(errbuf, errbufsz, "out of memory");
1517 xfree(buf);
1518 return 0;
1519 }
1520 buf = x;
1521 bufsz = xsz;
1522 }
1523 buf[off] = 0;
1524
1525 /* parse it, cleanup and finish */
1526 toml_table_t *ret = toml_parse(buf, errbuf, errbufsz);
1527 xfree(buf);
1528 return ret;
1529}
1530
1531static void xfree_kval(toml_keyval_t *p) {
1532 if (!p)
1533 return;
1534 xfree(p->key);
1535 xfree(p->val);
1536 xfree(p);
1537}
1538
1539static void xfree_tab(toml_table_t *p);
1540
1541static void xfree_arr(toml_array_t *p) {
1542 if (!p)
1543 return;
1544
1545 xfree(p->key);
1546 const int n = p->nitem;
1547 for (int i = 0; i < n; i++) {
1548 toml_arritem_t *a = &p->item[i];
1549 if (a->val)
1550 xfree(a->val);
1551 else if (a->arr)
1552 xfree_arr(a->arr);
1553 else if (a->tab)
1554 xfree_tab(a->tab);
1555 }
1556 xfree(p->item);
1557 xfree(p);
1558}
1559
1560static void xfree_tab(toml_table_t *p) {
1561 int i;
1562
1563 if (!p)
1564 return;
1565
1566 xfree(p->key);
1567
1568 for (i = 0; i < p->nkval; i++)
1569 xfree_kval(p->kval[i]);
1570 xfree(p->kval);
1571
1572 for (i = 0; i < p->narr; i++)
1573 xfree_arr(p->arr[i]);
1574 xfree(p->arr);
1575
1576 for (i = 0; i < p->ntab; i++)
1577 xfree_tab(p->tab[i]);
1578 xfree(p->tab);
1579
1580 xfree(p);
1581}
1582
1584
1585static void set_token(context_t *ctx, tokentype_t tok, int lineno, char *ptr,
1586 int len) {
1587 token_t t;
1588 t.tok = tok;
1589 t.lineno = lineno;
1590 t.ptr = ptr;
1591 t.len = len;
1592 t.eof = 0;
1593 ctx->tok = t;
1594}
1595
1596static void set_eof(context_t *ctx, int lineno) {
1597 set_token(ctx, NEWLINE, lineno, ctx->stop, 0);
1598 ctx->tok.eof = 1;
1599}
1600
1601/* Scan p for n digits compositing entirely of [0-9] */
1602static int scan_digits(const char *p, int n) {
1603 int ret = 0;
1604 for (; n > 0 && isdigit(*p); n--, p++) {
1605 ret = 10 * ret + (*p - '0');
1606 }
1607 return n ? -1 : ret;
1608}
1609
1610static int scan_date(const char *p, int *YY, int *MM, int *DD) {
1611 int year, month, day;
1612 year = scan_digits(p, 4);
1613 month = (year >= 0 && p[4] == '-') ? scan_digits(p + 5, 2) : -1;
1614 day = (month >= 0 && p[7] == '-') ? scan_digits(p + 8, 2) : -1;
1615 if (YY)
1616 *YY = year;
1617 if (MM)
1618 *MM = month;
1619 if (DD)
1620 *DD = day;
1621 return (year >= 0 && month >= 0 && day >= 0) ? 0 : -1;
1622}
1623
1624static int scan_time(const char *p, int *hh, int *mm, int *ss) {
1625 int hour, minute, second;
1626 hour = scan_digits(p, 2);
1627 minute = (hour >= 0 && p[2] == ':') ? scan_digits(p + 3, 2) : -1;
1628 second = (minute >= 0 && p[5] == ':') ? scan_digits(p + 6, 2) : -1;
1629 if (hh)
1630 *hh = hour;
1631 if (mm)
1632 *mm = minute;
1633 if (ss)
1634 *ss = second;
1635 return (hour >= 0 && minute >= 0 && second >= 0) ? 0 : -1;
1636}
1637
1638static int scan_string(context_t *ctx, char *p, int lineno, int dotisspecial) {
1639 char *orig = p;
1640 if (0 == strncmp(p, "'''", 3)) {
1641 char *q = p + 3;
1642
1643 while (1) {
1644 q = strstr(q, "'''");
1645 if (0 == q) {
1646 return e_syntax(ctx, lineno, "unterminated triple-s-quote");
1647 }
1648 while (q[3] == '\'')
1649 q++;
1650 break;
1651 }
1652
1653 set_token(ctx, STRING, lineno, orig, q + 3 - orig);
1654 return 0;
1655 }
1656
1657 if (0 == strncmp(p, "\"\"\"", 3)) {
1658 char *q = p + 3;
1659
1660 while (1) {
1661 q = strstr(q, "\"\"\"");
1662 if (0 == q) {
1663 return e_syntax(ctx, lineno, "unterminated triple-d-quote");
1664 }
1665 if (q[-1] == '\\') {
1666 q++;
1667 continue;
1668 }
1669 while (q[3] == '\"')
1670 q++;
1671 break;
1672 }
1673
1674 // the string is [p+3, q-1]
1675
1676 int hexreq = 0; /* #hex required */
1677 int escape = 0;
1678 for (p += 3; p < q; p++) {
1679 if (escape) {
1680 escape = 0;
1681 if (strchr("btnfr\"\\", *p))
1682 continue;
1683 if (*p == 'u') {
1684 hexreq = 4;
1685 continue;
1686 }
1687 if (*p == 'U') {
1688 hexreq = 8;
1689 continue;
1690 }
1691 if (p[strspn(p, " \t\r")] == '\n')
1692 continue; /* allow for line ending backslash */
1693 return e_syntax(ctx, lineno, "bad escape char");
1694 }
1695 if (hexreq) {
1696 hexreq--;
1697 if (strchr("0123456789ABCDEF", *p))
1698 continue;
1699 return e_syntax(ctx, lineno, "expect hex char");
1700 }
1701 if (*p == '\\') {
1702 escape = 1;
1703 continue;
1704 }
1705 }
1706 if (escape)
1707 return e_syntax(ctx, lineno, "expect an escape char");
1708 if (hexreq)
1709 return e_syntax(ctx, lineno, "expected more hex char");
1710
1711 set_token(ctx, STRING, lineno, orig, q + 3 - orig);
1712 return 0;
1713 }
1714
1715 if ('\'' == *p) {
1716 for (p++; *p && *p != '\n' && *p != '\''; p++)
1717 ;
1718 if (*p != '\'') {
1719 return e_syntax(ctx, lineno, "unterminated s-quote");
1720 }
1721
1722 set_token(ctx, STRING, lineno, orig, p + 1 - orig);
1723 return 0;
1724 }
1725
1726 if ('\"' == *p) {
1727 int hexreq = 0; /* #hex required */
1728 int escape = 0;
1729 for (p++; *p; p++) {
1730 if (escape) {
1731 escape = 0;
1732 if (strchr("btnfr\"\\", *p))
1733 continue;
1734 if (*p == 'u') {
1735 hexreq = 4;
1736 continue;
1737 }
1738 if (*p == 'U') {
1739 hexreq = 8;
1740 continue;
1741 }
1742 return e_syntax(ctx, lineno, "bad escape char");
1743 }
1744 if (hexreq) {
1745 hexreq--;
1746 if (strchr("0123456789ABCDEF", *p))
1747 continue;
1748 return e_syntax(ctx, lineno, "expect hex char");
1749 }
1750 if (*p == '\\') {
1751 escape = 1;
1752 continue;
1753 }
1754 if (*p == '\'') {
1755 if (p[1] == '\'' && p[2] == '\'') {
1756 return e_syntax(ctx, lineno, "triple-s-quote inside string lit");
1757 }
1758 continue;
1759 }
1760 if (*p == '\n')
1761 break;
1762 if (*p == '"')
1763 break;
1764 }
1765 if (*p != '"') {
1766 return e_syntax(ctx, lineno, "unterminated quote");
1767 }
1768
1769 set_token(ctx, STRING, lineno, orig, p + 1 - orig);
1770 return 0;
1771 }
1772
1773 /* check for timestamp without quotes */
1774 if (0 == scan_date(p, 0, 0, 0) || 0 == scan_time(p, 0, 0, 0)) {
1775 // forward thru the timestamp
1776 p += strspn(p, "0123456789.:+-Tt Zz");
1777 // squeeze out any spaces at end of string
1778 for (; p[-1] == ' '; p--)
1779 ;
1780 // tokenize
1781 set_token(ctx, STRING, lineno, orig, p - orig);
1782 return 0;
1783 }
1784
1785 /* literals */
1786 for (; *p && *p != '\n'; p++) {
1787 int ch = *p;
1788 if (ch == '.' && dotisspecial)
1789 break;
1790 if ('A' <= ch && ch <= 'Z')
1791 continue;
1792 if ('a' <= ch && ch <= 'z')
1793 continue;
1794 if (strchr("0123456789+-_.", ch))
1795 continue;
1796 break;
1797 }
1798
1799 set_token(ctx, STRING, lineno, orig, p - orig);
1800 return 0;
1801}
1802
1803static int next_token(context_t *ctx, int dotisspecial) {
1804 int lineno = ctx->tok.lineno;
1805 char *p = ctx->tok.ptr;
1806 int i;
1807
1808 /* eat this tok */
1809 for (i = 0; i < ctx->tok.len; i++) {
1810 if (*p++ == '\n')
1811 lineno++;
1812 }
1813
1814 /* make next tok */
1815 while (p < ctx->stop) {
1816 /* skip comment. stop just before the \n. */
1817 if (*p == '#') {
1818 for (p++; p < ctx->stop && *p != '\n'; p++)
1819 ;
1820 continue;
1821 }
1822
1823 if (dotisspecial && *p == '.') {
1824 set_token(ctx, DOT, lineno, p, 1);
1825 return 0;
1826 }
1827
1828 switch (*p) {
1829 case ',':
1830 set_token(ctx, COMMA, lineno, p, 1);
1831 return 0;
1832 case '=':
1833 set_token(ctx, EQUAL, lineno, p, 1);
1834 return 0;
1835 case '{':
1836 set_token(ctx, LBRACE, lineno, p, 1);
1837 return 0;
1838 case '}':
1839 set_token(ctx, RBRACE, lineno, p, 1);
1840 return 0;
1841 case '[':
1842 set_token(ctx, LBRACKET, lineno, p, 1);
1843 return 0;
1844 case ']':
1845 set_token(ctx, RBRACKET, lineno, p, 1);
1846 return 0;
1847 case '\n':
1848 set_token(ctx, NEWLINE, lineno, p, 1);
1849 return 0;
1850 case '\r':
1851 case ' ':
1852 case '\t':
1853 /* ignore white spaces */
1854 p++;
1855 continue;
1856 }
1857
1858 return scan_string(ctx, p, lineno, dotisspecial);
1859 }
1860
1861 set_eof(ctx, lineno);
1862 return 0;
1863}
1864
1865const char *toml_key_in(const toml_table_t *tab, int keyidx) {
1866 if (keyidx < tab->nkval)
1867 return tab->kval[keyidx]->key;
1868
1869 keyidx -= tab->nkval;
1870 if (keyidx < tab->narr)
1871 return tab->arr[keyidx]->key;
1872
1873 keyidx -= tab->narr;
1874 if (keyidx < tab->ntab)
1875 return tab->tab[keyidx]->key;
1876
1877 return 0;
1878}
1879
1880int toml_key_exists(const toml_table_t *tab, const char *key) {
1881 int i;
1882 for (i = 0; i < tab->nkval; i++) {
1883 if (0 == strcmp(key, tab->kval[i]->key))
1884 return 1;
1885 }
1886 for (i = 0; i < tab->narr; i++) {
1887 if (0 == strcmp(key, tab->arr[i]->key))
1888 return 1;
1889 }
1890 for (i = 0; i < tab->ntab; i++) {
1891 if (0 == strcmp(key, tab->tab[i]->key))
1892 return 1;
1893 }
1894 return 0;
1895}
1896
1897toml_raw_t toml_raw_in(const toml_table_t *tab, const char *key) {
1898 int i;
1899 for (i = 0; i < tab->nkval; i++) {
1900 if (0 == strcmp(key, tab->kval[i]->key))
1901 return tab->kval[i]->val;
1902 }
1903 return 0;
1904}
1905
1906toml_array_t *toml_array_in(const toml_table_t *tab, const char *key) {
1907 int i;
1908 for (i = 0; i < tab->narr; i++) {
1909 if (0 == strcmp(key, tab->arr[i]->key))
1910 return tab->arr[i];
1911 }
1912 return 0;
1913}
1914
1915toml_table_t *toml_table_in(const toml_table_t *tab, const char *key) {
1916 int i;
1917 for (i = 0; i < tab->ntab; i++) {
1918 if (0 == strcmp(key, tab->tab[i]->key))
1919 return tab->tab[i];
1920 }
1921 return 0;
1922}
1923
1925 return (0 <= idx && idx < arr->nitem) ? arr->item[idx].val : 0;
1926}
1927
1928char toml_array_kind(const toml_array_t *arr) { return arr->kind; }
1929
1931 if (arr->kind != 'v')
1932 return 0;
1933
1934 if (arr->nitem == 0)
1935 return 0;
1936
1937 return arr->type;
1938}
1939
1940int toml_array_nelem(const toml_array_t *arr) { return arr->nitem; }
1941
1942const char *toml_array_key(const toml_array_t *arr) {
1943 return arr ? arr->key : (const char *)NULL;
1944}
1945
1946int toml_table_nkval(const toml_table_t *tab) { return tab->nkval; }
1947
1948int toml_table_narr(const toml_table_t *tab) { return tab->narr; }
1949
1950int toml_table_ntab(const toml_table_t *tab) { return tab->ntab; }
1951
1952const char *toml_table_key(const toml_table_t *tab) {
1953 return tab ? tab->key : (const char *)NULL;
1954}
1955
1957 return (0 <= idx && idx < arr->nitem) ? arr->item[idx].arr : 0;
1958}
1959
1961 return (0 <= idx && idx < arr->nitem) ? arr->item[idx].tab : 0;
1962}
1963
1964static int parse_millisec(const char *p, const char **endp);
1965
1967 if (!src_)
1968 return -1;
1969
1970 const char *p = src_;
1971 int must_parse_time = 0;
1972
1973 memset(ret, 0, sizeof(*ret));
1974
1975 int *year = &ret->__buffer.year;
1976 int *month = &ret->__buffer.month;
1977 int *day = &ret->__buffer.day;
1978 int *hour = &ret->__buffer.hour;
1979 int *minute = &ret->__buffer.minute;
1980 int *second = &ret->__buffer.second;
1981 int *millisec = &ret->__buffer.millisec;
1982
1983 /* parse date YYYY-MM-DD */
1984 if (0 == scan_date(p, year, month, day)) {
1985 ret->year = year;
1986 ret->month = month;
1987 ret->day = day;
1988
1989 p += 10;
1990 if (*p) {
1991 // parse the T or space separator
1992 if (*p != 'T' && *p != 't' && *p != ' ')
1993 return -1;
1994 must_parse_time = 1;
1995 p++;
1996 }
1997 }
1998
1999 /* parse time HH:MM:SS */
2000 if (0 == scan_time(p, hour, minute, second)) {
2001 ret->hour = hour;
2002 ret->minute = minute;
2003 ret->second = second;
2004
2005 /* optionally, parse millisec */
2006 p += 8;
2007 if (*p == '.') {
2008 p++; /* skip '.' */
2009 const char *qq;
2010 *millisec = parse_millisec(p, &qq);
2011 ret->millisec = millisec;
2012 p = qq;
2013 }
2014
2015 if (*p) {
2016 /* parse and copy Z */
2017 char *z = ret->__buffer.z;
2018 ret->z = z;
2019 if (*p == 'Z' || *p == 'z') {
2020 *z++ = 'Z';
2021 p++;
2022 *z = 0;
2023
2024 } else if (*p == '+' || *p == '-') {
2025 *z++ = *p++;
2026
2027 if (!(isdigit(p[0]) && isdigit(p[1])))
2028 return -1;
2029 *z++ = *p++;
2030 *z++ = *p++;
2031
2032 if (*p == ':') {
2033 *z++ = *p++;
2034
2035 if (!(isdigit(p[0]) && isdigit(p[1])))
2036 return -1;
2037 *z++ = *p++;
2038 *z++ = *p++;
2039 }
2040
2041 *z = 0;
2042 }
2043 }
2044 }
2045 if (*p != 0)
2046 return -1;
2047
2048 if (must_parse_time && !ret->hour)
2049 return -1;
2050
2051 return 0;
2052}
2053
2054/* Raw to boolean */
2055int toml_rtob(toml_raw_t src, int *ret_) {
2056 if (!src)
2057 return -1;
2058 int dummy;
2059 int *ret = ret_ ? ret_ : &dummy;
2060
2061 if (0 == strcmp(src, "true")) {
2062 *ret = 1;
2063 return 0;
2064 }
2065 if (0 == strcmp(src, "false")) {
2066 *ret = 0;
2067 return 0;
2068 }
2069 return -1;
2070}
2071
2072/* Raw to integer */
2073int toml_rtoi(toml_raw_t src, int64_t *ret_) {
2074 if (!src)
2075 return -1;
2076
2077 char buf[100];
2078 char *p = buf;
2079 char *q = p + sizeof(buf);
2080 const char *s = src;
2081 int base = 0;
2082 int64_t dummy;
2083 int64_t *ret = ret_ ? ret_ : &dummy;
2084
2085 /* allow +/- */
2086 if (s[0] == '+' || s[0] == '-')
2087 *p++ = *s++;
2088
2089 /* disallow +_100 */
2090 if (s[0] == '_')
2091 return -1;
2092
2093 /* if 0* ... */
2094 if ('0' == s[0]) {
2095 switch (s[1]) {
2096 case 'x':
2097 base = 16;
2098 s += 2;
2099 break;
2100 case 'o':
2101 base = 8;
2102 s += 2;
2103 break;
2104 case 'b':
2105 base = 2;
2106 s += 2;
2107 break;
2108 case '\0':
2109 return *ret = 0, 0;
2110 default:
2111 /* ensure no other digits after it */
2112 if (s[1])
2113 return -1;
2114 }
2115 }
2116
2117 /* just strip underscores and pass to strtoll */
2118 while (*s && p < q) {
2119 int ch = *s++;
2120 if (ch == '_') {
2121 // disallow '__'
2122 if (s[0] == '_')
2123 return -1;
2124 // numbers cannot end with '_'
2125 if (s[0] == '\0')
2126 return -1;
2127 continue; /* skip _ */
2128 }
2129 *p++ = ch;
2130 }
2131
2132 // if not at end-of-string or we ran out of buffer ...
2133 if (*s || p == q)
2134 return -1;
2135
2136 /* cap with NUL */
2137 *p = 0;
2138
2139 /* Run strtoll on buf to get the integer */
2140 char *endp;
2141 errno = 0;
2142 *ret = strtoll(buf, &endp, base);
2143 return (errno || *endp) ? -1 : 0;
2144}
2145
2146int toml_rtod_ex(toml_raw_t src, double *ret_, char *buf, int buflen) {
2147 if (!src)
2148 return -1;
2149
2150 char *p = buf;
2151 char *q = p + buflen;
2152 const char *s = src;
2153 double dummy;
2154 double *ret = ret_ ? ret_ : &dummy;
2155
2156 /* allow +/- */
2157 if (s[0] == '+' || s[0] == '-')
2158 *p++ = *s++;
2159
2160 /* disallow +_1.00 */
2161 if (s[0] == '_')
2162 return -1;
2163
2164 /* decimal point, if used, must be surrounded by at least one digit on each
2165 * side */
2166 {
2167 char *dot = strchr(s, '.');
2168 if (dot) {
2169 if (dot == s || !isdigit(dot[-1]) || !isdigit(dot[1]))
2170 return -1;
2171 }
2172 }
2173
2174 /* zero must be followed by . or 'e', or NUL */
2175 if (s[0] == '0' && s[1] && !strchr("eE.", s[1]))
2176 return -1;
2177
2178 /* just strip underscores and pass to strtod */
2179 while (*s && p < q) {
2180 int ch = *s++;
2181 if (ch == '_') {
2182 // disallow '__'
2183 if (s[0] == '_')
2184 return -1;
2185 // disallow last char '_'
2186 if (s[0] == 0)
2187 return -1;
2188 continue; /* skip _ */
2189 }
2190 *p++ = ch;
2191 }
2192 if (*s || p == q)
2193 return -1; /* reached end of string or buffer is full? */
2194
2195 /* cap with NUL */
2196 *p = 0;
2197
2198 /* Run strtod on buf to get the value */
2199 char *endp;
2200 errno = 0;
2201 *ret = strtod(buf, &endp);
2202 return (errno || *endp) ? -1 : 0;
2203}
2204
2205int toml_rtod(toml_raw_t src, double *ret_) {
2206 char buf[100];
2207 return toml_rtod_ex(src, ret_, buf, sizeof(buf));
2208}
2209
2210int toml_rtos(toml_raw_t src, char **ret) {
2211 int multiline = 0;
2212 const char *sp;
2213 const char *sq;
2214
2215 *ret = 0;
2216 if (!src)
2217 return -1;
2218
2219 // for strings, first char must be a s-quote or d-quote
2220 int qchar = src[0];
2221 int srclen = strlen(src);
2222 if (!(qchar == '\'' || qchar == '"')) {
2223 return -1;
2224 }
2225
2226 // triple quotes?
2227 if (qchar == src[1] && qchar == src[2]) {
2228 multiline = 1; // triple-quote implies multiline
2229 sp = src + 3; // first char after quote
2230 sq = src + srclen - 3; // first char of ending quote
2231
2232 if (!(sp <= sq && sq[0] == qchar && sq[1] == qchar && sq[2] == qchar)) {
2233 // last 3 chars in src must be qchar
2234 return -1;
2235 }
2236
2237 /* skip new line immediate after qchar */
2238 if (sp[0] == '\n')
2239 sp++;
2240 else if (sp[0] == '\r' && sp[1] == '\n')
2241 sp += 2;
2242
2243 } else {
2244 sp = src + 1; // first char after quote
2245 sq = src + srclen - 1; // ending quote
2246 if (!(sp <= sq && *sq == qchar)) {
2247 /* last char in src must be qchar */
2248 return -1;
2249 }
2250 }
2251
2252 // at this point:
2253 // sp points to first valid char after quote.
2254 // sq points to one char beyond last valid char.
2255 // string len is (sq - sp).
2256 if (qchar == '\'') {
2257 *ret = norm_lit_str(sp, sq - sp, multiline, 0, 0);
2258 } else {
2259 *ret = norm_basic_str(sp, sq - sp, multiline, 0, 0);
2260 }
2261
2262 return *ret ? 0 : -1;
2263}
2264
2266 toml_datum_t ret;
2267 memset(&ret, 0, sizeof(ret));
2268 ret.ok = (0 == toml_rtos(toml_raw_at(arr, idx), &ret.u.s));
2269 return ret;
2270}
2271
2273 toml_datum_t ret;
2274 memset(&ret, 0, sizeof(ret));
2275 ret.ok = (0 == toml_rtob(toml_raw_at(arr, idx), &ret.u.b));
2276 return ret;
2277}
2278
2280 toml_datum_t ret;
2281 memset(&ret, 0, sizeof(ret));
2282 ret.ok = (0 == toml_rtoi(toml_raw_at(arr, idx), &ret.u.i));
2283 return ret;
2284}
2285
2287 toml_datum_t ret;
2288 memset(&ret, 0, sizeof(ret));
2289 ret.ok = (0 == toml_rtod(toml_raw_at(arr, idx), &ret.u.d));
2290 return ret;
2291}
2292
2295 toml_datum_t ret;
2296 memset(&ret, 0, sizeof(ret));
2297 ret.ok = (0 == toml_rtots(toml_raw_at(arr, idx), &ts));
2298 if (ret.ok) {
2299 ret.ok = !!(ret.u.ts = MALLOC(sizeof(*ret.u.ts)));
2300 if (ret.ok) {
2301 *ret.u.ts = ts;
2302 if (ret.u.ts->year)
2303 ret.u.ts->year = &ret.u.ts->__buffer.year;
2304 if (ret.u.ts->month)
2305 ret.u.ts->month = &ret.u.ts->__buffer.month;
2306 if (ret.u.ts->day)
2307 ret.u.ts->day = &ret.u.ts->__buffer.day;
2308 if (ret.u.ts->hour)
2309 ret.u.ts->hour = &ret.u.ts->__buffer.hour;
2310 if (ret.u.ts->minute)
2311 ret.u.ts->minute = &ret.u.ts->__buffer.minute;
2312 if (ret.u.ts->second)
2313 ret.u.ts->second = &ret.u.ts->__buffer.second;
2314 if (ret.u.ts->millisec)
2315 ret.u.ts->millisec = &ret.u.ts->__buffer.millisec;
2316 if (ret.u.ts->z)
2317 ret.u.ts->z = ret.u.ts->__buffer.z;
2318 }
2319 }
2320 return ret;
2321}
2322
2323toml_datum_t toml_string_in(const toml_table_t *arr, const char *key) {
2324 toml_datum_t ret;
2325 memset(&ret, 0, sizeof(ret));
2326 toml_raw_t raw = toml_raw_in(arr, key);
2327 if (raw) {
2328 ret.ok = (0 == toml_rtos(raw, &ret.u.s));
2329 }
2330 return ret;
2331}
2332
2333toml_datum_t toml_bool_in(const toml_table_t *arr, const char *key) {
2334 toml_datum_t ret;
2335 memset(&ret, 0, sizeof(ret));
2336 ret.ok = (0 == toml_rtob(toml_raw_in(arr, key), &ret.u.b));
2337 return ret;
2338}
2339
2340toml_datum_t toml_int_in(const toml_table_t *arr, const char *key) {
2341 toml_datum_t ret;
2342 memset(&ret, 0, sizeof(ret));
2343 ret.ok = (0 == toml_rtoi(toml_raw_in(arr, key), &ret.u.i));
2344 return ret;
2345}
2346
2347toml_datum_t toml_double_in(const toml_table_t *arr, const char *key) {
2348 toml_datum_t ret;
2349 memset(&ret, 0, sizeof(ret));
2350 ret.ok = (0 == toml_rtod(toml_raw_in(arr, key), &ret.u.d));
2351 return ret;
2352}
2353
2354toml_datum_t toml_timestamp_in(const toml_table_t *arr, const char *key) {
2356 toml_datum_t ret;
2357 memset(&ret, 0, sizeof(ret));
2358 ret.ok = (0 == toml_rtots(toml_raw_in(arr, key), &ts));
2359 if (ret.ok) {
2360 ret.ok = !!(ret.u.ts = MALLOC(sizeof(*ret.u.ts)));
2361 if (ret.ok) {
2362 *ret.u.ts = ts;
2363 if (ret.u.ts->year)
2364 ret.u.ts->year = &ret.u.ts->__buffer.year;
2365 if (ret.u.ts->month)
2366 ret.u.ts->month = &ret.u.ts->__buffer.month;
2367 if (ret.u.ts->day)
2368 ret.u.ts->day = &ret.u.ts->__buffer.day;
2369 if (ret.u.ts->hour)
2370 ret.u.ts->hour = &ret.u.ts->__buffer.hour;
2371 if (ret.u.ts->minute)
2372 ret.u.ts->minute = &ret.u.ts->__buffer.minute;
2373 if (ret.u.ts->second)
2374 ret.u.ts->second = &ret.u.ts->__buffer.second;
2375 if (ret.u.ts->millisec)
2376 ret.u.ts->millisec = &ret.u.ts->__buffer.millisec;
2377 if (ret.u.ts->z)
2378 ret.u.ts->z = ret.u.ts->__buffer.z;
2379 }
2380 }
2381 return ret;
2382}
2383
2384static int parse_millisec(const char *p, const char **endp) {
2385 int ret = 0;
2386 int unit = 100; /* unit in millisec */
2387 for (; '0' <= *p && *p <= '9'; p++, unit /= 10) {
2388 ret += (*p - '0') * unit;
2389 }
2390 *endp = p;
2391 return ret;
2392}
static int nitem(const double *range)
Definition mrtk_ionex.c:53
double dot(const double *a, const double *b, int n)
Inner product of vectors.
Definition mrtk_mat.c:151
char * stop
Definition toml.c:356
char * errbuf
Definition toml.c:357
token_t tok
Definition toml.c:360
char * key[10]
Definition toml.c:366
struct context_t::@343266115336034272003212003032200377137064012210 tpath
int top
Definition toml.c:365
char * start
Definition toml.c:355
toml_table_t * root
Definition toml.c:361
toml_table_t * curtab
Definition toml.c:362
int errbufsz
Definition toml.c:358
int cnt
Definition toml.c:1193
token_t key[10]
Definition toml.c:1194
int eof
Definition toml.c:350
int len
Definition toml.c:349
tokentype_t tok
Definition toml.c:346
int lineno
Definition toml.c:347
char * ptr
Definition toml.c:348
int nitem
Definition toml.c:303
toml_arritem_t * item
Definition toml.c:304
int kind
Definition toml.c:299
int type
Definition toml.c:300
const char * key
Definition toml.c:298
int valtype
Definition toml.c:290
toml_array_t * arr
Definition toml.c:293
char * val
Definition toml.c:292
toml_table_t * tab
Definition toml.c:294
union toml_datum_t::@034014057205341050151107111126247137201246022032 u
int b
Definition toml.h:87
double d
Definition toml.h:89
char * s
Definition toml.h:86
int ok
Definition toml.h:83
int64_t i
Definition toml.h:88
toml_timestamp_t * ts
Definition toml.h:85
const char * val
Definition toml.c:285
const char * key
Definition toml.c:284
const char * key
Definition toml.c:308
int narr
Definition toml.c:317
bool readonly
Definition toml.c:310
bool implicit
Definition toml.c:309
int nkval
Definition toml.c:313
int ntab
Definition toml.c:321
toml_array_t ** arr
Definition toml.c:318
toml_keyval_t ** kval
Definition toml.c:314
toml_table_t ** tab
Definition toml.c:322
char z[10]
Definition toml.h:72
struct toml_timestamp_t::@140140272151246031144276257317172000233346153225 __buffer
static int e_forbid(context_t *ctx, int lineno, const char *msg)
Definition toml.c:405
toml_table_t * toml_table_at(const toml_array_t *arr, int idx)
Definition toml.c:1960
int toml_table_ntab(const toml_table_t *tab)
Definition toml.c:1950
toml_datum_t toml_bool_at(const toml_array_t *arr, int idx)
Definition toml.c:2272
static void xfree_arr(toml_array_t *p)
Definition toml.c:1541
static void(* ppfree)(void *)
Definition toml.c:39
static int valtype(const char *val)
Definition toml.c:985
tokentype_t
Definition toml.c:330
@ LBRACE
Definition toml.c:335
@ LBRACKET
Definition toml.c:338
@ EQUAL
Definition toml.c:334
@ NEWLINE
Definition toml.c:337
@ DOT
Definition toml.c:332
@ RBRACE
Definition toml.c:336
@ RBRACKET
Definition toml.c:339
@ STRING
Definition toml.c:340
@ INVALID
Definition toml.c:331
@ COMMA
Definition toml.c:333
static int e_keyexists(context_t *ctx, int lineno)
Definition toml.c:400
static int parse_array(context_t *ctx, toml_array_t *arr)
Definition toml.c:1006
static int skip_newlines(context_t *ctx, int isdotspecial)
Definition toml.c:919
static int parse_select(context_t *ctx)
Definition toml.c:1312
static void ** expand_ptrarr(void **p, int n)
Definition toml.c:422
static void xfree(const void *x)
Definition toml.c:325
static void *(* ppmalloc)(size_t)
Definition toml.c:38
static int check_key(toml_table_t *tab, const char *key, toml_keyval_t **ret_val, toml_array_t **ret_arr, toml_table_t **ret_tab)
Definition toml.c:692
char toml_array_type(const toml_array_t *arr)
Definition toml.c:1930
static char * STRDUP(const char *s)
Definition toml.c:69
void toml_set_memutil(void *(*xxmalloc)(size_t), void(*xxfree)(void *))
Definition toml.c:41
toml_datum_t toml_string_in(const toml_table_t *arr, const char *key)
Definition toml.c:2323
#define malloc(x)
Definition toml.c:52
toml_datum_t toml_int_at(const toml_array_t *arr, int idx)
Definition toml.c:2279
#define MALLOC(a)
Definition toml.c:49
static int walk_tabpath(context_t *ctx)
Definition toml.c:1250
static int key_kind(toml_table_t *tab, const char *key)
Definition toml.c:730
toml_array_t * toml_array_in(const toml_table_t *tab, const char *key)
Definition toml.c:1906
toml_datum_t toml_double_at(const toml_array_t *arr, int idx)
Definition toml.c:2286
int toml_table_nkval(const toml_table_t *tab)
Definition toml.c:1946
char toml_array_kind(const toml_array_t *arr)
Definition toml.c:1928
static toml_array_t * create_keyarray_in_table(context_t *ctx, toml_table_t *tab, token_t keytok, char kind)
Definition toml.c:825
static toml_table_t * create_keytable_in_table(context_t *ctx, toml_table_t *tab, token_t keytok)
Definition toml.c:777
int toml_rtob(toml_raw_t src, int *ret_)
Definition toml.c:2055
static int next_token(context_t *ctx, int dotisspecial)
Definition toml.c:1803
static int scan_string(context_t *ctx, char *p, int lineno, int dotisspecial)
Definition toml.c:1638
static int scan_digits(const char *p, int n)
Definition toml.c:1602
static toml_arritem_t * expand_arritem(toml_arritem_t *p, int n)
Definition toml.c:435
int toml_rtos(toml_raw_t src, char **ret)
Definition toml.c:2210
static void * CALLOC(size_t nmemb, size_t sz)
Definition toml.c:56
static void * expand(void *p, int sz, int newsz)
Definition toml.c:410
const char * toml_table_key(const toml_table_t *tab)
Definition toml.c:1952
int toml_array_nelem(const toml_array_t *arr)
Definition toml.c:1940
static int eat_token(context_t *ctx, tokentype_t typ, int isdotspecial, const char *fline)
Definition toml.c:931
toml_raw_t toml_raw_at(const toml_array_t *arr, int idx)
Definition toml.c:1924
#define FREE(a)
Definition toml.c:50
static toml_array_t * create_array_in_array(context_t *ctx, toml_array_t *parent)
Definition toml.c:879
#define ALIGN8(sz)
Definition toml.c:48
const char * toml_key_in(const toml_table_t *tab, int keyidx)
Definition toml.c:1865
toml_datum_t toml_double_in(const toml_table_t *arr, const char *key)
Definition toml.c:2347
toml_datum_t toml_int_in(const toml_table_t *arr, const char *key)
Definition toml.c:2340
static char * STRNDUP(const char *s, size_t n)
Definition toml.c:83
static int parse_keyval(context_t *ctx, toml_table_t *tab)
Definition toml.c:1106
static void set_eof(context_t *ctx, int lineno)
Definition toml.c:1596
static void xfree_kval(toml_keyval_t *p)
Definition toml.c:1531
const char * toml_array_key(const toml_array_t *arr)
Definition toml.c:1942
int toml_key_exists(const toml_table_t *tab, const char *key)
Definition toml.c:1880
toml_table_t * toml_table_in(const toml_table_t *tab, const char *key)
Definition toml.c:1915
#define FLINE
Definition toml.c:373
static int scan_date(const char *p, int *YY, int *MM, int *DD)
Definition toml.c:1610
int toml_ucs_to_utf8(int64_t code, char buf[6])
Definition toml.c:198
static toml_table_t * create_table_in_array(context_t *ctx, toml_array_t *parent)
Definition toml.c:900
static int e_internal(context_t *ctx, const char *fline)
Definition toml.c:385
toml_datum_t toml_bool_in(const toml_table_t *arr, const char *key)
Definition toml.c:2333
int toml_rtoi(toml_raw_t src, int64_t *ret_)
Definition toml.c:2073
static char * normalize_key(context_t *ctx, token_t strtok)
Definition toml.c:626
int toml_table_narr(const toml_table_t *tab)
Definition toml.c:1948
static int fill_tabpath(context_t *ctx)
Definition toml.c:1201
static int parse_millisec(const char *p, const char **endp)
Definition toml.c:2384
toml_raw_t toml_raw_in(const toml_table_t *tab, const char *key)
Definition toml.c:1897
static toml_keyval_t * create_keyval_in_table(context_t *ctx, toml_table_t *tab, token_t keytok)
Definition toml.c:736
static int scan_time(const char *p, int *hh, int *mm, int *ss)
Definition toml.c:1624
void toml_free(toml_table_t *tab)
Definition toml.c:1583
static int e_badkey(context_t *ctx, int lineno)
Definition toml.c:395
static char * norm_basic_str(const char *src, int srclen, int multiline, char *errbuf, int errbufsz)
Definition toml.c:493
static toml_arritem_t * create_value_in_array(context_t *ctx, toml_array_t *parent)
Definition toml.c:864
static int parse_inline_table(context_t *ctx, toml_table_t *tab)
Definition toml.c:945
toml_table_t * toml_parse_file(FILE *fp, char *errbuf, int errbufsz)
Definition toml.c:1480
toml_table_t * toml_parse(char *conf, char *errbuf, int errbufsz)
Definition toml.c:1402
static char * norm_lit_str(const char *src, int srclen, int multiline, char *errbuf, int errbufsz)
Definition toml.c:444
int toml_rtots(toml_raw_t src_, toml_timestamp_t *ret)
Definition toml.c:1966
static void set_token(context_t *ctx, tokentype_t tok, int lineno, char *ptr, int len)
Definition toml.c:1585
toml_datum_t toml_timestamp_in(const toml_table_t *arr, const char *key)
Definition toml.c:2354
int toml_rtod_ex(toml_raw_t src, double *ret_, char *buf, int buflen)
Definition toml.c:2146
static int e_syntax(context_t *ctx, int lineno, const char *msg)
Definition toml.c:390
int toml_rtod(toml_raw_t src, double *ret_)
Definition toml.c:2205
int toml_utf8_to_ucs(const char *orig, int len, int64_t *ret)
Definition toml.c:97
toml_array_t * toml_array_at(const toml_array_t *arr, int idx)
Definition toml.c:1956
static int e_outofmemory(context_t *ctx, const char *fline)
Definition toml.c:380
toml_datum_t toml_string_at(const toml_array_t *arr, int idx)
Definition toml.c:2265
static void xfree_tab(toml_table_t *p)
Definition toml.c:1560
toml_datum_t toml_timestamp_at(const toml_array_t *arr, int idx)
Definition toml.c:2293
#define free(x)
Definition toml.c:53
const char * toml_raw_t
Definition toml.h:165